JS函数的this指向

JS函数的this指向

this作用

JavaScript中的this和常见的面向对象语言中的this区别:

  • 常见面向对象的编程语言中,比如Java、C++、Swift、Dart等等一系列语言中,this通常只会出现在类的方法中。
  • 也就是你需要有一个类,类中的方法(特别是实例方法)中,this代表的是当前调用对象。
  • 但是JavaScript中的this更加灵活,无论是它出现的位置还是它代表的含义

JavaScript

代码解读

复制代码

// 没有this,编写代码不方便 var obj1 = { name :"why", eating: function() { console.log(obj1.name,+ "在吃东西") }, running: function() { console. log(obj1.name + "在跑步") } } var info= { name :"why", eating: function() { console.log(info.name + "在吃东西") }, running: function() { console. log(info.name + "在跑步") } }

this指向

全局作用域

  • 浏览器: window (global0bject)
  • Node环境:{} (把每个文件当成module -> 加载->编译->放到一个函数compiledWrapper ->执行这个函数.call({}))

this通常在函数中使用

动态绑定:this在函数执行时才会确定

函数执行上下文(函数的调用栈、AO对象、this

  • 函数在调用时,JavaScript会默认给this绑定一个值;
  • this的绑定和定义的位置(编写的位置)没有关系;
  • this的绑定和调用方式以及调用的位置有关系;
  • this是在运行时被绑定的;

JavaScript

代码解读

复制代码

// this指向什么,跟函数所处的位置是没有关系的 // 跟函数被调用的方式是有关系 function foo() { console.log(this) } // 1. 直接调用这个函数 foo() // 2. 创建一个对象,对象中的函数指向foo var obj = { name: 'why', foo:foo } obj. foo() // 3. call/apply调用 foo.apply("abc")

image.png

this绑定规则

  1. 默认绑定:独立函数调用

没有调用主题

image.png

  1. 隐式绑定:object.fn()

前提:

  • 必须在调用的对象内部有一个对函数的引用(比如一个属性);
  • 如果没有这样的引用,在进行调用时,会报找不到该函数的错误;
  • 正是通过这个引用,间接的将this绑定到了这个对象上;

object对象会被js引擎绑定到fn函数的中this里面

在其调用位置中,是通过某个对象发起的函数调用。

image.png

  1. 显示绑定:call、apply、bind

call、apply

JavaScript所有的函数都可以使用call和apply方法(这个和Prototype有关)。

第一个参数都要求是一个对象(给this准备),后面的参数,apply为数组,call为参数列表;

在调用这个函数时,会将this绑定到这个传入的对象上


JavaScript

代码解读

复制代码

function sum(num1, num2, num3) { console.log(num1 + num2 + num3, this) } sum.call("call", 20, 30, 40) sum.apply("apply", [20, 30, 40])

foo直接调用和 call/apply 调用的不同在于this绑定的不同

foo直接调用指向的是全局对象(window);call/apply是可以指定this的绑定对象

bind


JavaScript

代码解读

复制代码

function foo() { console.log(this) } // 默认绑定和显示绑定bind冲突: 优先级(显示绑定) var newFoo = foo.bind("aaa") newFoo()

  1. new绑定
  • 创建一个全新的对象;
  • 这个新对象会被执行prototype连接;
  • 这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成);
  • 如果函数没有返回其他对象,表达式会返回这个新对象;

JavaScript

代码解读

复制代码

// 我们通过一个new关键字调用一个函数时(构造器), 这个时候this是在调用这个构造器时创建出来的对象 // this = 创建出来的对象 // 这个绑定过程就是new 绑定 function Person(name, age) { this.name = name this.age = age } var p1 = new Person("why", 18) console.log(p1.name, p1.age) // this->Peson {} var p2 = new Person("kobe", 30) console.log(p2.name, p2.age)

this其他补充


JavaScript

代码解读

复制代码

