this
-
JavaScript的this总是指向一个对象,具体指向哪一个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。我们需要判断到底this.key,到底输出哪一个值,就需要明白this指向哪里.
-
this指向,分为四种
1. 作为对象的方法使用:作为对象的方法被调用时,this指向该对象
let obj = {
a: 1,
getA: function () {
console.log(this.a);
}
};
obj.getA(); // =>1
2. 作为普通函数调用:当函数不作为属性被调用时,也就是我们常说的普通函数方式,此时的this指向全局对象。在浏览器的JavaScript里,这个全局对象是window对象。
a = 1;
function getA() {
console.log(this.a);
}
getA(); // => 1
3. 构造器调用:构造器的外表跟普通函数一模一样,区别在于被调用的方式,使用new运算符调用函数时,该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。
function myfunction() {
this.b = 7;
}
let obj = new myfunction();
console.log(obj.b); // => 7
// 如果构造器显示返回了object类型的对象,那么此次运算结果将返回这个对象
function myfunction() {
this.b = 7;
return {
b: 8
};
}
let obj = new myfunction();
console.log(obj.b); // => 8
如果构造器不显示地返回任何数据或者返回一个非对象的数据,就不会造成上述问题
验证一下上述的说法
a = 2;
let obj = {
a: 1,
func: function () {
var self = this;
console.log(this.a);
console.log(self.a);
(function () {
console.log(this.a);
console.log(self.a);
})();
}
};
obj.func();
这段代码会输出什么? 答案是 1,1,2,1;
分析:obj.func(); 函数是作为对象的方法被调用的,那么this就应该指向该对象(obj),所以毫无疑问,第一个和第二个输出都是1,不同的是,匿名函数是由全局函数调用的,它的this指向的是window,也就是普通函数,所以输出了2,而同时它在这里也是形成了一个闭包,可以访问到外层函数额属性,所以self还是指向obj的,因此输出了1。
4. Function.prototype.call或者Function.prototype.apply
两者的作用: 可以动态地修改this
let obj_1 = {
name: 'liming',
getName: function () {
console.log(this.name);
}
};
let obj_2 = {
name: 'xiaohong'
};
obj_1.getName(); //=> liming
// 按道理只有obj_1才有getName这个方法
obj_1.getName.call(obj_2); //=>xiaohong
这是因为我们使用call在调用getName之前先偷梁换柱,把它原来的this指向obj_2,再去调用。
丢失this
let obj_1 = {
name: 'liming',
getName: function () {
console.log(this.name);
}
};
let obj_2 = obj_1.getName;
obj_2(); // => undefined
在这里我们进行赋值了,obj_2就是一个普通的函数:
当我们再去调用它的时候,已经把它当成一个普通的函数进行调用了,这时候this指向window,而window中并没有定义这个name属性。所以就输出了undefined了.如果我们定义了:
我们可以使用call或者apply去修正这个this
name = '222';
let obj_1 = {
name: 'liming',
getName: function () {
console.log(this.name);
}
};
let obj_2 = obj_1.getName;
obj_2.call(obj_1); // => liming
接下来学习学习call和apply
-
他们属于Function原型定义的两个方法,作用一模一样,就是写法不一样。
-
apply: 第一个参数执行函数体内this的指向,第二个参数为一个数组,apply会把数组中的元素作为参数传递给被调用的函数。
-
call: 传入的参数数量不固定,第一个参数也是代表函数体内this的指向,从第二个开始,每一个参数都被依次传入函数
let func = function (a, b, c) {
console.log(a, b, c);
};
func.apply(null, [1, 2, 3]); // => 1,2,3
func.call(null, 1, 2, 3); // => 1,2,3
如果我们传入的第一个参数为null,函数体内的this会指向默认的宿主环境,在浏览器中是window
call和apply的其他用途
- 改变this的指向
- 借用其他对象的方法 ,如下
arguments虽然是一个类数组对象,但是除了length外,没有任何关于Array的属性,直接使用shift操作是会报错的,所以我们可以通过call去让它具备这样的属性方法。