About "this"
P1:如何使用this?
- this 实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
这话说起来容易,理解起来缺常常出现问题。请看如下几段代码
var a =1;
var obj = {
a : 0,
say: function(){ console.log(this.a) }
}
var fun = obj.say;
obj.say(); // 0
fun(); // 1
为什么会出现在这种情况?
明明我的fun和obj.say指向了同一个函数,而且都在window对象中调用,为什么出现了不同的结果?
本质上是这样的:
obj.say() 等价于 obj.say.call(obj) //你不写.call(obj),浏览器自动帮你写
fun() 等价于 fun.call(window)
- 把obj当作this传入了say函数中,自然输出的是obj内的a
- 在window对象中执行fun(),就相当于把window当作this传入了该函数中,输出的就是window里的a!
更加普遍化的,this其实时时刻刻都伴随着我们的代码
- 你调用fun(),实际上是执行了fun.call(undefined)
- 你调用obj.fun(),实际上执行了obj.fun.call(obj)
如果你传的是null 或者 undefined,那么默认将window传入(严格模式下默认是 undefined)
至此我们基本讲述了this的基本用法
P2:我们如何判断this指向?
如果要判断一个运行中函数的 this 绑定,就需要找到这个函数的直接调用位置。找到之后就可以按优先顺序应用下面这四条规则来判断 this 的绑定对象。
- 由 new 调用,则绑定到新创建的对象。
- 由 call 或者 apply (或者 bind )调用?绑定到指定的对象。
由上下文对象调用?绑定到那个上下文对象。
function say(){ console.log(this.name) } let person = { name:'Jam', age: 18, say: say} person.say() // 'Jam'
- 默认:在严格模式下绑定到 undefined ,否则绑定到全局对象。
P3:箭头函数中的this
- 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象,箭头函数中没有自己的this的(箭头函数无法使用call,apply),而箭头函数会默认使用父级的this。
我不知道其他人怎样理解,但如此的定义确实让我难以理解。何为定义时所在的对象?如何使用父级的this?接下来我用实例带你理解。
let obj = {
prin: function(){
//父级作用域 此处保存着父级的this
setTimeout(()=>{
console.log(this.num);
},1000)
}
}
let obj1 = { num:1 };
let obj2 = { num:2 };
首先我们直接执行prin方法试一下
obj.prin(); // undefined
分析:
obj.prin()等价于obj.prin.call(obj),
我们将obj作为this,传到prin函数中此时箭头函数向上查找父级作用域中保存的this,
顺理成章的找到了obj,于是去obj的环境内部寻找num
遗憾的是obj内部并没有num属性,故打印undefined尝试改变父级中this的指向
obj.prin.call(obj1); // 1 obj.prin.call(obj2); // 2
分析:
父级中的this被赋值为obj1,箭头函数顺着obj1寻找,找到了num属性,打印了它的值
同理父级中的this被赋值为obj2,箭头函数顺着obj2寻找,找到了num属性,打印了它的值那我们不如直接给obj一个num属性试试?
obj.num = 0; obj.prin(); // 0
分析:
当obj中拥有了属性num,那么箭头函数一找就找到了它!我们再来最后一个例子加深理解!当我把prin函数也用箭头函数书写呢?
var num = 10, //“祖级作用域” window var obj = { num : 5; prin: ()=>{ //父级作用域 此处保存着父级的this setTimeout(()=>{ console.log(this.num); },1000) } } obj.prin()
你猜猜会输出什么呢?
·
·
·
答案是10!分析:
setTimeout中的箭头函数到父级作用域中寻找this,发现父级作用域也是箭头函数,于是再向外查 找,找到了“祖级作用域”window,恰好window有num属性,于是setTimeout中的箭头函数快乐地把 window.num打印了出来!
P4:其他一些总结
- 使用let,const声明的变量可能会不符合上述结论。
原因是:let,const 在全局作用域下声明的变量并不会像 var 一样,被添加为window的属性,所以即使在全局中声明了let number = 1, 箭头函数等等也不会在全局作用域中找到 number!
本文借鉴了 @方应杭 老师的思想 https://zhuanlan.zhihu.com/p/...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。