effective javascript 學習心得

第2條:理解JavaScript的浮點數

1.js數字只有一種類型java

2.見代碼ajax

/**
 * Created by Administrator on 2017/7/2.
 */
console.log("charpter2");
console.log(1-0.41); //0.5900000000000001 double不能精確計算
console.log((8).toString(2));//1000 數字轉其餘進制輸出
console.log(parseInt("1001", 2));//9 其餘進制轉數字

 

第3條:小心隱式的類型轉換

1.       - * / % 在計算以前會把參數轉化成數字, +能夠是數字或者字符串,有字符串就優先字符串, 位運算符 ~ & | ^ <<  >>  >>>會將參數轉化成32位整數chrome

2.見代碼api

 1 console.log("charpter3");
 2 console.log("17" * 3); //51
 3 console.log(NaN === NaN);//false
 4 console.log(isNaN(NaN));//true
 5 console.log(isNaN("haha"));//true
 6 console.log(isNaN(""));//false
 7 console.log(isNaN(null));//false
 8 console.log(isNaN(undefined));//true
 9 console.log(null === null);//true
10 console.log(undefined === undefined);//true
11 function isReallyNaN(a) { // 判斷參數究竟是不是NaN的最簡單方法
12     return a !== a;
13 }
14 console.log("object : " + {
15         toString: function () {
16             return "object"
17         }, valueOf: function () {
18             return 123;
19         }
20     }); //優先選擇valueOf做爲返回值

3. if || && 會把參數轉化成布爾值, js裏有7個轉化後爲假的值: false 0 -0 null undefined NaN ""數組

4.檢查參數是否爲undefined能夠用typeof(x) === "undefined" 或者 x===undefined瀏覽器

 

第4條:原始類型因爲封裝對象

1.js有5個原始值類型:boolean number string null undefined安全

2.原始值也能夠調用對應的包裝類的方法,可是對原始值設置屬性沒有什麼用處,由於原始值會被隱式封裝成1個新的對象,因此實際上是在操做那個新的對象.閉包

3.一些實驗併發

 1 console.log("charpter4");
 2 console.log(typeof null); //object, null比較特殊,和object同樣
 3 console.log(typeof undefined);//undefined
 4 console.log(typeof NaN);//number
 5 console.log(typeof true);//boolean
 6 //String類和字符串仍是有區別的
 7 console.log(typeof "");//string
 8 console.log(typeof new String());//object
 9 console.log("123" === "123");//true
10 console.log(new String("123") == new String("123"));//false

 

第5條:避免對混合類型使用==運算符

1.將字符串轉爲數字可使用Number()或者+運算符app

2.實驗結果:

 1 console.log("charpter4");
 2 // == 比較的原則爲
 3 console.log(null == undefined); //true 1.null,undefined 與 null,undefined比較不轉型直接返回true
 4 console.log(null == 0); //false 2. null,undefined 與 非null,undefined 比較不轉型直接返回false
 5 
 6 // 3.非null,undefined原始類型與Date比較都轉爲數字,Date比較特殊,優先調用toString而不是valueOf
 7 var dateToStringFunction = Date.prototype.toString;
 8 Date.prototype.toString = function(){
 9     console.log("Date.toString");
10     var result = dateToStringFunction.apply(this, arguments);
11     console.log(result);//Sun Jul 02 2017 18:12:42 GMT+0800 (中國標準時間)
12     return result;
13 }
14 var dateValueOfFunction = Date.prototype.valueOf;
15 Date.prototype.valueOf = function(){
16     console.log("Date.valueOf");
17     var result = dateValueOfFunction.apply(this, arguments);
18     console.log(result);
19     return result;
20 }
21 console.log(true == new Date()); //false 由於轉化成數字 new Data().toString() 結果爲NaN
22 //clean
23 Date.prototype.toString = dateToStringFunction;
24 Date.prototype.valueOf = dateValueOfFunction;
25 
26 // 4.非null,undefined原始類型與非Date比較都轉爲數字,優先調用valueOf
27 var objectToStringFunction = Object.prototype.toString;
28 Object.prototype.toString = function(){
29     console.log("Object.toString");
30     var result = objectToStringFunction.apply(this, arguments);
31     console.log(result);
32     return result;
33 }
34 var objectValueOfFunction = Object.prototype.valueOf;
35 Object.prototype.valueOf = function(){
36     console.log("Object.valueOf");
37     var result = objectValueOfFunction.apply(this, arguments);
38     console.log(result); //Object
39     return result;
40 }
41 console.log(true == new Object()); //false
42 //clean
43 Object.prototype.toString = objectToStringFunction;
44 Object.prototype.valueOf = objectValueOfFunction;
45 
46 //5.非null,undefined原始類型與非null,undefined原始類型比較轉爲數字
47 console.log(true == "1"); //true

