摘要:一前言指向,,,的区别是一个经典的面试问题,同时在项目中会经常使用到的原生的方法。中可能会极大的避免了产生的错误,有时候需要维护老的项目还是有必要了解一下的指向和,,三者的区别。
一、前言
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() // Cherry2、在函数内部使用_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 Cherry2、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
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/104577.html
摘要:参考链接在中,和是对象自带的三个方法,都是为了改变函数体内部的指向。返回值是函数方法不会立即执行,而是返回一个改变了上下文后的函数。而原函数中的并没有被改变,依旧指向全局对象。原因是,在中,多次是无效的。 参考链接:https://juejin.im/post/59bfe8... 在JavaScript中,call、apply和bind是Function对象自带的三个方法,都是为了改变...
摘要:如果连续呢结果会是什么结果还是第一个原因是,在中,多次是无效的。更深层次的原因,的实现,相当于使用函数在内部包了一个,第二次相当于再包住第一次故第二次以后的是无法生效的。 this 1.其实js中的this没那么难理解,当找不到this时记住一句话:谁调我,我就指谁!new 谁指谁 function text1(){ console.log(this); //指wind...
摘要:的作用在中,三者作用是改变某个函数的执行上下文,具体作用是改变函数体内部的指向。 apply、call、bind的作用 在javascript中,三者作用是改变某个函数的执行上下文(Execution Context),具体作用是改变函数体内部this的指向。 举个栗子: function example() {} example.prototype = { name: wil...
摘要:理解文章中已经比较全面的分析了在中的指向问题,用一句话来总结就是的指向一定是在执行时决定的,指向被调用函数的对象。与和直接执行原函数不同的是,返回的是一个新函数。这个新函数包裹了原函数,并且绑定了的指向为传入的。 理解 JavaScript this 文章中已经比较全面的分析了 this 在 JavaScript 中的指向问题,用一句话来总结就是:this 的指向一定是在执行时决定的,...
摘要:是的,始终指向调用对象,调用对象,这个很重要,的静态成员是没有的概念的。所以和,的区别是返回一个明确的新函数,和立即执行了。 1. 问题引入 function A() {} A.prototype.fna = function() { console.log(this); } 我的问题是 fna 的 this 是指向哪里的? var a = new A(); a.fna(); ...
阅读 1609·2021-11-15 11:37
阅读 3311·2021-09-28 09:44
阅读 1610·2021-09-07 10:15
阅读 2747·2021-09-03 10:39
阅读 2646·2019-08-29 13:20
阅读 1250·2019-08-29 12:51
阅读 2170·2019-08-26 13:44
阅读 2088·2019-08-23 18:02