首先
typeof bar === "object"
是檢測bar
是不是對象的可靠方法,但在javascript
中null
也被認爲是對象,所以如下代碼在控制檯中將輸出true
:javascript
var bar = null;
console.log(typeof bar == "object");
因此知道了
null
的問題,同時檢測bar
是不是null
,就能夠避免這一問題啦:java
console.log((bar !== null) && (typeof bar === "object"));
當
bar
是一個數組的時候,例如,當var bar = []
的時候;在不少狀況下,這是指望行爲,由於數字是真正的對象,但若是你想數組也返回false
時,能夠修改上述方案:數組
console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]"));
(function(){ var a = b = 3; })(); console.log(typeof a == "undefined"); console.log(typeof b == "undefined");
var a = b = 3;
這句代碼等同於:b = 3; var a = b;
這時候變量b
是不加var
聲明的變量,也就是全局變量,在函數內部沒有var
聲明的變量是隱式全局變量。因此控制檯打印的結果爲:true
和false
。 若是再深刻一步:在嚴格模式(使用use strict
),結果又會怎樣? 在嚴格模式下運行的結果是:報錯:b is not undefined
;這正是嚴格模式的特色,避免沒必要要的bug
(避免全局變量污染)。安全
this
的指向問題,如下代碼將會輸出什麼?var myObject = {
foo:"bar", func:function(){ var self = this; console.log(this.foo); console.log(self.foo); (function(){ console.log(this.foo); console.log(self.foo); }()); } }; myObject.func();
在外部函數中,
this
和self
都是指向myObject
,因此二者均可以正確的引用和訪問foo
,在內部函數中,this
再也不指向myObject
,結果是this.foo
沒有在內部函數中被定義。在ECMA5
以前,在內部函數中的this
將指向全局的window
對象;反之,由於做爲ECMA5
,內部函數中的功能this
是未定義的。因此控制檯將輸出:bar ;bar ;undefined ;bar ;
bash
use strict
有什麼意義和好處?
use strict
是一種在JavaScript
代碼運行時自動實行更嚴格解析和錯誤處理的方法。 嚴格模式的一些主要優勢包括:函數
1.使調試更加容易。那些被忽略或默默失敗了的代碼錯誤,會產生錯誤或拋出異常,所以儘早提醒你代碼中的問題,你才能更快地指引到它們的源代碼。測試
2.防止意外的全局變量。若是沒有嚴格模式,將值分配給一個未聲明的變量會自動建立該名稱的全局變量。這是JavaScript
中最多見的錯誤之一。在嚴格模式下,這樣作的話會拋出錯誤。字體
3.消除this
強制。若是沒有嚴格模式,引用null
或未定義的值到this
值會自動強制到全局變量。這可能會致使許多使人頭痛的問題和讓人巴不得拔本身頭髮的bug
。在嚴格模式下,引用 null
或未定義的this
值會拋出錯誤。ui
4.不容許重複的屬性名稱或參數值。當檢測到對象中重複命名的屬性,例如: var object = {foo: "bar", foo: "baz"};
) 或檢測到函數中重複命名的參數時,例如: function foo(val1, val2, val1){}
) 嚴格模式會拋出錯誤,所以捕捉幾乎能夠確定是代碼中的bug能夠避免浪費大量的跟蹤時間。this
5.使eval()
更安全。在嚴格模式和非嚴格模式下,eval()
的行爲方式有所不一樣。最顯而易見的是,在嚴格模式下,變量和聲明在eval()
語句內部的函數不會在包含範圍內建立(它們會在非嚴格模式下的包含範圍中被建立,這也是一個常見的問題源)。
6.在delete
使用無效時拋出錯誤。delete
操做符(用於從對象中刪除屬性)不能用在對象不可配置的屬性上。當試圖刪除一個不可配置的屬性時,非嚴格代碼將默默地失敗,而嚴格模式將在這樣的狀況下拋出異常。
javascript
自動插入分號機制?看下面的代碼,它們會返回什麼?function foo1(){ return { bar:"hello" }; } function foo2(){ return { bar:"hello" }; } console.log("foo1 returns:"); console.log(foo1()); consoel.log("foo2 returns:"); console.log(foo2());
以上代碼將會打印出:
foo1 returns:
Object {bar:"hello"} foo2 returns: undefined
緣由是這樣的,當碰到
foo2()
中包含return
語句的代碼行(代碼行上沒有其餘任何代碼),分號會當即自動插入到返回語句以後。請仔細留意上面兩個函數中return
的不一樣之處,foo2
函數的return
是單獨一行的。也不會拋出錯誤,由於代碼的其他部分是徹底有效的,即便它沒有獲得調用或作任何事情(至關於它就是是一個未使用的代碼塊,定義了等同於字符串"hello"
的屬性bar
)。因此,在使用return
語句的時候,要留意javascript
的這個特色,儘量不要將return
關鍵字寫在獨立的一行,避免沒必要形成沒必要要的錯誤。 在《JavaScript語言精粹》
這本書裏,這個「自動插入分號」機制被劃入到了JavaScript
的毒瘤裏面,與之並列的前面的全局變量。
NaN
是什麼?如何測試一個值是否等於NaN
?
NaN
屬性表明一個「不是數字」的值。這個特殊的值是由於運算不能執行而致使的,不能執行的緣由要麼是由於其中的運算對象之一非數字。例如:"abc" / 4
,要麼是由於運算的結果非數字。例如:除數爲零。雖然NaN
意味着「不是數字」,可是它的類型,無論你信不信,是Number
:
console.log(typeof NaN === "number") // true
此外, NaN 和任何東西比較,甚至是它本身自己,結果是false:
console.log(NaN == NaN) // false
一種半可靠的方法來測試一個數字是否等於
NaN
,是使用內置函數isNaN()
,但即便使用isNaN()
依然並不是是一個完美的解決方案。 一個更好的解決辦法是使用value !== value
,若是值等於NaN
,只會產生true
。由於只有NaN
這貨,纔會本身不等於本身。 另外,ES6
提供了一個新的Number.isNaN()
函數,這是一個不一樣的函數,而且比老的全局isNaN()
函數更可靠。
1.console.log(1 + "2" + "2"); // "122";
2.console.log(1 + +"2" + "2"); // "32";
根據運算的順序,要執行的第一個運算是
+"2"
(第一個"2"
前面的額外+
被視爲一元運算符),所以,JavaScript
將"2"
的類型轉換爲數字,而後應用一元 + 號(即將其視爲一個正數)。其結果就是獲得一個數字2
。
3.console.log(1 + -"1" + "2"); // "02";
4.console.log(+"1" + "1" + "2"); // "112";
5.console.log("a" - "b" + "2"); // "NaN2";
6.console.log("a" - "b" + 2); // NaN;
console.log( 0 || 1); // 1; console.log( 1 || 2); // 1; console.log( 0 && 1); // 0; console.log( 1 && 2); // 2;
在
JavaScript
中,||
和&&
都是邏輯運算符,用於在從左至右計算時,返回第一個可徹底肯定的「邏輯值」。
var a = {},
b = {key:"b"}, c = {key:"c"}; a[b] = 123; a[c] = 456; console.log(a[b]);
JavaScript
在設置對象的屬性的時候,會暗中字符串化參數值;在以上代碼中b
和c
都是對象,把它們設置爲對象a
的參數,它們都將被轉換爲"[object Object]"
, 因此a[b]
和a[c]
都至關於a['object Object']
;因此a[c]
會將a[b]
的值覆蓋掉,所以,設置或引用a[c]
和設置或引用a[b]
徹底相同。因此獲得的答案是456
;
line-height:15px; line-height:150%; line-height:1.5; line-height:1.5em;
行高爲150%時,會根據父元素的字體大小先計算出行高值而後再讓子元素繼承。因此當line-height:150%時,子元素的行高等於
父元素的fontSize值 * 150%
;
當line-height:1.5em時,會根據父元素的字體大小先計算出行高值而後再讓子元素繼承。因此當line-height:1.5em時,子元素的行高等於
父元素的fontSize值 * 1.5em
;
當line-height:1.5時,會根據子元素的字體大小動態計算出行高值讓子元素繼承。因此,當line-height:1.5時,子元素行高等於
子元素的fontSize值 * 1.5 = 45px
;若是沒有子元素,則以自身的fontSize值爲準
var person = {
_name: 'I am John', sayHello: function (){ return this._name; } }; var sayHello = person.sayHello; console.log(sayHello()); console.log(person.sayHello());
代碼運行的結果是:
undefined I am John
在執行
sayHello()
的時候,當訪問到this._name
時,此時的this
已經再也不是person
對象,而是全局窗口對象,也就是widnow
對象。與此同時,widnow
對象並不存在_name
屬性,因此返回的是undefined
。