this、call和apply

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的其他用途

  1. 改变this的指向
  2. 借用其他对象的方法 ,如下
    在这里插入图片描述
    arguments虽然是一个类数组对象,但是除了length外,没有任何关于Array的属性,直接使用shift操作是会报错的,所以我们可以通过call去让它具备这样的属性方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值