# 我真的懂 this 吗
# 先知
this 实际上是在函数被调用时发生的绑定,它指向哪里完全取决于函数在哪里被调用。
# 大提示: 不想看分析的可以直接拉到最后看结论。
# 面试常见题
# 第一题
function foo(){
console.log(this.a)
}
var obj = {
a :2,
foo:foo
}
var bar = obj.foo
obj.foo()
bar()
复制代码
2
3
4
5
6
7
8
9
10
11
问: 最后两个打印出什么?
# 第二题
function foo(){
console.log(this.a)
}
var obj = {
a :2,
foo:foo
}
var obj2 = {
a:1,
obj:obj
}
var obj3 = obj2.obj.foo
obj2.obj.foo() // 2
obj3() //undefined
复制代码
2
3
4
5
6
7
8
9
10
11
12
13
14
15
问: 最后两个打印出什么? 答?
# 我们如何理解 this 绑定的到底是谁?或者说 this 到底是谁?下面介绍四种方法
# 1. 默认绑定
什么是默认绑定呢?上代码先
var a = 2;
function foo(){
console.log(this.a)
}
function foo2(){
'use strict'
console.log(this.a)
}
foo() // 2
foo2() // TypeError: Cannot read property 'a' of undefined
复制代码
2
3
4
5
6
7
8
9
10
11
- 在上面的代码中,「 foo() 直接使用时不带任何修饰的函数引用进行调用的 」, 因此只能使用「默认绑定」
- 所以到 foo() 中的 this 绑定到「 全局对象 window 」,而「 严格模式 」时,全局对象无法被绑定,所以 this 绑定到 「undefined」
默认绑定总结:默认绑定即不带任何修饰的函数引用被调用时的绑定,此时 this 绑定到「 全局对象 window 」或者 「undefined」
# 2. 隐式绑定
# 隐式绑定是什么呢?隐式的绑定
当函数引用有上下文对象时,隐式绑定会把函数调用中的 this 绑定到这个上下文对象。
那么回到面试题
# 2.1 面试题一
function foo(){ console.log(this.a)}
var obj = { a :2, foo:foo }
var bar = obj.foo
obj.foo() //2
bar() /undefined
复制代码
2
3
4
5
6
7
foo() 被调用时,落脚点指向 obj 对象(上下文对象),所以 this 绑定到 obj ,this.a 即 obj.a , 所以打印出了 2
但是为什么 bar() 打印出了 undefined 呢?
虽然 bar 是 obj.foo 的引用,但实际上是 foo函数 本身的引用,所以此时 bar() 是不带任何修饰的函数调用,使用默认调用
# 2.2 面试题二
function foo(){ console.log(this.a) }
var obj = { a :2, foo:foo }
var obj2 = { a:1, obj:obj }
var obj3 = obj2.obj.foo
obj2.obj.foo() // 2
obj3() //undefined
复制代码
2
3
4
5
6
7
跟上面一题相同,虽然引用链比较长,但是最后 foo() 是在 obj 中被调用,所以 this 绑定到 obj ,引用链只有最后一层影响调用位置。
# 隐式绑定总结 : 函数在上下文对象中调用时, this 绑定到 上下文对象上。
# 3. 显式绑定
使用「 call apply bind 」 进行绑定 this , this 绑定到第一个传入的参数
# 3.1 call 的使用
回到面试题第一题,我们使用「 call 」进行显式绑定
function foo(){ console.log(this.a) }
var obj = {
a :2,
foo:foo
}
var bar =obj.foo
obj.foo() // 2
bar.call(obj) //2
复制代码
2
3
4
5
6
7
8
9
此时两者都打印出 2 ,因为我们将 this 绑定到 obj ,打印出的即是 //obj.a //2
# 3.2 apply 绑定第一个参数是 this , 二参是 一个数组
# 3.3 bind 是 绑定第一个参数是 this
# 显式绑定总结: 使用call apply bind 时,第一个参数是 this ,不传的话,默认为 undefined 。
# 4. new 绑定
# 使用 new 来调用函数, 到底做了什么 ?
- 创建一个全新的对象
- 这个新对象的__proto__ 链接到 构造函数的 prototype
- 这个新对象会绑定到函数调用的 this
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
function foo(a){
this.a = a
}
var bar = new foo(2)
console.log(bar.a) // 2
复制代码
2
3
4
5
6
7
分析: 使用 new 调用 foo() 时,我们构造一个对象并把它绑定到 foo() 调用的 this 上
# new 绑定总结: new 绑定中 this 绑定的就是新生成的对象
# 总结
- 「 箭头函数 」内的 this 就是外面的 this ,外面的 this 是啥看下面四条
- 2 . 「 new 绑定 」函数是否在 new 中调用 ? 如果是 this 绑定的即是 新创建的对象。 var bar = new foo()
- 「 显式绑定 」函数是否通过 call 、apply、 bind 绑定?this绑定的时第一个参数 var bar = foo.call(obj)
- 4.「 隐式绑定 」 函数是否在某个上下文中调用? 是的话,this 绑定的是那个上下文对象 var bar = obj.foo()
- 「 默认绑定」如果都不是,那么就是默认绑定。严格模式绑定到 undefined ,否则绑定到 全局对象 var bar = foo()
← JS高级第一天 ES6(常用的、重点的) →
关于评论
评论前请填好“昵称”、“邮箱”这两栏内容,否则不会收到回复,谢谢!