this指向和apply,call,bind三者的区别

时间: 2019-04-10阅读: 356标签: this

一、前言

this指向,apply,call,bind的区别是一个经典的面试问题,同时在项目中会经常使用到的原生的js方法。同时也是ES5中的众多坑的一个。ES6中可能会极大的避免了this产生的错误,有时候需要维护老的项目还是有必要了解一下this的指向和apply,call,bind三者的区别。


二、this的指向

在ES5中,其实this的指向,始终坚持一个原理:this永远指向最后一个调用它的那个对象。

首先我们看一个栗子1:

var name = "windowsName";
function a() {
    var name = "Cherry";
    console.log(this.name);          // windowsName
    console.log("inner:" + this);    // inner: Window
}
a();
console.log("outer:" + this)         // outer: Window

输出windowsName,是因为“this永远指向最后调用它的那个对象”,我们看到调用a的地方a(),前面没有调用的对象那么就是全局对象window,就是全局对象调用a(),相当于window.a()。

如果使用严格模式,全局对象就是undefined,会报错name of undefined

栗子2:

var name = "windowsName";
var a = {
    name: "Cherry",
    fn : function () {
        console.log(this.name);      // Cherry
    }
}
a.fn();

在这个栗子中,函数fn是对象a调用的,所以console是a中的name

栗子3:

var name = "windowsName";
    var a = {
        name: "Cherry",
        fn : function () {
            console.log(this.name);      // Cherry
        }
    }
    window.a.fn();

这个栗子中,记住“this永远指向最后一个调用它的那个对象”,调用fn的对象有window,a,但是最后调用fn是a对象,所以this指向对象a中的name。

栗子4:

var name = "windowsName";
var a = {
    // name: "Cherry",
    fn : function () {
        console.log(this.name);      // undefined
    }
}
window.a.fn();

为啥undefined,调用fn的对象有:window,a,最后一个调用fn是a,但是a中没有对那么进行定义,也不会继续向上一个对象寻找 this.name,而是直接输出 undefined,所以this.name为undefined。

栗子5(比较坑):

var name = "windowsName";
var a = {
    name : null,
    // name: "Cherry",
    fn : function () {
        console.log(this.name);      // windowsName
    }
}
var f = a.fn;
f();

这个栗子比较坑,为啥 不是null,因为虽然将a对象的fn方法赋值给变量f,但是没有调用,“this永远执行最后一个调用ta的那个对象”,由于刚刚的f没有调用,所以fn()最后仍然是被window调用的,所以this指向的也就是window。

注意:this的指向并不是在创建的时候可以确定,在ES5中,永远都是this永远指向最后调用它的那个对象。

栗子6:

var name = "windowsName";
function fn() {
    var name = 'Cherry';
    innerFunction();
    function innerFunction() {
        console.log(this.name);      // windowsName
    }
}
fn()


三、怎样改变this的指向

改变this的指向,我总结以下的方法:

(1)使用ES6中箭头函数

(2)函数内部使用_this = this

(3)使用apply,call,bind方法

(4)new实例化一个对象

举个栗子7:

var name = "windowsName";
var a = {
    name : "Cherry",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        setTimeout(  function () {
            this.func1()
        },100);
    }
};
a.func2()     // this.func1 is not a function

在这个栗子中,不使用箭头函数情况下,会报错的,因为最后调用setTimeout的对象时window,但是在window并没有func1函数

我们改变this的指向这一节将吧这个栗子作为demo进行改造。


1、ES6中的箭头函数

众所周知,ES6的箭头函数是可以避免ES5中this的坑,箭头函数的this始终指向函数定义时候的this,而并不是执行时候。箭头函数需要记住这句话:“箭头函数没有this绑定,必须通过查找作用域来决定其值,如果箭头函数被非箭头函数包含,则this的绑定的是最近一层非箭头函数的this,否则,this为undefined”

栗子8:

var name = "windowsName";
var a = {
    name : "Cherry",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        setTimeout( () => {
            this.func1()
        },100);
    }
};
a.func2()     // Cherry


2、在函数内部使用_this = this

在不使用ES6中,那么这种方式应该是最简单的不会出错的方式,我们先将调用这个函数的对象保存在变量_this中,然后在函数中都使用这个_this,这样_this就不会改变了。

栗子9:

var name = "windowsName";
var a = {
    
    name : "Cherry",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        var _this = this;
        setTimeout( function() {
            _this.func1()
        },100);
    }
};
a.func2()       // Cherry

在func2中,首先设置var _this = this,这里this是调用func2的对象a,为了防止在func2中的setTimeout被window调用而导致的在setTimeout中的this为window。我们将this赋值给一个变量_this,这样在func2中我们使用_this就是指向对象a了。


3、使用apply

栗子10:

var a = {
    name : "Cherry",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        setTimeout(  function () {
            this.func1()
        }.apply(a),100);
    }
};
a.func2()            // Cherry

