詞法做用域是一套關於引擎如何尋找變量以及會在何處找到變量的規則。 (函數做用域和塊做用域)數組
JavaScript 中的做用域就是詞法做用域,也就是靜態做用域,由定義代碼決定app
動態做用域彷佛暗示有很好的理由讓做用域做爲一個在運行時就被動態肯定的形式,而不是在寫代碼時進行靜態肯定的形式函數
動態做用域並不關心函數和做用域是如何聲明以及在何處聲明的,只關心它們從何處調用。換句話說,做用域鏈是基於調用棧的,而不是代碼中的做用域嵌套oop
ps:能夠忽略下面這段話 :this
靜態類型語言是指在編譯時變量的數據類型便可肯定的語言,多數靜態類型語言要求在使用變量以前必須聲明數據類型,某些具備類型推導能力的現代語言可能可以部分減輕這個要求.
動態類型語言是在運行時肯定數據類型的語言。變量使用以前不須要類型聲明,一般變量的類型是被賦值的那個值的類型spa
不要混淆概念噢 code
this 的綁定和函數聲明的位置沒有任何關係,只取決於函數的調用方式。當一個函數被調用時,會建立一個活動記錄(有時候也稱爲執行上下文)。這個記錄會包
含函數在哪裏被調用(調用棧)、函數的調用方法、傳入的參數等信息。this 就是記錄的其中一個屬性,會在函數執行的過程當中用到對象
綁定規則: blog
1. 由new 調用?綁定到新建立的對象。
2. 由call 或者apply(或者bind)調用?綁定到指定的對象。
3. 由上下文對象調用?綁定到那個上下文對象。
4. 默認:在嚴格模式下綁定到undefined,不然綁定到全局對象。繼承
1.默認綁定
function foo() { console.log( this.a ); } var a = 2; foo(); // 2
2.
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 函數別名! var a = "oops, global"; // a 是全局對象的屬性 bar(); // "oops, global" 雖然bar 是obj.foo 的一個引用,可是實際上,它引用的是foo 函數自己,所以此時的 bar() 實際上是一個不帶任何修飾的函數調用,所以應用了默認綁定。
3.
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 setTimeout(fn,delay) { // 等待delay 毫秒 fn(); // <-- 調用位置! }
fn若傳入obj.fn 實際也發生隱式賦值
硬綁定的典型應用場景就是建立一個包裹函數,傳入全部的參數並返回接收到的全部值:
function foo(something) { console.log( this.a, something ); return this.a + something; } var obj = { a:2 }; var bar = function() { return foo.apply( obj, arguments ); }; var b = bar( 3 ); // 2 3 console.log( b ); // 5
call和apply實際上就是調用fn(運行時綁定),將fn裏面的this 綁定指向obj,運行fn arguments是fn參數組成的數組 fn.apply(obj,【arguments】)
call相似只不過fn的參數不是數組形式
function foo(something) { console.log( this.a, something ); return this.a + something; } // 簡單的輔助綁定函數 function bind(fn, obj) { return function() { return fn.apply( obj, arguments ); }; } var obj = { a:2 }; var bar = bind( foo, obj ); var b = bar( 3 ); // 2 3 console.log( b ); // 5
箭頭函數:
箭頭函數最經常使用於回調函數中,例如事件處理器或者定時器: function foo() { setTimeout(() => { // 這裏的this 在此法上繼承自foo() console.log( this.a ); },100); } var obj = { a:2 }; foo.call( obj ); // 2
箭頭函數會繼承外層函數調用的this 綁定