摘要:一前言指向,,,的區別是一個經典的面試問題,同時在項目中會經常使用到的原生的方法。中可能會極大的避免了產生的錯誤,有時候需要維護老的項目還是有必要了解一下的指向和,,三者的區別。
一、前言
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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/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(); ...
閱讀 1689·2021-11-15 11:37
閱讀 3423·2021-09-28 09:44
閱讀 1669·2021-09-07 10:15
閱讀 2799·2021-09-03 10:39
閱讀 2697·2019-08-29 13:20
閱讀 1304·2019-08-29 12:51
閱讀 2214·2019-08-26 13:44
閱讀 2134·2019-08-23 18:02