3.==會產生隱式類型轉化,因此仍是本身強制轉化而後使用===比較好理解.

 

第6條:瞭解分號插入的侷限

1.js能夠自動插入分號.規則是:①分號僅在}以前,一個或多個換行以後和程序輸入的結尾被插入,因此一行有多處要插入分號的話是不能省略的.

②分號在隨後的輸入標記不能解析時插入,這可能會致使程序解析和想的不同.好比

a=b
["r", "g", "b"].foEach(function(key)){
    .........  
}

會被解釋成a = b["b"].forEach(......),由於b["r", "g", "b"]能夠被解析(,分隔表達式從左向右執行,返回最後邊的表達式的值)

③for不會做爲for循環頭部被插入,因此若是for頭部有多行,要本身插入分號

2.通常仍是本身插入;比較清楚簡單,可是有時候js也會自動插入分號.好比return同一行最後.

return 
{};

等價於return ; {};程序不會報錯.其餘還有些限制產生式.可是我基本都會自動插入;而且不換行避免.

 

第7條:視字符串爲16位代碼單元序列

1.當字符串包含輔助平面的代碼點時候,js將每一個代碼點表示爲2個元素而不是1個.因此特殊字符應該算length=2,好比∮.

可是實際上我本身測試結果長度仍是1.

不知道爲何..

 

第8條:儘可能少用全局對象

console.log();
console.log("charpter8");
//console.log(a); //Uncaught ReferenceError: a is not defined
console.log(this.a);//undefined

 

第9條:始終聲明局部變量

1.JS給一個未綁定的變量賦值會簡單的建立一個新的全局變量並賦值給它,而不是報錯.

 

第10條:避免使用with

1.如題

2.在with代碼塊的內部,變量查找先開始找with對象的屬性,和從原型鏈上繼承下來的屬性,沒有再找外部做用域.

4.with須要搜素對象的原型鏈,因此運行速度比通常代碼塊慢.

 

第11條:熟練掌握閉包

1.閉包就是可以使用外部做用域定義的變量的函數

2.閉包比建立他們的函數有更長的聲明週期

3.一個測試:

 1 console.log();
 2 console.log("charpter11");
 3 (function () {
 4     function f() {
 5         var a = 1;
 6         function add1() {
 7            a++;
 8            console.log(a);
 9         }
10         function add2() {
11             a++;
12             console.log(a);
13         }
14         add1(); // 2
15         add2(); // 3
16     }
17     f();
18 })();

 

第12條:理解變量聲明提高

1.JS不支持塊級做用域,變量定義的做用域並非離其最近的代碼塊,而是包含它們的函數.

2.JS沒有塊級做用域的一個例外是異常.

 

 

第13條:熟練掌握閉包

1.閉包存儲的是其外部變量的引用而不是值

2.能夠用自執行函數來建立局部做用域

3.JS不支持塊級做用域,可是可使用函數做用域代替.

 

第14條:小心命名函數表達式笨拙的做用域

1.命名函數表達式因爲會致使不少問題,因此並不值得使用

2.一些實驗

