对 this 的误解
认为 this 指向的是函数自身
在 JavaScript 中,所有函数都是对象。既然是对象,那么就可以有属性来存储其值。所以就会存在认为 this 指向函数自身,比如下面的例子:
function foo(value) {
console.log(`Foo: ${value}`)
this.count++
}
foo.count = 0
foo(1)
应该会有很多人认为此时 count 值为 1;其实不是,它的值为 NaN。为什么呢?因为此时 this 指向的是全局对象,在全局作用域创建变量 count,默认值为 undefined,执行操作后其值为 NaN。因此,this 并不是指向函数自身的。
认为 this 指向函数的作用域
注意:this 在任何情况下都不指向函数的词法作用域。
从 ECMAScript 角度理解 this(Reference)
this 是在函数运行时进行绑定的,而不是在编写时绑定;this 的绑定与函数声明位置没有关系,而与函数调用方式有关系。
ECMAScript 类型
如何确定 this
备注:对于确实是否是 Reference 类型,需要查看 ECMAScript 规范确认。
this 绑定规则
1、默认绑定
函数调用时不带任何修饰的引用,非严格模式下为全局对象(window),严格模式下为 undefined。
function foo() {
console.log(this.a)
}
var a = 2
2、隐式绑定
通过引用(对象)调用函数,this 绑定到该对象,不过需要注意隐式丢失 this(原始函数赋值给一个变量)。
// 隐式绑定
function foo() {
console.log(this.a)
}
const obj = {
a: 2,
foo: foo
}
obj.foo() // 2
// 隐式丢失
function foo() {
console.log(this.a)
}
const obj = {
a: 2,
foo: foo
}
var a = 4
const bar = obj.foo
bar() // 4 此时 bar 是 foo 函数的引用,调用时不带任何修饰,应用默认规则
// 还有一种是回调函数传参
3、显式绑定
通过 Function.prototype.bind、apply 和 call 方法显式指定 this(硬绑定:bind 中绑定 this 对象)。
// 显式绑定
function foo() {
console.log(this.a)
}
const obj = {
a: 8
}
foo.call(obj)
// 硬绑定
function foo(something) {
return this.a + something
}
var obj = {
a: 5
}
var bar = funtion() {
return foo.apply(obj, arguments)
}
var b = bar(3)
console.log(b)
4、new 绑定
new 对象过程:
- 创建新对象 obj;
- 给新对象 obj 的内部属性赋值,比如
[[Prototype]],构造原型链;(如果构造函数的原型是对象类型,则指向构造函数的原型;否则指向 Object 的原型。obj.proto = F.prototype) - 执行构造函数中的代码,新对象会绑定到函数调用的 this;
- 如果构造函数内部返回对象类型数据,则返回该对象类型;否则返回新对象 obj。
优先级
new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定
参考链接
-
《你不知道的 JavaScript》(上卷)