在栗子中,apply()方法调用一个函数,其具有一个指定的this值,以及作为一个数组(或者类似数组的对象)提供的参数,fun.apply(thisArg, [argsArray])

thisArg:在fun函数运行时指定的this值。指定this的值并不一定是函数执行时真正的this值,如果是原始值的this会指向该原始值的自动包装对象。

argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给fun函数。参数为null或者undefined,则表示不需要传入任何参数。


4、使用call

栗子11:

var a = {
    name : "Cherry",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        setTimeout(  function () {
            this.func1()
        }.call(a),100);
    }
};
a.func2()            // Cherry

在栗子中,call()方法调用一个函数,其具有一个指定的this值,以及若干个参数列表,fun.call(thisArg, arg1, arg2, ...)

thisArg:在fun函数运行时指定的this值。指定this的值并不一定是函数执行时真正的this值,如果是原始值的this会指向该原始值的自动包装对象。

arg1, arg2, ...:若干个参数列表


5、使用bind

栗子12:

var a = {
    name : "Cherry",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        setTimeout(  function () {
            this.func1()
        }.bind(a)(),100);
    }
};
a.func2()            // Cherry

在栗子中,bind()方法创建一个新的函数,当被调用时,将其this的关键字设置为提供的值,在调用新函数时,在任何提供一个给定的参数序列。

bind创建了一个新函数,必须手动去调用。


四、apply,call,bind区别

1、apply和call的区别

apply和call基本类似,他们的区别只是传入的参数不同。apply传入的参数是包含多个参数的数组,call传入的参数是若干个参数列表。

栗子13:

var a ={
    name : "Cherry",
    fn : function (a,b) {
        console.log( a + b);
        console.log( this.name );
    }
}
var b = a.fn;
b.apply(a,[1,2])     // 3   Cherry

栗子14:

var a ={
    name : "Cherry",
    fn : function (a,b) {
        console.log( a + b);
        console.log( this.name );
    }
}
var b = a.fn;
b.call(a,1,2)       // 3   Cherry


2、bind和apply、call区别

bind方法会创建一个新的函数,当被调用的时候,将其this关键字设置为提供的值,我们必须手动去调用。

var a ={
    name : "Cherry",
    fn : function (a,b) {
        console.log( a + b);
        console.log( this.name );
    }
}
var b = a.fn;
b.bind(a,1,2)()   //3   //Cherry
站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/3627

匿名函数没有自己的this

匿名函数没有自己的this,因此,在构造对象中调用全局函数时,可以省去保存临时this,再将其传入全局函数这一步:

理解call apply bind以及其中所谓的改变this指向问题

上述代码很简单,小明有一只铅笔,有一把转笔刀,可以用来削铅笔,当我们调用;很明显会得到:小明使用了转笔刀把铅笔变成了削好的铅笔和木屑

小程序中为什么使用var that=this?

在小程序或者js开发中,this是指当前对象,只是一个指针,真正的对象存放在堆内存中,this的指向在程序执行过程中会变化,因此如果需要在函数中使用全局数据需要合适地将this复制到变量中。

this指针

javascript中this指针是动态的,主要是根据当前函数执行上下文及函数调用方式决定的.以函数方法调用时this指针全局或严格模式中为undefined,以方法调用时this是指针当前对象实例的.以构造函数方式时this指向当前创建的实现对象。

this的指向问题

举个生活中的例子:比如说你在厨房做菜,那厨房就是你的上下文环境,你要拿一点辣椒,顺手就拿到了;比如你在试衣间,那试衣间就是你的上下文环境,你想在试衣间拿一点辣椒,但是这次拿不到了

JavaScript的奇妙this

this 关键字是 JavaScript 中最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有函数的作用域中。但是即使是非常有经验的 JavaScript 开发者也很难说清它到底指向什么。

理解JavaScript函数调用和this

我看到很多人都有关于JavaScript函数调用的困惑。特别是,很多人抱怨函数调用中的语义令人困惑。在我看来,通过理解核心函数调用原语,可以清除很多这种混淆,然后查看在该原语之上调用函数作为语法糖的所有其他方法。

JavaScript之this

JavaScript中的this比较灵活,根据在不同环境下,或者同一个函数在不同方式调用下,this都有可能是不同的。但是有一个总的原则,那就是this指的是,调用函数的那个对象

彻底淘汰并消除JavaScript中的this

如果这很难明白,为什么我们不停止使用它呢?认真的思考一下?如果你读过 将90%的垃圾扔进垃圾桶后,我如何重新发现对JavaScript的爱, 当我说扔掉它时,你不会感到惊讶,this被丢弃了

js手写实现apply,call,bind

apply和call的区别就是传的参数形式不一样。call是一个一个的传,apply可以将参数以数组的形式传进去。而bind是传入第二个和后面的参数,且绑定this,返回一个转化后的函数。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全运营推广