console.log();
console.log("charpter14");
// 如下測試說明的個人360極速的chrome內核已經支持es5了.
(function () {
    var constructor = function () {
        return null;
    };
    var f = function f() {
        return console.log(constructor());//null
    };
    f();

    var f = function () {
        return console.log(constructor());//null
    };
    f();
})();

 

 

第15條:小心命名函數表達式笨拙的做用域

1.由於沒有塊級做用域,因此聲明在代碼塊中的函數其實仍是至關於聲明在外部做用域中的.但也不是全部環境都是如此,因此很容易出錯.

2.ES5官方指定函數聲明只能出如今其餘函數或者程序的最外層.

3.可使用var 聲明和有條件的賦值語句代替有條件的函數聲明.

4.一個實驗

 1 console.log();
 2 console.log("charpter15");
 3 (function () {
 4     function f() {
 5         return "global";
 6     }
 7 
 8     function test(x) {
 9         var g = f;
10         result = [];
11         if (x) {
12             g = function () {
13                 return "local";
14             }
15             result.push(g());
16         }
17         result.push(g());
18         return result;
19     }
20     console.log(test(false)); //["global"]
21     console.log(test(true)); // ["local", "local"]
22 })();

 

第17條:間接調用eval函數優於直接調用

1.綁定eval函數到另一個變量名,經過該變量名調用函數會使代碼失去對全部局部做用域的訪問能力

2.測試:

 1 var a = "global";
 2 console.log();
 3 console.log("charpter17");
 4 //直接調用eval就和普通函數同樣,間接調用的話只能訪問全局做用域
 5 (function () {
 6     var a = "outer";
 7     function test(){
 8         var a = "inner";
 9         console.log(eval("a")); //inner
10     }
11     test();
12 
13     function test2(){
14         var a = "inner";
15         console.log((0, eval)("a"));//global
16     }
17     test2();
18 
19     function test3(){
20         var a = "inner";
21         var f = eval;
22         console.log(f("a"));//global
23     }
24     test3();
25 
26     function test4(){
27         var a = "inner";
28         console.log((eval)("a"));//inner
29     }
30     test4();
31 
32     function test5(){
33         //var a = "inner";
34         console.log(eval("a")); //outer
35     }
36     test5();
37 })();

3.儘量間接調用eval函數,隱藏細節,同時也加快執行速度.

 

第18條:理解函數調用、方法調用以及構造函數調用之間的不一樣

1.在方法調用中是由調用表達式自身來肯定this變量的綁定.綁定到this變量的對象被稱爲調用接收者.

2.一般,經過某個對象調用方法將查找該方法並將該對象做爲該方法的接收者

3.一個非方法的函數調用會將全局對象做爲接收者.

 

第19條:熟練掌握高階函數

1.高階函數式那些將函數做爲參數活返回值的函數

2.須要引入高階函數抽象的信號是出現重複或類似的代碼.

 

第23條:永遠不要修改arguments對象

1.如題,由於形參指向的是arguments中的元素,修改arguments實際上會修改形參

2.能夠經過[].slice[arguments]來複制一份(淺克隆).

3.實驗

 1 console.log();
 2 console.log("charpter23");
 3 //obj 指向 arguments[0] . method指向 arguments[1]
 4 (function () {
 5     function callMethod(obj, method) {
 6         var shift = [].shift;
 7         shift.call(arguments);
 8         shift.call(arguments);
 9         return obj[method].apply(obj, arguments);
10     }
11 
12     var obj = {
13         add : function (x, y) {
14             return x + y;
15         }
16     }
17 
18     //callMethod(obj, "add", 17, 25); //Uncaught TypeError: Cannot read property 'apply' of undefined
19 })();

 

第25條:使用bind方法提取具備肯定接收者的方法

1.在ES5中可使用bind方法爲方法綁定一個接收者

