函数 与 this
this 是一个特殊的对象,它在标准函数和箭头函数中有不同的行为。
在标准函数中,this引用的是把函数当成方法调用的上下文对象,这时候通常称其为this值(在网页的全局上下文中调用函数时,this指向Windows)。
window.color = 'red';
let obj = {
color : 'blue'
}
function sayColor(){
console.log(this.color)
}
sayColor();
obj.sayColor = sayColor;
obj.sayColor();
定义在全局上下文中的函数sayColor()引用了this 对象。这个 this 到底引用哪个对象必须到函数被调用时才能确定。因此这个值在代码执行过程中可能会发生改变。如果在全局上下文中调用sayColor() ,这个结果会输出“red”,因为此时 this 指向 window,而this.color 相当于window.color。后面把sayColor赋值给 obj对象之后再去调用obj.sayColor,此时的this 指向obj对象,故而this.color相当于obj.color,所以显示“blue”。
在箭头函数中,this的引用是定义箭头函数的上下文。下面的例子演示了这一点。在对sayColor()的两次调用当中,this的引用的都是window对象,因为这个箭头函数都是在window的上下文中定义的:
window.color = 'red';
let o = {
color: 'blue',
}
let sayColor = () => console.log(this.color);
sayColor();//red。这时候的this指向的是sayColor的上下文即: window对象
o.sayColor = sayColor;
o.sayColor();//red。同样指向的是 对象的上下文也是window对象
这里我们知道,在事件回调或者定时回调中调用某个函数时,this值的指向的并非都是想要的对象。此时将回调函数写成箭头函数就可以解决问题,这是因为箭头函数中的this会保留定义该函数的上下文
如果内部函数中没有使用箭头函数定义,则this对象会在运行时绑定到执行函数的上下文。
function getIdentityFunc(){
identity = 'My Object';
return function(){
return this.identity;//这个this是执行函数,也就是说他绑定的上下文是 getIdentityFunc
}
}
console.log(getIdentityFunc()())//My Object
如果在全局函数中调用,则this在非严格模式下等于 window,在严格模式下等于 undefined。,
如果作为某个对象的方法调用,则this等于这个对象。匿名函数在这种情况下不会绑定到某个对象,这意味着this 会指向 window对象,除非在严格模式下this 是 undefined。
window.identity = 'The window';
let object = {
identity : 'My Object',
getIdentityFunc(){
return function(){
return this.identity;
}
}
}
console.log(object.getIdentityFunc()());//The window
这里先创建了一个全局变量 identity ,之后又创建一个包含 identity 属性对象。这个对象还包含一个getIdentityFunc()方法,返回一个匿名函数。这个匿名函数。这个匿名函数返回this.identity。因为getIdentityFunc()返回函数,所以 object.getIdentityFunc() ()会立即调用这个返回的函数,从而得到一个字符串。科了,,室,此时返回的字符串是“The window”,即:全局变量 identity 在值。为什么匿名函数没有使用其包含的作用域【getIdentityFunc()】的this对象?
由于每个函数在被调用时都会自动创建两个特殊变量:this 和 argument。内部函数蝾螈不可能直接访问外部外部函数的两个变量。但是,如果把 this 保存到闭包可以访问的另一个变量中,则是行的通的。
window.identity = 'the window';
let object = {
identity : 'My Object',
getIdentityFunc(){
let that = this;
return function(){
return that.identity;
}
}
}
console.log(object.getIdentityFunc()());//My Object
在这个例子上,在定义匿名函数之前,先把外部函数的this保存在变量 that 中。然后在定义闭包时,就可以让它访问 that ,因为这是包含函数中名称没有任何冲突的一个变量。即使在外部函数返回之后,that仍然指向Object,所以调用object.getIdentityFunc()就会返回“My Object”。
但是在一些特殊的情况下,this的值可能并不是我们所期待的值。比如
window.identity = "My Windows";
let Object = {
identity: "My Object",
getImdentity(){
return this.identity
}
}
console.log(Object.getImdentity()) 输出的是“My Object”
但是Object.getImdentity()的调用方式不同,其最后的结果也会出现不同。
console.log(Object.getImdentity());
console.log((Object.getImdentity)());
console.log((Object.getImdentity=Object.getImdentity)());
结果:
My Object
My Object
My Windows
第一行的输出是正常调用Object.getImdentity(),会返回“My Object”,因为this.identity就是 Object.iddentity。
第二行在调用的时候放到了括号中,但是 还是对一个函数的引用,this的值并没有变。这是因为 Object.getImdentity 和 (Object.getImdentity)在规范上是等价的。
第三行执行了一次赋值,然后在调用赋值后的结果,因为赋值表达式的值是函数本身,this的值不再与任何的对象绑定,所以返回的值是 “My Windows”
最后,箭头函数中this 是如何进行查找的呢?
个人是这样理解的:this 向外层作用域中一层层的查找this,直到有this的定义,这个this便是了。