setTimeout(function() { console.log(this) // window,内部是**独立函数调用** }, 2000) // 默认绑定


JavaScript

代码解读

复制代码

const boxDiv = document.querySelector('.box') boxDiv.onclick = function() { console.log(this) // boxDiv元素 } // 隐式绑定 boxDiv.addEventListener('click', function() { console.log(this) // boxDiv元素 }) // 显示绑定


JavaScript

代码解读

复制代码

// 3.数组.forEach/map/filter/find,可以传两个参数(函数、this指向) var names = ["abc", "cba", "nba"] names.forEach(function(item) { console.log(item, this) }) // window names.map(function(item) { console.log(item, this) }, "cba") // "cba"

规则优先级

1.默认规则的优先级最低

2.显示绑定优先级高于隐式绑定


JavaScript

代码解读

复制代码

// 1.call/apply的显示绑定高于隐式绑定 var obj = { name: "obj", foo: function() { console.log(this) } } obj.foo.apply('abc') // 'abc' obj.foo.call('abc') // 'abc' // 2.bind的优先级高于隐式绑定 function foo() { console.log(this) } var obj = { name: "obj", foo: foo.bind("aaa") } obj.foo() // "aaa"

3.new绑定优先级高于隐式绑定


JavaScript

代码解读

复制代码

var obj = { name: "obj", foo: function() { console.log(this) } } // new的优先级高于隐式绑定 var f = new obj.foo() // foo {}

4.new绑定优先级高于bind


JavaScript

代码解读

复制代码

// 结论: new关键字不能和apply/call一起来使用 // new的优先级高于bind function foo() { console.log(this) } var bar = foo.bind("aaa") var obj = new bar() // foo {} // new绑定 > 显示绑定(apply/call/bind) > 隐式绑定(obj.foo()) > 默认绑定(独立函数调用)

this规则之外

  1. 忽略显示绑定

JavaScript

代码解读

复制代码

function foo() { console.log(this) } foo.apply("abc") // "abc" foo.apply({}) // {} // apply/call/bind: 当传入null/undefined时, 自动将this绑定成全局对象 foo.apply(null) // window foo.apply(undefined) // window var bar = foo.bind(null) bar() // window

  1. 间接函数引用

JavaScript

代码解读

复制代码

// 争论: 代码规范 ; var obj1 = { name: "obj1", foo: function() { console.log(this) } } var obj2 = { name: "obj2" }; // 不加“;”词法分析会认为代码还未结束,与下面的(obj2.bar = obj1.foo)()一起 // obj2.bar = obj1.foo // obj2.bar() //obj2 (obj2.bar = obj1.foo)() //独立函数调用

  1. ES6箭头函数(arrow function)

JavaScript

代码解读

复制代码

// 1. 编写箭头函数 // 1> (): 参数 // 2> =>: 箭头 // 3> {}: 函数的执行体 var foo = (num1, num2, num3) => { console.log(num1, num2, num3) } function bar(num1, num2, num3) { } // 高阶函数在使用时, 也可以传入箭头函数 var nums = [10, 20, 45, 78] nums.forEach((item, index, arr) => {}) // 箭头函数有一些常见的简写: // 简写一: 如果参数只有一个, ()可以省略 nums.forEach(item => { console.log(item) }) // 简写二: 如果函数执行体只有一行代码, 那么{}也可以省略 // 强调: 并且它会默认将这行代码的执行结果作为返回值,不用return nums.forEach(item => console.log(item)) var newNums = nums.filter(item => item % 2 === 0) console.log(newNums) // [10,20,78] // filter/map/reduce var result = nums.filter(item => item % 2 === 0) .map(item => item * 100) .reduce((preValue, item) => preValue + item) console.log(result) // 10800 // 简写三: 如果一个箭头函数, 只有一行代码, 并且返回一个对象, 这个时候如何编写简写 // var bar = () => { // return { name: "why", age: 18 } // } var bar = () => ({ name: "why", age: 18 })

箭头函数不使用this的四种标准规则(也就是不绑定this),而是根据外层作用域来决定this。


JavaScript

代码解读

复制代码

// 1.测试箭头函数中this指向 // var name = "why" // var foo = () => { // console.log(this) // } // foo() //window // var obj = {foo: foo} // obj.foo() //window // foo.call("abc") // window // 2.应用场景 var obj = { data: [], getData: function() { // 发送网络请求, 将结果放到上面data属性中 // 在箭头函数之前的解决方案 // var _this = this // setTimeout(function() { // var result = ["abc", "cba", "nba"] // _this.data = result // }, 2000); // 箭头函数之后 // 箭头函数没有this,就会向上层作用域找,上层function隐式绑定obj setTimeout(() => { var result = ["abc", "cba", "nba"] this.data = result }, 2000); } } obj.getData()

原文:https://juejin.cn/post/7478687361737490458

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值