为什么要使用this
function identify(){
return this.name.toUpperCase();
}
let me = {"name":"peter"};
identify.call(me);//call()方法是函数原型对象属性的方法,调用者为函数对象可以将一个对象指定为第一个参数,
此时这个对象将会成为函数执行时的this,从第二个参数起依次传入实参
上段代码可以在不同的上下文对象中重复使用函数identify,不用针对每个对象编写不同版本的函数,如果不适用this,那就需要给identify()显式的传入一个对象。
function identify(object){
return object.name.toUpperCase();
}
let me = {};
me.name = "peter";
identify(me);
this提供了一种更优雅的方式来隐式”传递”一个对象的引用,因此可以将API设计的更加简洁并且更易复用。
误解
指向自身
人们很容易把this理解成指向函数自身,但是this并不是指向函数自身。
function foo(num){
console.log("foo:"+num);
this.count++;
}
foo.count=0;
for(let i = 0;i < 10;i++){
foo(i);
}
console(foo.count)//0;
console(this.count)//10;
console.log(window.count)//10----WFT?为什么this.count挂在window上了?
通过上面的例子你会发现this.count和foo.count不是一个东西。。。天啊!
this指向函数的作用域
第二种常见误解是,this指向函数的作用域。这个问题有点复杂了,因为在某种情况下他是正确的,但是在某些情况下他确实错误的。
需要明确的是,this在任何情况下都不指向函数的词法作用域。在JavaScript内部,作用域和对象类似,但是作用域”对象”无法通过JavaScript代码访问,他存在于JS引擎内部。
this全面解析
调用位置
在理解this绑定过程前,首先要理解调用位置:调用位置就是函数在代码中被调用的位置(不是被声明的位置)。最重要的是分析调用栈(就是为了达到当前执行位置所调用的所有函数)
绑定规则
默认绑定
首先要介绍的是最常用的函数调用类型:独立函数调用。
function obj() {
console.log(this.a);
}
let a = 2;
obj();
//2-----WTF?this.a访问到了a。
声明在全局作用域中的变量a就是全局对象的一个属性。但是当我们调用obj时,this.a被解析成了全局变量a。这是因为函数调用时应用了this默认绑定,因此this指向了全局对象。
但是如果使用严格模式,全局对象将无法使用默认绑定,因此this将会绑定到undefined。
隐式绑定
function foo(){
console.log(this.a);
}
let obj = {
a : 2,
foo : foo
}
obj.foo();//2
调用位置会使用obj上下文来引用函数,因此你可以说函数被调用时obj对象拥有或包含他。当函数调用有上下文时,隐式绑定规则就会把函数调用中的this绑定到这个上下文中。并且对象属性引用链中只有最后一层会影响调用位置。
显式绑定
JavaScript中的函数都有一些有用的特性,可以用来解决这个问题,具体点说,可以使用函数的call()和apply()方法。有些函数没有这两种方法,但是这种函数比较罕见。这两个方法怎么工作的?他们的第一个参数是一个对象,他们会把这个对象绑定到this,接着调用函数时会指定这个this,我们称之为显示绑定
function foo(num){
console.log(this.a,num);
return this.a + num;
}
var obj = {
a : 2
}
var bar = function(){
return foo.call(obj)
}
bar();//2
new绑定
使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
- 创建(或者说构造)一个全新的对象
- 这个 对象会被执行到prototype上
- 这个对象会被绑定到函数调用的this
- 如果函数没有返回对象,那么new表达式种的函数调用会自动返回这个新对象。
function foo(a){
this.a = a;
}
let bar = foo(2);
console.log(bar.a);//2
反思
this的指向在函数定义的时候是确定不了的,只有在函数执行的时候才会确定。this实际上指向最终那个调用它的对象。通过常量来改变this的指向
如果想要在类方法中的普通函数调用this指向调用它函数,就需要改变this的指向let lesson ={
site:["后盾人"],
show:function(){//类方法
//this指向的是调用的对象
return this.site.map(function(){
//this指向的是window(普通函数)
})
}
}
方法一:利用 变量 self = this
方法二:map函数中有第二个参数,该参数会自动赋值给函数中的this。有些函数没有这个参数。注意let lesson ={
site:["后盾人"],
show:function(){//类方法
//this指向的是调用的对象
return this.site.map(function(){
//this指向的是window(普通函数)
},this)//this指向对象lesson
}
}
箭头函数带来的this的变化
箭头函数中this指向的是上下文,即指向父级作用域