2.實驗:

 1 console.log();
 2 console.log("charpter25");
 3 (function () {
 4     function f() {
 5         console.log(this);
 6     }
 7     var f2 = f.bind({});
 8     f();//window
 9     f2();//object
10 
11 })();

 

第26條:使用bind方法實現函數柯里化

1.將函數與其參數的一個本身綁定的技術成爲函數柯里化.

其實並非很懂是啥意思,大概就是說原本參數是隨便傳入的,如今可能有些參數的值被固定了,剩下的參數隨便傳,多是把一個很是通用的函數拆成部分業務通用的函數.

2實驗:

 1 console.log();
 2 console.log("charpter26");
 3 (function () {
 4     function f(a, b, c) {
 5         console.log(arguments); // ["a", "b", 1, 0, Array[3]] ......value=1 index=0 array=Array[3]
 6         return a + b + c;
 7     }
 8     var a = [1, 2, 3];
 9     var b = a.map(f.bind(null, "a", "b")); //用bind簡化函數調用,固定值能夠直接寫死.
10     console.log(b); //["ab1", "ab2", "ab3"]
11 
12     //猜想bind的實現原理
13     function bind2() {
14         var arg0 = arguments;
15         var me = this;
16         return function () {
17             var arg = [].slice.apply(arg0, [1]);
18             arg.push.apply(arg, arguments) //後來發現array有個concat方法直接能夠用....args.concat(arguments)
19             return me.apply(arg0[0], arg);
20         }
21     }
22     Function.prototype.bind2 = bind2;
23     //bind2 實驗1
24     var b2 = a.map(f.bind2(null, "c", "d"));
25     console.log(b2); //["cd1", "cd2", "cd3"]
26     //bind2 實驗2
27     var fun = console.log.bind2(console, "jet: ");
28     fun("hello world!"); //jet:  hello world!
29     //bind2 實驗3
30     var fun2 = function () {
31         console.log(this);
32     }
33     fun2.bind2(new Date())(); //Sun Jul 09 2017 16:12:55 GMT+0800 (中國標準時間)
34 })();

原本f方法裏應該傳3個參數a,b,c應該都是可變的,如今經過bind2直接寫死了a和b,這樣就只能變化c了.可能在部分業務能夠減小不少代碼.由於a和b的值是固定的.可是我感受這樣好不習慣..用bind感受沒有直接傳函數清楚,可能我用的比較少.

25, 26兩節總結下的話就是bind函數能夠改變函數中的this.同時能夠寫死函數的部分參數值(實際上是返回了一個新的函數來實現的).

 

 

第27條:使用閉包而不是字符串來封裝代碼

1.eval函數裏面使用的變量有可能會是全局變量也有多是局部變量,要看怎麼使用,因此比較容易出問題

2.閉包能夠訪問外部做用域的局部變量,因此有局部變量確定先找局部變量.

3.傳字符串代碼的代碼很難寫,編譯期也很難優化.而閉包則很簡單.

4.一些測試:

 1 console.log();
 2 console.log("charpter27");
 3 var a = "global";
 4 (function () {
 5     var a = "outer";
 6     function f(n) {
 7         eval(n);
 8     }
 9     function log() {
10         var a  = "inner";
11         f("console.log(a)");
12     }
13     log(); //outer
14 
15 
16     function f2(){
17         console.log(a);
18     }
19     function log2() {
20         var a = "inner";
21         f2();
22     }
23     log2(); //outer
24 })();

 

第30條:理解prototype、getPrototypeOf和__prototype__之間的不一樣

1.在對象上獲取原型對象能夠經過Object.getPrototypeOf方法,或者obj.__proto__

2.js中類的本質是一個構造函數與一個用於在該類實例間共享方法的原型.

