前端基本功(三):javascript中讓人腦袋疼的this關鍵字

javascript 的this關鍵字

1. this是什麼

this是javascript中的關鍵字之一。他是使用對象自動生成的一個內部對象,只能在對象內部使用。它會根據上下文而進行變化,而且會在不一樣的 JavaScript的模式(是否爲嚴格模式)下表現出差別。javascript

2. this的指向關鍵

this的指向取決於什麼地方以什麼方式調用,而不是建立時。箭頭函數中的 this 的做用域繼承自執行上下文,箭頭函數自身不綁定 this,所以 this 的值將在調用堆棧中查找。前端

3. this的綁定規則

  1. 默認綁定: 直接使用不帶任何修飾的函數調用,默認且只能應用默認綁定。通常綁定到window,嚴格模式下是 undefined;
  2. 隱形綁定:obj.foo() 函數執行時就有了上下文對象,就是obj。這種狀況下,函數默認綁定的是它的上下文對象。若是是鏈性關係,xx.yy.obj.foo();上下文取函數的直接上級,也就是緊挨着的obj,或者說對象鏈的最後一個。(隱式丟失:綁定至上下文對象的函數被賦值給一個新的函數,而後調用這個新的函數時。傳入回調函數時:其實這就是第一種狀況的變種,實際上參數傳遞就是一種隱式賦值。除了開發人員自定義的函數,在將函數傳入語言內置的函數好比 setTimeout 時,一樣會發生隱式丟失的狀況。)
  3. 顯性綁定: (隱形綁定的話:必需要有一個上下文包含咱們的函數,這樣就須要顯性綁定了)1. call,appy,bind. 2. new。this綁定的是新建立的對象,例:var bar = new foo(); 函數 foo 中的 this 就是一個叫foo的新建立的對象 , 而後將這個對象賦給bar , 這樣的綁定方式叫 new綁定 .
  4. new綁定:js中的只要用new修飾的 函數就是'構造函數',準確來講是 函數的構造調用,由於在js中並不存在所謂的'構造函數'。用new 作到函數的構造調用後,js幫咱們作了什麼工做:
    1. 建立一個新對象;
  5. 把這個新對象的__proto__屬性指向 原函數的prototype屬性。(即繼承原函數的原型);
  6. 將這個新對象綁定到 此函數的this上 。
  7. 返回新對象,若是這個函數沒有返回其餘對象。
  8. 箭頭中的 this的做用域繼承自執行上下文,箭頭函數自身不綁定 this,箭頭函數的this綁定沒法被修改.

4. this綁定優先級

new 綁定 > 顯示綁定 > 隱式綁定 > 默認綁定java

5. call,apply,bind

  1. 都是用來改變函數的this對象的指向的。
  2. 第一個參數都是this要指向的對象。
  3. 均可以利用後續參數傳參。
  4. call:從第二個參數開始素有參數都是原函數的參數。apply:只接受兩個參數,且第二個參數必須是數組,這個數組表明原函數的參數列表。 bind:只有一個函數,且不會馬上執行,只是將一個值綁定到函數的this上,並將綁定好的函數返回。bind 是返回對應函數,便於稍後調用;apply 、call 則是當即調用 .

6. 代碼實例

1. 默認綁定

function foo(){
    var a = 1 ;
    console.log(this.a);    // 10
}
var a = 10;
foo();

2. 隱性綁定

function foo(){
    console.log(this.a);
}
var obj = {
    a : 10,
    foo : foo
}
foo();                // undefined (默認綁定)

obj.foo();            // 10

// 隱式丟失(引用賦值)
var a = 0;
function foo(){
    console.log(this.a);
};
var obj = {
    a : 2,
    foo:foo
}
//把obj.foo賦予別名bar,形成了隱式丟失,由於只是把foo()函數賦給了bar,而bar與obj對象則毫無關係
var bar = obj.foo;
bar();//0
//等價於
var a = 0;
var bar = function foo(){
    console.log(this.a);
}
bar();//0

// 隱式丟失(參數傳遞)參數傳遞其實就是一種隱式賦值,所以咱們傳入的函數也會被隱式賦值。
 function foo(){
   console.log(this.a);
 }

function doFoo(fn){
  //fn其實引用的是foo
  fn();//調用位置
}
var obj = {
  a:2,
  foo:foo
};
var a = "oops,global";//a是全局對象的屬性
doFoo(obj.foo);//oops,global

//若是把函數傳入內置的函數中結果是同樣的 
 function foo(){
   console.log(this.a);
 }
var obj = {
  a:2,
  foo:foo
};
var a = "oops,global";//a是全局對象的屬性
setTimeout(obj.foo,100);//oops,global

3. 顯性綁定

function foo(){
    console.log(this.a);
}
var obj = { a : 10 };

foo = foo.bind(obj);
foo();                    // 10

function foo(){
    this.a = 10;
    console.log(this);
}
foo();                    // window對象
console.log(window.a);    // 10 默認綁定

var obj = new foo();      // foo{ a : 10 } 建立的新對象的默認名爲函數名
                          // 而後等價於 foo { a : 10 }; var obj = foo;
console.log(obj.a);       // 10 new綁定

// 使用new調用函數後,函數會 以本身的名字 命名 和 建立 一個新的對象,並返回。
//若是原函數返回一個對象類型,那麼將沒法返回新對象,你將丟失綁定this的新對象。
function foo(){
    this.a = 10;
    return new String("搗蛋鬼");
}
var obj = new foo();
console.log(obj.a);       // undefined
console.log(obj);         // "搗蛋鬼"
複製代碼
來一塊兒學習前端基本功與面試題啦

github地址: github.com/ruralist-si…git

相關文章
相關標籤/搜索