使用 typeof bar === “object” 判斷 bar 是不是一個對象有何潛在的弊端。如何避免這種弊端。
var arr = []; var obj = {}; var nl = null; console.log(typeof arr === 'object'); //true console.log(typeof obj === 'object'); //true console.log(typeof nl === 'object'); //true// 從上面的輸出結果可知, 使用 typeof 並不能準確判斷 bar 就是一個 Object。// 可以通過 Object.prototype.toString.call(bar) === "[object Object]" 來避免這種弊端: console.log(Object.prototype.toString.apply(arr)); //[object Array] console.log(Object.prototype.toString.apply(obj)); //[object Object] console.log(Object.prototype.toString.apply(nl)); // [object Null]
另外,在控制台檢查會發現, if([]) { console.log('[] is true') } 點擊Enter鍵[] is trueundefined[]==true 點擊Enter鍵false[]===true 點擊Enter鍵false[]==false 點擊Enter鍵true ([]和 false值相同 )[]===false 點擊Enter鍵false ([]和 false類型不相同,===三個等號表示值和類型都相同)[object Array] VS [object Boolean]
2.下面的代碼會在 console 輸出神馬。為什麼。
(function(){ var a = b = 3;})();console.log("a defined? " + (typeof a !== 'undefined')); console.log("b defined? " + (typeof b !== 'undefined'));
// 函數所建立的範圍中的局部變數,JS中只有函數可以建立作用。 // JS不存在塊級範圍 // JS中是詞法範圍(與之對立的為動態範圍),在代碼寫好的那一刻,範圍就已經確定了 // 詞法範圍的規則: // 函數允許訪問函數外的資料 // 如果當前範圍中有了該變數,就不考慮外面的同名變數 (function() { var a = b = 3; // 這一句等價於: // b = 3; 全域變數 // var a = b; })(); console.log(a); // Uncaught ReferenceError: a is not defined 報錯後,後面的不執行,要想後面代碼執行,需要屏蔽這一句。 console.log(typeof a); // undefined console.log(b); //3 console.log("a defined? " + (typeof a !== 'undefined')); //false console.log("b defined? " + (typeof b !== 'undefined')); // true
3.下面的代碼會在 console 輸出神馬。為什麼。
var myObject = { foo: "bar", func: function() { var self = this; console.log("outer func: this.foo = " + this.foo); console.log("outer func: self.foo = " + self.foo); (function() { console.log("inner func: this.foo = " + this.foo); console.log("inner func: self.foo = " + self.foo); }()); } }; myObject.func();
我們在sublime中寫出來,實踐出真知:
var myObject = { foo: "bar", func: function() { var self = this; //self指的是myObject對象 console.log(this); //這裡的this指的是myObject對象 console.log("outer func: this.foo = " + this.foo); // bar 。。 console.log("outer func: self.foo = " + self.foo); // bar (function() { console.log(this);//這裡的this指window console.log(self); //self就是myObject console.log("inner func: this.foo = " + this.foo); // undefined window上是沒有foo屬性的 console.log("inner func: self.foo = " + self.foo); // bar }()); } }; myObject.func();第一個和第二個的輸出不難判斷,self和this都是指的調用func的對象myObject,所以列印結果都是bar。對於第三個,因為 this (指的是window)在可訪問到的範圍內是 undefined,第四個輸出是 undefined。在 ES6 之前,JavaScript 只有函數範圍,所以 func 中的 IIFE 有自己的獨立範圍,並且它能訪問到外部範圍中的 self,所以第四個列印也是bar。
如果你知道閉包,下面的內容也是很好理解的:
var myObject = { foo: "bar", func: function() { var self = this; (function(test) { // 當myObject.func();執行完畢後,下面的IIFE等於放在最外層執行,此時的this指的是window console.log("inner func: this.foo = " + this.foo); //'bar' // 這裡實參傳遞給形參等價於下面兩行代碼 // var test; // test = self; console.log(self); //self就是myObject console.log(test); //test就是self也即myObject console.log("inner func: this.foo = " + test.foo); //'bar' console.log("inner func: self.foo = " + self.foo); }(self)); } }; myObject.func();
4.將 JavaScript 程式碼封裝含在一個函數塊中有什麼意思呢。為什麼要這麼做。
這個問題其實就是看你是否掌握了閉包,關於閉包我打算專門寫一篇博文,這個問題也可以理解為,IIFE的作用是什麼
IIFE即是: 立即執行函數運算式(Immediately-Invoked Function Expression)
先看下下面這段代碼:
for(var i =0;i<6;i++){ setTimeout(function(){ console.log(i); }, 1000); }列印結果是什麼呢。六個6很經典的一個問題:所有的主任務的代碼執行完畢之後,去檢查所有的setTimeout回呼函數,如果到時間了就執行,此時i已經變為6了。可以用閉包來解決這個問題,關於閉包,我總結了三個關於閉包的特點,其實不用看我的總結,只要你觀察下閉包,基本上也就是這三個特點: // 1.IIFE // 2.函數裡面的內容不會立即執行,調用的時候(時間到了或者使用者點擊的時候)才會執行 // 3.1 函數裡面內容雖然不會立即執行,如果再每次迴圈階段(預解析階段)把值以函數參數的形式傳進去之後,在函數執行階段,用的就是當時傳進去的值 // 3.2 函數裡面內容雖然不會立即執行,如果在內層作為傳回值return出來的函數中,定義一個變數,引用了外層的變數,那麼執行階段,用的就是預解析階段引用的值 好,我們看下鋼材那個問題,如果想要輸出0,1,2,3,4,5該怎麼改寫代碼 for (var i = 0; i < 6; i++) { function foo(j) { return function() { /第2條 console.log(j); } } var f = foo(i); //第1條 第3.1條(至於第3.2條,等我專門寫閉包了再講吧) setTimeout(f, 1000); }好了上面是IIFE的第一個常用之處。---------- 另外 JQuery/Node 的外掛程式和模組開發中,為避免變數汙染,也是一個大大的 IIFE:(function($) { //代碼 } )(jQuery);而不是直接的function(){ jQuery...}
5.下面兩個函數的傳回值是一樣的嗎。為什麼。
function foo1() { return { bar: "hello" }; } function foo2() { return //這裡換行 { bar: "hello" }; } var o1 = foo1(); var o2 = foo2(); console.log(o1.bar); //hello console.log(o2.bar); //Uncaught TypeError: Cannot read property 'bar' of undefined在程式設計語言中,基本都是使用分號(;)將語句分隔開,這可以增加代碼的可讀性和整潔性。而在JS中,如若語句各占獨立一行,通常可以省略語句間的分號(;),JS 解析器會根據能否正常編譯來決定是否自動填滿分號:var test = 1 + 2console.log(test); //3在上述情況下,為了正確解析代碼,就不會自動填滿分號了,但是對於 return 、break、continue 等語句,如果後面緊跟換行,解析器一定會自動在後面填充分號(;),所以第二個函數報錯,第二段代碼等價於: function foo2() { return; //這裡換行 { bar: "hello" }; }
6.神馬是 NaN,它的類型是神馬。怎麼測試一個值是否等於 NaN?
NaN 是 Not a Number 的縮寫,JavaScript 的一種特殊數值,可以通過 isNaN(param) 來判斷一個值是否是 NaN:console.log(isNaN(NaN)); // trueconsole.log(isNaN(123)); // falseconsole.log(isNaN("1111")); // falseconsole.log(isNaN("1asd")); // trueconsole.log(isNaN("asdaa222"));// trueconsole.log(isNaN("'ssss'")); // trueconsole.log(isNaN==isNaN); // trueconsole.log(isNaN===isNaN); // trueconsole.log(Object.prototype.toString.apply(isNaN));// [object Function]console.log(Object.prototype.toString.call(isNaN)); // [object Function]console.log(typeof isNaN) // function