3.實驗:

 1 console.log();
 2 console.log("charpter30");
 3 (function () {
 4     var a = {};
 5     console.log(Object.getPrototypeOf(a) === Object.prototype);//true
 6     console.log(Object.getPrototypeOf("") === String.prototype);//true
 7 
 8     function f(a,b) {
 9         this.a = a;
10         this.b = b;
11     }
12     f.prototype.c = 1;
13     console.log(f.toString === Function.prototype.toString);//true
14     console.log(f.toString === Object.prototype.toString);//false
15     console.log(f.prototype.a);//undefined 構造函數構造出來的對象的屬性再也不原型對象上
16     //和java的原理同樣,就是建立的時候對象有個指向原型的指針
17     var objF = new f();
18     console.log(objF.c);//1
19     f.prototype.c = 2;
20     console.log(objF.c);//2
21     f.prototype = {};
22     console.log(objF.c);//2
23 })();

 

第32條:始終不要修改__proto__屬性

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create

 1 //Shape - superclass
 2 function Shape() {
 3   this.x = 0;
 4   this.y = 0;
 5 }
 6 
 7 Shape.prototype.move = function(x, y) {
 8     this.x += x;
 9     this.y += y;
10     console.info("Shape moved.");
11 };
12 
13 // Rectangle - subclass
14 function Rectangle() {
15   Shape.call(this); //call super constructor.
16 }
17 
18 Rectangle.prototype = Object.create(Shape.prototype);
19 
20 var rect = new Rectangle();
21 
22 rect instanceof Rectangle //true.
23 rect instanceof Shape //true.
24 
25 rect.move(1, 1); //Outputs, "Shape moved."

Rectangle.prototype.__proto__  === Shape.prototype 爲true.因此var a = Object.creatye(X)就是建立了一個對象a它的原型是X.

第33條:使用構造函數與new操做符無關

1 console.log();
2 console.log("charpter33");
3 (function () {
4     function f() {
5         return new String("123");
6     }
7     console.log(new f()); //String {0: "1", 1: "2", 2: "3", length: 3, [[PrimitiveValue]]: "123"} return能夠覆蓋new返回的對象
8 })();

 

第37條:認識this變量的隱式綁定問題

1.在回調函數中this很難看出來到底指向什麼對象.因此要清楚的表達有3種方式:

第一個就是回調函數API多傳1個對象,調用方法的時候this綁定到這個對象.因此這個是要看api是怎麼寫的.

第二個就是用對象指向this,好比在外層var me = this.而後調用me.XXX

第三個使用bindFunction.prototype.bind方法的第一個參數能夠綁定方法的this指針.

第38條:在子類的構造函數中調用父類的構造函數

1.js繼承的步驟:

第一,子類的構造函數不中調用Parent.call(this,.....);

第二,Child.prototype = Object.create(Parent.prototype);

 

第41條:將原型視爲實現細節

1.實驗:

 1 console.log();
 2 console.log("charpter41");
 3 (function () {
 4     function f(x) {
 5         this.a = x;
 6     }
 7 
 8     f.prototype.a2 = function () {
 9 
10     }
11 
12     function f2(x, y) {
13         f.call(this, x);
14         this.b = y;
15     }
16 
17     f2.prototype = Object.create(f.prototype);
18     f2.prototype.b2 = function () {
19 
20     }
21 
22     var test = new f2();
23     console.log(test);
24     console.log(test.__proto__ === f2.prototype); // true
25     console.log(f2.prototype.__proto__ === f.prototype); // true
26     console.log(test.hasOwnProperty("b2")); // false
27     console.log(test.hasOwnProperty("b")); // true
28     console.log(test.hasOwnProperty("a")); // true 實例都是定義在對象裏的
29     console.log(f2.prototype.hasOwnProperty("b2")); // true
30 })();

 

第43條:使用Object的直接實例構造輕量級字典

1.實驗:

 1 console.log();
 2 console.log("charpter43");
 3 //利用Object.defineProperty能夠添加特殊屬性
 4 (function () {
 5     var o = {}; // 建立一個新對象
 6 // Example of an object property added with defineProperty with a data property descriptor
 7     Object.defineProperty(o, "a", {
 8         value: 37,
 9         writable: true,
10         enumerable: false,
11         configurable: true
12     });
13 
14     var o2 = {a: 37};
15 
16     for (var i in o) {
17         console.log(i); //無輸出,由於不能枚舉a屬性
18     }
19     for (var i in o2) {
20         console.log(i); //a
21     }
22 
23     console.log({} instanceof Object);//true
24     console.log({}.__proto__ === Object.prototype);//true
25 })();

 

