函数的 this 指向
一、this 的绑定规则
默认绑定
javascript
// 1 独立函数被调用-this指向window
function foo() {
console.log(this)
}
foo()
// 2 函数定义在对象中,但是被独立调用-this指向window
var obj = {
bar: function () {
console.log(this)
},
}
var baz = obj.bar
baz()
// 3 高阶函数,函数作为实参被调用-this指向window
var obj2 = {
bar: function () {
console.log(this)
},
}
function test(fn) {
fn()
}
test(obj2.bar)隐式绑定
javascript
function foo() {
console.log(this)
}
var obj = {
bar: foo,
}
// 通过对象调用函数-this指向该对象
obj.bar()显式绑定
javascript
function foo(name, age, height) {
console.log(this, name, age, height)
}
// 1 apply调用:第一个参数绑定this,第二个参数传入额外的实参(以数组的形式)
foo.apply('apply', ['mocha', 18, 1.88])
// 2 call调用:第一个参数绑定this,其余传入参数列表作为实参
foo.call('call', 'latte', 19, 1.99)
// 3 bind绑定
var obj = { name: 'obj' }
// 调用函数时候,总是绑定到对象上,但函数不写入对象中
var bar = foo.bind(obj, 'mocha', 18, 1.88)
bar()new 绑定
javascript
// new绑定-创建一个新的空对象,this指向这个对象
function foo() {
console.log(this)
}
new foo()注意
- 函数在调用的时候,JavaScript 会默认给 this 绑定一个值
- this 的绑定和定义的位置(编写的位置)没有关系
- this 的绑定和调用方式以及调用的位置有关系
- this 是在运行时被绑定的
二、this 的绑定优先级
- 默认绑定优先级最低
- 显式绑定高于隐式绑定
- new 绑定高于隐式绑定
- new 绑定高于 bing,new 不能和 call,apply 同时使用
javascript
function foo() {
console.log(this)
}
// 1、显式绑定高于隐式绑定
var obj = { bar: foo }
obj.bar.apply('apply') // this指向apply
obj.bar.call('call') // this指向call
var bar = foo.bind('bind')
var obj2 = { baz: bar }
obj2.baz() // this指向bind
// 2、new绑定高于隐式绑定
var obj3 = {
foo: function () {
console.log(this)
},
}
new obj3.foo() // this指向新的空对象
// 3、new 绑定高于bind
var bindFn = foo.bind('bind')
new bindFn() // this指向新的空对象三、绑定之外的情况
情况一
在显式绑定中,传入 null/undefined,这个显式绑定会被忽略,使用默认规则,但在严格模式下将为原始值
javascript
function foo() {
console.log(this)
}
foo.apply(null) // this指向window,严格模式下为null
foo.apply(undefined) // this指向window,严格模式下为undefined情况二
间接函数引用,使用默认规则
javascript
var obj = {
foo: function () {
console.log(this)
},
}
var obj2 = {}((obj2.foo = obj.foo))() // this指向window四、箭头函数的使用
特性
- 箭头函数不会绑定 this,也不会有 arguments 属性
- 箭头函数不能作为构造函数
编写优化
- 只有一个参数的时候可以省略()
- 函数体只有一行代码时可以省略{},但会将这行代码作为返回值
- 如果默认返回一个对象的时候,必须加上()
javascript
var names = ['mocha', 'latte', 'coffee', 'tea-milk']
names.forEach(item => console.log(item))
var arrFn = () => ({ name: 'mocha', age: 18 })
var nums = [1, 2, 3, 4, 5]
var totalNums = nums
.filter(item => item % 2 === 0)
.map(item => item ** 2)
.reduce((preValue, item) => preValue + item)箭头函数中的 this 用法:
javascript
function request(url, callbackFn) {
var result = ['aaa', 'bbb', 'ccc']
callbackFn(result)
}
var obj = {
names: [],
network: function () {
// es5之前使用变量保存this
// _this = this
request('/names', res => {
this.names = [].concat(res)
})
},
}
obj.network()
console.log(obj.names)五、this 练习题分析
练习题一
javascript
var name = 'window'
var person = {
name: 'person',
sayName: function () {
console.log(this.name)
},
}
function sayName() {
var test = person.sayName
test() // window 默认绑定(独立函数调用)
person.sayName() // person 隐式绑定
person.sayName() // person 隐式绑定
;(b = person.sayName)() // window 间接函数调用(独立函数调用)
}
sayName()练习题二
javascript
var name = 'window'
var person1 = {
name: 'person1',
foo1: function () {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function () {
return function () {
console.log(this.name)
}
},
foo4: function () {
return () => {
console.log(this.name)
}
},
}
var person2 = { name: 'person2' }
person1.foo1() // window (独立函数调用)
person2.foo1.call(person2) // person2 (显示绑定)
person1.foo2() // window (箭头函数不绑定this,上层作用域是全局)
person1.foo2.call(person2) // window (箭头函数不适用this的绑定规则)
person1.foo3()() // window (独立函数调用)
person1.foo3.call(person2)() // window (独立函数调用)
person1.foo3().call(person2) // person2 (最终调用返回函数时,使用的是显示绑定)
person1.foo4()() // person1 (箭头函数不绑定this,上层作用域是person1)
person1.foo4.call(person2) // person2 (上层作用域被显示地绑定为person2)
person1.foo4().call(person2) // peerson1 (上层找到了person1)练习题三
javascript
var name = 'window'
function Person(name) {
this.name = name
this.foo1 = function () {
console.log(this.name)
}
this.foo2 = () => console.log(this.name)
this.foo3 = function () {
return function () {
console.log(this.name)
}
}
this.foo4 = function () {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1() // person1 (隐式绑定)
person1.foo1.call(person2) // person2 (显示绑定)
person1.foo2() // person1 上层作用域是person1
person1.foo2.call(person2) // person1 call不绑定箭头函数中的this
person1.foo3()() // window (独立函数调用)
person1.foo3.call(person2)() // window (独立函数调用)
person1.foo3().call(person2) // person2 (显示绑定)
person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1练习题四
javascript
var name = 'window'
function Person(name) {
this.name = name
this.obj = {
name: 'obj',
foo1: function () {
return function () {
console.log(this.name)
}
},
foo2: function () {
return () => {
console.log(this.name)
}
},
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()() // window (独立函数调用)
person1.obj.foo1.call(person2)() // window (独立函数调用)
person1.obj.foo1().call(person2) // person2 (显示绑定)
person1.obj.foo2()() // obj
person1.obj.foo2.call(person2)() // person2
person1.obj.foo2().call(person2) // obj