<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>你不知道的javascript(上卷)</title>
</head><body><script type="text/javascript">/*//9、this 的全面解析this的綁定和函數聲明位置沒有任何關系,之取決于函數的調用方式在理解this的綁定過程之前,首先理解調用位置:調用位置就是在代碼中被調用的位置(問不是聲明位置,)。只有仔細分析調用位置才能回答這個問題:這個this到底引用的是什么通常來說,尋找調用位置就是尋找“函數被調用的位置”2.1、函數調用位置function baz(){console.log("baz"); bar(); //bar的調用位置}function bar(){console.log("bar");foo();//foo的調用位置}function foo(){console.log("foo");}baz();//baz的調用位置b、函數調用位置2function foo(){console.log(this.a);}var a = 2;//2foo();function foo(){"use strict";console.log(this.a); //報錯,嚴格模式下,this不會默認綁定給window}var a = 2;foo();function foo(){console.log(this.a);}var a = 2;(function(){"use strict";foo(); //2})();//三種情況下,只要函數執行不是執行在嚴格模式下,默認綁定才會綁定到全局上2.2、綁定規則2.2.1默認綁定function foo(){console.log(this.a);}var a = 2;foo();//2//非嚴格模式下,this默認綁定在window下function foo(){"use strict";console.log(this.a);}var a = 2;foo();// this is not defined;//嚴格模式下不能將全局對象默認綁定,因此this會綁定到undefined上function foo(){console.log(this.a);}var a = 2;(function(){"use strict";foo();//2 })()//嚴格模式下的調用不影響默認綁定2.2.2隱式綁定function foo(){console.log(this.a);}var obj = {a : 2,foo : foo}obj.foo();//無論是直接在obj中定義還是先定義在添加為引用屬性,這個函數嚴格來說不屬于obj對象,//調用位置會使得obj上下文來引用函數,因此你可以說函數被調用時obj對象“擁有”或者“包含”函數function foo(){console.log(this.a);}var obj2 = {a : 42,foo : foo}var obj1 = {a : 2,obj2 : obj2}obj1.obj2.foo();//42//對象屬性引用鏈中只有上一層或者說最后一層在調用位置中起作用。//隱式丟失function foo(){console.log(this.a);}var obj = {a : 2,foo : foo}var bar = obj.foo;//函數別名var a = "oops,global";bar();//"oops,global";2.2.3顯示綁定function foo(){console.log(this.a);}var obj = {a : 2,}foo.call(obj);//2//通過foo.call(..),我們可以調用foo時強制把他的this綁定到obj上//硬綁定 function foo(){console.log(this.a);}var obj = {a : 2,}var bar = function(){foo.call(obj);}bar();//2setTimeout(bar,1000);//2bar.call(window);//2//硬綁定的bar不可能在修改他的this//創建函數bar(),并且在內部手動調用foo.call(obj),//因此強制把foo的this綁定到obj,無論后面我們如何調用到bar(),//他總會手動在obj上調用foo,這種綁定是一種顯性綁定,因此我們稱之為硬綁定//API調用的‘上下文’function foo(el){console.log(el,this.id); //1 awesome 2 awesome 3 awesome}var obj = {id : "awesome",}//調用foo()時把this綁定到objvar arr = [1,2,3].forEach(foo,obj);//console.log(arr);new 綁定使用new調用函數,會執行以下操作1、創建(或者說構造)一個全新的對象2、這個新對象會被執行[[Protoptye]]連接3、這個新的對象會綁定到函數調用的this4、如果函數沒有返回其他對象,那么new表達式中的函數調用會自動返回這個新的對象function foo(a){this.a = a;}var bar = new foo(2);console.log(bar.a);2.3優先級默認綁定 < 隱式綁定 < 顯式綁定 < new ....2.4被忽略的thisfunction foo(){console.log(this.a);}var a = 2;foo.call(null);//2//call 參數為null或者undefined的時候會默認是全局this柯里化。。。。*//*8、this詞法 var foo = a =>{ console.log(a);}foo(2); //2//箭頭函數,是根據為層(函數或者全局)作用域來決定thisvar foo1 = function(a){console.log(a);}foo1(2);// 兩種聲明是等效的var obj = {id : "awesome",cool:function coolFn(){console.log(this.id)}};var id = "not awesome";obj.cool(); //awesomesetTimeout(obj.cool,100); // not awesome // setTimeout 導致 cool()函數丟失了同this之間的綁定//解決方案var obj = {count : 0,cool: function coolFn(){var self = this;if(self.count<1){setTimeout(function timer(){self.count++;console.log("awesome");},100);}}}obj.cool(); // awesome*//*//7、動態作用域function foo(){console.log(a);}function bar(){var a = 3;foo();}var a = 2;bar(); //2 輸出結果是2,詞法作用域讓foo()中的a通過RHS引用到了全局//作用域中的a,因此會輸出2function foo(){console.log(a); //a is not defined}function bar(){var a = 3;foo();}bar();function foo(){var a = 3;console.log(a); //引用的是局部變量a的值}var a = 1;foo();// 3*//*//5、閉包作用域function foo(){var a = 2;function bar(){console.log(a);}return bar;}var baz = foo();baz(); //2 foo() 的返回值是bar()函數,所以通過baz()可以執行這個函數function foo(){var a = 2;function baz(){console.log(a);}bar(baz);} function bar(fn){fn(); }foo();//2 foofor(var i = 0;i<=5;i++){(function(){var j = i;setTimeout(function time(){console.log(j); // 每100毫秒輸出一個數,分別輸出0,1,2,3,4},j*100);})()}for(var i = 0;i<=5;i++){(function(j){setTimeout(function time(){console.log(j); // 每100毫秒輸出一個數,分別輸出0,1,2,3,4},j*100);})(i)}for(var i = 1;i<=5;i++){(function(){setTimeout(function time(){console.log(i); // 每100毫秒輸出一個數,分別輸出6,6,6,6,6},i*100);})()}*//*//4、提升 --先編譯在執行a = 2;var a;console.log(a);//a 因為var聲明的變量存在提升console.log(b); //undefined var聲明存在提升,賦值不存在提升,所以b存在但是沒賦值var b = 2;foo(); //函數竟然可以執行,說明函數聲明也提升了function foo(){console.log(a); //undefined , 聲明提升了,不存在賦值提升var a = 2;}foo(); //1 var foo;function foo(){console.log(1);}foo = function(){console.log(2)}//引擎編譯如下function foo(){console.log(1);}foo(); //1 var foo = function(){console.log(2)}foo(); //3//var foo 盡管出現在在function之前,但是由于是重復聲明,所以被忽略掉//函數聲明會被提升到普通變量之前function foo(){console.log(1);}var foo = function(){console.log(2);}function foo(){console.log(3);}foo(); // foo is not a functionvar a = true;if(a){function foo(){console.log("A");}}else{function foo(){console.log("B");}}*//*//3.4.3、let和var的區別for(var i = 0;i<10;i++){}console.log(i);// 10for(let j=0;j<10;j++){}console.log(j);// j is not defined//for循環結束后i并沒有被銷毀,導致全局污染*//*//3.3.2、立即執行函數:抱在一對括號內var a = 2;(function foo(){var a = 3;console.log(a); //3})();console.log(a);// 2*//*//塊級作用域,函數作用域//3.2、規避沖突*//*function foo(){function bar(a){i = 3;console.log(a+i);}for(var i = 0;i<10;i++){bar(i*2);}}foo();//死循環,bar中的i覆蓋了for循環中的i導致死循環*//*//2.2.1、evalfunction foo(str,a){ eval(str);console.log(a,b); //4}var b = 2;var result = foo("var b = 3;",1);console.log("result:",result); //undefined???默認嚴格模式?//書上的結果是1,3因為eval(str)== var b = 3; 讀取的是局部變量3function foo(str){"use strict";eval(str);console.log(a);}foo("var a = 2");//a si not defined*/</script>
</body></html>