第44條:使用null原型以防止原型污染

1.實驗:

 1 console.log();
 2 console.log("charpter44");
 3 (function () {
 4     function f() {
 5 
 6     }
 7     f.prototype =null;
 8     var a = new f();
 9     console.log(Object.getPrototypeOf(a) === Object.prototype); // true
10 
11     var b = Object.create(null);
12     console.log(Object.getPrototypeOf(b) === null); // true 利用Object.create(null);來建立空原型的對象
13 })();

 

第45條:使用hasOwnProperty方法以免原型污染

1.實驗

 1 console.log();
 2 console.log("charpter45");
 3 (function () {
 4     var a = {};
 5     console.log("toString" in a); //true
 6 
 7     for (var i in a) {
 8         console.log(i); //無輸出,不能被遍歷的屬性用in仍是返回true的
 9     }
10     
11 })();

 

第48條:避免在枚舉期間修改對象

for in 循環可能在不一樣的js環境中選擇不一樣的枚舉順序,甚至在同一個js環境中執行也不相同.

 

第49條:數組迭代要優先使用for循環而不是for...in循環

1.for...in循環始終枚舉全部key,key始終是字符串.

 

第50條:迭代方法優於循環

1.循環只有一點優於迭代函數,那就是前者有控制流程,如break,continue.

 

第51條:在數組對象上服用通用的數組方法

1.複用數組方法傳入的參數不必定就是要數組,也能夠是類數組,只要知足條件

①有length屬性,0-2^32-1

②有索引,小於length在0-2^32-2.

第58條:區分數組對象和類數組對象

1.API毫不應該重載於其餘類型有重疊的類型,好比區分Array和Object就比較麻煩.

2.當瀏覽器跨frame通訊的時候,一個frame中的數組不會繼承自另外一個frame的Array.prototype

3.實驗

console.log();
console.log("charpter58");
(function () {
    console.log(typeof []); //object
    console.log(typeof {}); //object
    console.log([] instanceof Array); //true
    console.log(Array.isArray([])); //true
})();

 

第60條:支持方法連

1.無狀態的方法能夠返回新的對象支持方法鏈,好比string的replace,有狀態的方法使用返回this來支持方法鏈

第61條:不要阻塞I/O事件隊列

1.js併發的接受事件,但會使用一個事件隊列按順序地處理事件處理程序.

個人理解:

 1 console.log();
 2 console.log("charpter61");
 3 (function () {
 4     //3 1 2
 5     $.ajax({
 6         url: "/a.jsp",
 7         success : function (data) {
 8             for(var i=0; i< 10000000000; i++){
 9 
10             }
11             console.log(1);
12         }
13     });
14     $.ajax({
15         url: "/b.jsp",
16         success : function (data) {
17             console.log(2);
18         }
19     });
20     console.log(3);
21 })();

3,必定是在1和2以前的.可是1,2之間的順序要看後臺運行狀況.多是12,也多是21,因此個人理解是ajax是異步執行的,請求收到返回結果之後看哪一個ajax先註冊時間處理程序哪一個就先執行.

第62條:在異步序列中使用嵌套活命名的回調函數

