Js基礎之this指向問題

一、爲什麼要用this

能夠隱式的傳遞對象引用,更加簡潔。

二、this指向規則和詞法作用域

詞法作用域:作用域由函數書寫代碼時決定(定義時上下文)

this指向規則:不指向函數詞法作用域,不指向函數本身,由函數調用時的位置決定(運行時上下文,類似於動態作用域)

三、this指向規則

this的指向規則如下四條,優先級爲:new +構造函數 > 顯式綁定 > 隱式綁定 > 默認

1.默認(獨立調用)

獨立函數調用情況下,this指向全局變量或undefined。

(1)函數在非嚴格模式下,this指向全局變量

(2)函數在嚴格模式下(use strict),this 指向undefined

2.隱式綁定

(1)調用位置有上下文對象的,this綁定在上下文對象上

(2)調用位置有多個鏈式上下文對象的,this綁定在就近的對象上

注意:隱式綁定可能會出現this的隱式丟失,原因如下:

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 單獨執行
f() // 1

// obj 環境執行
obj.f() // 2

 

(上例和圖片來自http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

由以上例子能夠看出,當定義一個對象,並在對象中定義函數的過程是先開闢一個內存存儲函數,然後將地址傳遞給對象的foo。當調用foo()時,是直接調用全局中的foo函數;當調用obj.foo()時是訪問obj.foo存儲的地址,此時this指向obj。

若再次定義var a = obj.foo;即將地址傳給了全局的a,此時調用a()相當於直接調用全局中的函數,此時this指向全局變量(非嚴格模式下)造成this的隱式丟失

在回調函數和參數傳遞(隱式賦值)時,容易發生this的隱式丟失。

隱式丟失的解決辦法:

(1)var self = this

(2)硬綁定(bind)

(3)箭頭函數(ES6)

3.顯式綁定

顯式的綁定this指向可以採用call()、apply()和硬綁定bind()

call()和apply()的作用完全一樣,只是參數傳遞方式不一樣

(1)函數.call ( this新指向,數據1,... ,數據n)

將函數中的this指向新指向,並向該函數傳遞數據1-n

(2)函數.apply(this新指向,數組或類數組) 其中數組或類數組爲:[數據1,... ,數據n]

將函數中的this指向新指向,並向該函數傳遞數組 [數據1,...,數據n]

call()和apply() 的用法:

  • 劫持別人的方法
var foo = {
  name:"mingming",
  logName:function(){
    console.log(this.name);
  }
}
var bar={
  name:"xiaowang"
};
foo.logName.call(bar);//xiaowang
  • 實現繼承
function Animal(name){   
  this.name = name;   
  this.showName = function(){   
    console.log(this.name);   
  }   
}   
 
function Cat(name){  
  Animal.call(this, name);  
}   
 
var cat = new Cat("Black Cat");   
cat.showName(); //Black Cat
  • 強制改變this指向
window.id="window";
document.querySelector('#test').onclick = function(){
  console.log(this.id);//test
  var fun = function(){
    console.log(this.id);
  }
  fun();//window
  fun.call(this);//test
}

(3)硬綁定bind(未完)

bind()是ES5新增(IE6,7,8不支持)

var  新函數 = 舊函數.bind(this新指向,數據1,... ,數據n)

bind() 作用和前兩個相同,即改變this指向

call()和apply()在改變指向以後立即執行改變後的函數,而bind()卻返回一個改變後的新函數。

注意:call(),apply()和bind() 在非嚴格模式下,第一個參數爲null或者undefined時this會自動替換爲指向全局對象

4.new+構造函數

在傳統面嚮對象語言中,構造函數是類的特殊函數

在JavaScript中,構造函數只是能夠使用new操作符調用的普通函數,他不屬於某個類,也不能實例一個類

當使用new 來調用構造函數時,自動執行一下操作:

(1)創建一個新的對象

(2)對新對象執行 [[原型]] 連接

(3)把新對象綁定到函數的this

(4)若函數沒有返回其他對象,則函數自動返回這個新對象

四、ES6改進(箭頭函數)

箭頭函數的this不按照以上四條規則,而是按照詞法作用域由外部作用域決定this指向

箭頭函數能夠通過call、apply、bind 改變this指向,但只能改變一次

參考資料:

http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章