Js 方法指向,this、call、apply

1,228 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文同时参与 「掘力星计划」            ,赢取创作大礼包,挑战创作激励金

前言

this指向是一个让开发头痛到爆炸的一个问题,本章我来带大家学习一下this指向的一些方法和指向

this指向

在一个方法内部,this是一个特殊变量,它始终指向当前对象

来个例子

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

执行: image.png

在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaomingbirth属性。

但是如果我们拆开写

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25, 正常结果
getAge(); // NaN

单独调用函数getAge()怎么返回了NaN

da0f8e9f2cdabfb1ad82f4d154b56192.jpg

请注意,我们已经进入到了JavaScript的一个大坑里。

ceeb653ely1gam2j9ym3tg20dc0cmab5.gif

Q: JavaScript的函数内部如果调用了this,那么这个this到底指向谁?

答案是,视情况而定!

如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。

如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

坑爹啊!

12a813663c4d7c56a43281ba8f296704.jpg 更坑爹的是,如果这么写:

var fn = xiaoming.age; // 先拿到xiaoming的age函数
fn(); // NaN

也是不行的!要保证this指向正确,必须用obj.xxx()的形式调用! 这时候就引来了 applycall

虽然在一个独立的函数调用中,根据是否是strict模式,this指向undefinedwindow,不过,我们还是可以控制this的指向的!

要指定函数的this指向哪个对象,可以用函数本身的apply、call方法,

  • apply()把参数打包成Array再传入
  • call()把参数按顺序传入
function getAge(a,b) {
    var y = new Date().getFullYear();
     return y - this.birth + '-' + a + '-' + b;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};
xiaoming.age(1,2); // "30-1-2"
getAge.apply(xiaoming, [3,4]); // "30-3-4", this指向xiaoming, 参数为空
getAge.call(xiaoming, 7,8); // "30-7-8", this指向xiaoming, 参数为空

// 当然还可以这样
var fn1 = xiaoming.age
fn1.call(xiaoming, 7,8) // "30-7-8"
fn1.apply(xiaoming, [10,1]) // "30-10-1"

当然啦 还可以这样 用var that = this;,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var that = this; // 在方法内部一开始就捕获this
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - that.birth; // 用that而不是this
        }
        return getAgeFromBirth();
    }
};

xiaoming.age();

学会了吗这位同学?

小结

this 总是(非严格模式下)指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境;当函数不作为对象的属性被调用,而是以普通函数的方式,this总是指向全局对象(在浏览器中,通常是Window对象),跟普通的函数调用相比,用call和apply可以动态的改变函数的this