1.實驗

 1 console.log();
 2 console.log("charpter62");
 3 (function () {
 4     // 3 4 5 1 2
 5     $.ajax({
 6         url: "/a.jsp",
 7         success: function (data) {
 8             for (var i = 0; i < 1000000000; i++) {
 9 
10             }
11             console.log(1);
12         }
13     });
14     $.ajax({
15         url: "/b.jsp",
16         success: function (data) {
17             console.log(2);
18         }
19     });
20     console.log(3);
21     for (var i = 0; i < 3000000000; i++) {
22 
23     }
24     $.ajax({
25         async: false,
26         url: "/a.jsp",
27         success: function (data) {
28             for (var i = 0; i < 1000000000; i++) {
29 
30             }
31             console.log(4);
32         }
33     });
34     console.log(5);
35 })();
36 
37 (function () {
38     // 5 1
39     $.ajax({
40         url: "/a.jsp",
41         success: function (data) {
42             console.log(1);
43         }
44     });
45     for (var i = 0; i < 3000000000; i++) {
46 
47     }
48     console.log(5);
49 })();
50 
51 (function () {
52     // 後臺哪一個斷點先放開就輸出哪一個對應的值
53     $.ajax({
54         url: "/TestServlet",
55         success: function (data) {
56             console.log(1);
57         }
58     });
59     $.ajax({
60         url: "/TestServlet2",
61         success: function (data) {
62             console.log(2);
63         }
64     });
65     console.log(5);
66 })();
67 
68 (function () {
69     // 在打印2以前後臺就會收到請求,可是就算返回了仍是先輸出2再輸出1
70     $.ajax({
71         url: "/TestServlet",
72         success: function (data) {
73             console.log(1);
74         }
75     });
76     for (var i = 0; i < 3000000000; i++) {
77 
78     }
79     console.log(2);
80 })();

前2個實驗:

第一個實驗3,4,5,1,2的輸出說明了異步操做的回調函數確定是後於主函數執行的.

第二個實驗5,1的輸出說明了只有等主函數執行完畢纔會輪到回調函數的觸發.即便以前ajax已經返回結果也不會直接調用回調函數.

第三個實驗我在後臺打了斷點,先放開哪一個斷點就執行哪一個回調函數,說明ajax請求是異步的,可是隻有等資源返回之後纔會註冊回調函數給事件隊列,並不由於第一個ajax寫在第二個ajax上面,它的success就先執行.而是等資源返回之後纔會註冊success.因此當第二個斷點先放開的時候會先註冊第二個ajax的success函數到事件隊列中.

第四個實驗在js打印2以前後臺斷點就收到請求.因此ajax請求資源是當即的.可是回調函數是資源返回完之後才註冊的.

第63條:小心丟棄錯誤

1.異步API直接使用trycatch是不對的,由於結果會馬上返回也不會有錯誤.通常異步API都回傳一個處理錯誤的回調函數來處理出錯的狀況,或者向回調函數中額外傳一個包裝了錯誤的參數,若是這個參數不爲null或者其餘假值,說明發生了錯誤.

第64條:對異步循環使用遞歸

1.把異步API放到循環中調用只會一次啓用N個異步操做,若是想異步操做同步進行,須要遞歸調用這些異步操做.

2.異步API是不會致使棧溢出的,由於調用會馬上返回,當回調函數被壓入棧的時候棧確定是空的.

第65條:不要在計算時阻塞事件隊列

1.若是計算須要很長時間,使用遞歸和循環都會致使主線程被卡死,能夠考慮使用異步的操做好比setTimeout來解決,由於是異步的,在異步過程當中其餘事件能夠被響應.優化一點的話一次異步過程當中可使用循環計算N次操做而不是單次操做.

第66條:使用計數器來執行並行操做

1.多個異步操做的回調函數的順序是不一樣的,因此若是要同步全部異步操做的結果再調用回調函數的話可使用計數器,每一個異步操做結束都把計數器數字-1,並判斷計數器是否爲0.

第67條:毫不要同步地調用異步的回調函數

1.同步的調用異步函數會致使執行順序被改變,同時異步函數的遞歸調用是安全的,不會棧溢出,而同步的調用回調函數則不能保證.若是回調函數拋出異常就有可能會中斷整個函數執行.

2.可使用setTomeout(fun, 0)來異步調用fun函數.

相關文章
相關標籤/搜索