You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var a = 2020
function foo() {
console.log('this.a >>> ', this.a)
}
var o = {
a: 2019,
fn: foo
}
var doFoo = o.fn
doFoo()
还有一种更微秒的情况,是发生在函数作为参数传递,以回调函数执行时
var a = 2020 // global variable
function foo() {
console.log('this.a >>> ', this.a)
}
function doFoo(fn) {
fn()
}
var o = {
a: 2019,
fn: foo
}
doFoo(o.fn) // this.a >>> 2020
其实最重要还是记住,其传参的值,也是引用地址,真正决定 this 的,还是调用的位置
显式绑定
我们常见的 call 和 apply 就是显示绑定的例子,通过这两个方法,我们可以指定函数调用时 this 的指向,简单示例如下,call 和 apply 的区别这里不展开说明了
var a = 2020
function foo() {
console.log('this.a >>> ', this.a)
}
var o = {
a: 2019,
fn: foo
}
foo.call(o)
另外一种显示绑定的方法是我们常见的 bind,由 ES5 提出 Function.prototype.bind,它会创建一个新的函数,并且指定其 this 为传入的参数上,简单的实现为
function foo(a) {
this.a = a
}
var bar = new foo(123)
console.log('bar.a >>> ', bar) // 123
箭头函数
以上的四种绑定规则仅适用于正常的函数,ES6 中新增了一种特殊的函数声明方式:箭头函数
箭头函数不使用 this 的四条标准规则,而是根据外层(函数或者全局)作用域来决定 this
示例:
function foo(a) {
return a => {
// this 继承自 foo
console.log(this.a)
}
}
var o1 = {
a: 2020
}
var o2 = {
a: 2019
}
var bar = foo.call(o1)
bar.call(o2) // 2020
解析:foo() 内部创建的箭头函数会捕获调用 foo() 时的 this。由于 foo() 的 this 绑定到了 o1,所以箭头函数的 this 也绑定到了 o1,然后将其引用赋值给 bar,箭头函数的 this 无法被修改。
总结:
如果要判断一个运行中的函数 this 的绑定,就需要找到这个函数的直接调用位置,找到之后就可以按顺序应用以下规则来判断 this 绑定的对象(箭头函数除外)
由 new 调用?绑定到新建的对象
由 call 或者 apply 或者 bind 调用,绑定到指定的对象
由上下文对象调用?绑定到对应的调用上下文对象
默认:在严格模式下绑定到 undefined,否则绑定到全局对象
The text was updated successfully, but these errors were encountered:
对于初学者来说 this,可真的是让人头大,其语义也有一定的歧义,在不同地方,可能会有不同含义,甚至是相同地方也有可能在不同时机下会变得不一样,实在是难以琢磨,当初的我也是对此倍感费解
我们在网上看得最多的对 this 的描述是,this 指向函数执行时上下文,而箭头函数则指向声明时的上下文,那么,我们来看下例子
可见即使 bar 执行在 foo 的作用域内,但仍然无法访问到 a.
这段代码试图通过 this 来联通 foo() 和 bar() 的词法作用域,这是不可能实现的
还有一些说法会说 this 指向函数自身,那么再来看下
所以函数内的 this 并非指向自身,而在函数内部使用的 this.count,实际上是在 this 所指向的作用域创建了一个值为 NaN 的变量,此处 this 指向 window
上述是对 this 的一些错误的理解,我们知道每个函数的 this 是在函数调用时被绑定的,完全取决于函数的调用位置
调用位置
调用位置是指函数被调用的位置,而非声明位置(箭头函数除外,后面再讨论箭头函数)
分析调用栈
可以看出,三个函数的 this 都是指向 window,也就是 baz 被调用的位置
这里也可以通过在控制台断点查看其函数内部的 scope,其 this 一直是指向 window,这里函数体内调用外部的其他函数,与 this.bar(), this.foo() 无异(非严格)。
绑定规则
默认绑定
从上面的例子我们可以看得知,在函数体内使用 this 访问对象,然后在全局环境中调用它,可以访问到全局环境下的同名属性,这里就是应用了 this 的默认绑定,但是如果使用了严格模式,则不能对全局对象用于默认绑定(声明时,非调用时)
隐式绑定
再来看一段更常见的代码
这里 o.fn 实际上保存是 foo 函数的引用地址,也就是说,o.fn 和 foo 是同一个东西,这里可以说函数被调用时,o 对象“拥有”或者“包含” foo 函数的引用
当 foo 被调用时(o.fn()),它的前面增加了对 o 对象的引用。当函数引用有上下文对象时,隐式绑定规则会把函数中的 this 绑定到这个上下文件对象
如果对象属性的引用是有链式引用,则以上一层或者说最后一层的调用位置为准:
此处引申出另一个问题,平常被隐式绑定的函数,有些场景下会丢失绑定的对象,也就是说它会应用默认绑定,如下:
还有一种更微秒的情况,是发生在函数作为参数传递,以回调函数执行时
其实最重要还是记住,其传参的值,也是引用地址,真正决定 this 的,还是调用的位置
显式绑定
我们常见的 call 和 apply 就是显示绑定的例子,通过这两个方法,我们可以指定函数调用时 this 的指向,简单示例如下,call 和 apply 的区别这里不展开说明了
另外一种显示绑定的方法是我们常见的 bind,由 ES5 提出 Function.prototype.bind,它会创建一个新的函数,并且指定其 this 为传入的参数上,简单的实现为
更详细的模拟 bind 实现参见此处
new 绑定
使用 new 调用函数时,会执行如下操作:
示例:
箭头函数
以上的四种绑定规则仅适用于正常的函数,ES6 中新增了一种特殊的函数声明方式:箭头函数
示例:
解析:foo() 内部创建的箭头函数会捕获调用 foo() 时的 this。由于 foo() 的 this 绑定到了 o1,所以箭头函数的 this 也绑定到了 o1,然后将其引用赋值给 bar,箭头函数的 this 无法被修改。
总结:
如果要判断一个运行中的函数 this 的绑定,就需要找到这个函数的直接调用位置,找到之后就可以按顺序应用以下规则来判断 this 绑定的对象(箭头函数除外)
The text was updated successfully, but these errors were encountered: