本文原创:liruifangjavascript
你是否被this困扰过? 求职时你是否在笔试或者面试的时候被问起过? 你是否在代码中写过self = this?java
this,究竟是何方神圣?git
this是一个很特别的关键字,被自动定义在 全部函数的做用域中 this 关键字是 JavaScript 中最复杂的机制之一github
科幻小说家亚瑟·查理斯·克拉克说过一句话:任何足够先进的技术都和魔法无异。面试
在缺少清晰认识的状况下,this 彻底就是一种魔法segmentfault
先看几个例子~浏览器
正经解释:bash
听过不少道理 却依然……app
不!融于意识、付诸实践的道理,才是你的道理。函数
1、调用位置
2、绑定规则
3、绑定优先级
4、凡事都有例外
this 的绑定,使用开发者工具获得调用栈,而后找到栈中第二个元素,这就是真正的调用位置。
Bob.callPerson(John);
Bob called a person named John”
callPerson() 是 Bob 发起的,this 就指向 Bob。
复制代码
- 答案:16
- 对象属性引用链中只有最顶层或者说最后一层会影响调用位置。
- 无论有多少层,在判断this的时候,咱们只关注最后一层。
复制代码
- 虽然 bar 是 obj.foo 的一个引用,可是实际上,它引用的是 foo 函数自己
- bar() 实际上是一个不带任何修饰的函数调用
- 重复强调:隐式绑定的形式 obj.fun()
复制代码
经过call、apply、bind的方式,显式地指定this所指向的对象。
- 答案:number is 2
- 执行fn的时候,至关于直接调用了foo方法(记住: obj.foo已经被赋值给fn了,隐式绑定也丢了),没有指定this的值,对应的是默认绑定。
- 这显然不是咱们想要的,怎么办?
复制代码
调用fn显式的强制绑定,硬绑定
咱们建立了函数 Hi(),并在它的内部手动调用 了 fn.call(obj),所以强制把 fn 的 this 绑定到了 obj。不管以后如何调用函数 Hi,它总会手动在 obj 上调用 fn。
复制代码
思考: new 作了什么?
1. 建立一个新对象
2. 将构造函数的做用域赋值给新对象,即this指向这个新对象
3. 执行构造函数中的代码
4. 返回新对象
复制代码
foo的this指向bar对象上
复制代码
(一)默认绑定 var bar = foo()
严格模式下,绑定到undefined,不然绑定到 全局对象。
复制代码
(二)隐式绑定 var bar = obj1.foo()
在某个上下文对象中调用,this 绑定的是那个上下文对象。
复制代码
(三)显式绑定 var bar = foo.call(obj2)
this绑定的是 指定的对象。
复制代码
(四)new绑定 var bar = new foo()
this绑定的是新建立的对象。
复制代码
new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
这样就结束了吗?
将null或undefined做为this的绑定对象传入call、apply或者是bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
- 答案:2
- foo() 内部建立的箭头函数会捕获调用时 foo() 的 this。因为 foo() 的 this 绑定到 obj1, bar(引用箭头函数)的 this 也会绑定到 obj1,箭头函数的绑定没法被修改。
复制代码
(一)默认绑定 var bar = foo()
严格模式下,绑定到undefined,不然绑定到 全局对象。
复制代码
(二)隐式绑定 var bar = obj1.foo()
在某个上下文对象中调用,this 绑定的是那个上下文对象。
复制代码
(三)显式绑定 var bar = foo.call(obj2)
this绑定的是 指定的对象。
复制代码
(四)new绑定 var bar = new foo()
this绑定的是新建立的对象。
复制代码
(五)箭头函数
没有本身的this,当前的词法做用域覆盖了 this 原本的值,this继承于外层代码库中的this,且不可被修改。
复制代码
欢迎再次来到this的魔法世界,让咱们一块儿升级打怪吧~
问题剖析,真相只有一个!
- 答案:
1 2
- 分析:
隐式绑定,this指向obj,num是1;
默认绑定:foo直接指向了foo的引用,和obj无关,是不带任何修饰的函数调用 。
复制代码
- 答案:hi,jadfe
复制代码
- 分析:
setTimeout(fn,delay){ fn(); },至关因而将obj.foo赋值给了一个变量,最后执行了变量, foo是不带任何修饰的函数调用这个时候,foo的this显然和obj就没有关系了。
复制代码
- 答案:
Hello, Wiliam
Hello, Wiliam
Hello, Christina
- 分析:
① setTimeout的回调函数中,this使用的是默认绑定,非严格模式下,执行的是全局对象
② 上个例子刚分析了,跟setTimeout实现机制有关。
③ 第三条虽然也是在setTimeout的回调中,可是咱们能够看出,这是执行的是person2.sayHi()使用的是隐式绑定,所以这是this指向的是person2。
复制代码
- 答案:
2 2
- 分析:
箭头函数,this继承于外层的this
默认绑定:foo是不带任何修饰的函数调用
复制代码
- 答案:
2
- 分析:
箭头函数经常使用于回调函数中,this继承于外层foo的this,foo中的this显示绑定到obj上,所以至关于obj.a = a4-5
复制代码
- 答案:
Obj对象
Obj对象
Window对象
Window对象
Window对象
- 分析:
① obj.hi(); 隐式绑定,this绑定在obj上,输出obj。
② hi(); 执行箭头函数,继承外层做用域的this。
③ sayHi(); 隐式绑定丢失的状况,this执行的是默认绑定,指向全局对象window。
④ fun1(); 执行的是箭头函数,this是继承于外层代码库的this。外层代码库咱们刚刚分析了,this指向的是window,所以这儿的输出结果是window。
⑤ obj.say(); 执行的是箭头函数,当前的代码块obj中是不存在this的,只能往上找,就找到了全局的this,指向的是window。
复制代码
- 答案:
0 NaN
- 分析:
看调用位置,显示绑定,
无心中建立了一个全局变量 count
这个count值是什么?
有些地方称值为NaN是错误的,值为undefined,++运算符,类型转换NaN
复制代码
- 答案:
5
- 分析:
将null或undefined做为this的绑定对象传入call、apply或者是bind,
这些值在调用时会被忽略,实际应用的是默认绑定规则
复制代码
1. 函数是不是new绑定,若是是,那么this绑定的是新建立的对象。
2. 函数是否经过call,apply,bind调用显式绑定,若是是,那么this绑定的就是指定的对象。
3. 函数是否在某个上下文对象中调用(隐式绑定),通常是obj.foo(),若是是的话,this绑定的是那个上下文对象[注意隐式丢失的状况]。
4. 若是以上都不是,那么使用默认绑定。在严格模式下,则绑定到undefined,不然绑定到全局对象。
5. 若是把null或者undefined做为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
6. 若是是箭头函数,箭头函数的this继承的是外层代码块的this。
复制代码
若是你已经很是清楚的知道怎么判断this的指向,那就试试这道题吧~
答案:
10
9
3
27
20
复制代码