JavaScript是一種弱類型腳本語言,所謂弱類型指的是定義變量時,不須要什麼類型,在程序運行過程當中會自動判斷類型javascript
typeof xxx
獲得的值有一下類型:undefined、boolean、number、string、object、function、symbol
前端
typeof null
結果是object
,實際這是typeof
的一個bug
,null
是原始值,非引用類型typeoof [1,2]
結果是object
,結果中沒有這一項,引用類型除了function
其餘的所有都是objecttypeof Symbol()
用typeof
獲取symbol
類型的值獲得的是symbol
,這是ES6
新增的知識點用於實例和構造函數的對應。例如判斷一個變量是不是數組,使用typeof
沒法判斷,但可使用[1,2] instanceof Array來判斷。由於,[1,2]
是數組,它的構造函數就是Array:同理java
function Foo(name) { this.name = name } var foo = new Foo('bar') console.log(foo instanceof Foo) // true
除了原始類型,ES還有引用類型,上文提到的typeof識別出來的類型中,只有object和function是引用類型,其餘都是值類型數組
根據JavaScript中的變量類型傳遞方式,又分爲值類型
和引用類型
值類型包括:Boolean、string、number、undefined、null
;
引用類型包括:object類的全部,如Date、Array、function等。
在參數傳遞方式上,值類型是按值傳遞,引用類型是按地址傳遞promise
// 值類型 var a = 10 var b = a b = 20 console.log(a) // 10 console.log(b) // 20
上述代碼中,a b都是值類型,二者分別修改賦值,相互之間沒有任何影響。再看引用類型的例子:瀏覽器
// 引用類型 var a = {x: 10, y: 20} var b = a b.x = 100 b.y = 200 console.log(a) // {x: 100, y: 200} console.log(b) // {x: 100, y: 200}...
上述代碼中,a b都是引用類型。在執行了b = a以後,修改b的屬性值,a的也跟着變化。由於a和b都是引用類型,指向了同一個內存地址,即二者引用的是同一個值,所以b修改屬性時,a的值隨之改動。
再借助題目進一步講解一下。閉包
function foo(a){ a = a * 10; } function bar(b){ b.value = 'new'; } var a = 1; var b = {value: 'old'}; foo(a); bar(b); console.log(a); // 1 console.log(b); // value: new...
經過代碼執行,會發現:ecmascript
Number
類型的a
是按值傳遞的,而Object
類型的b
是按地址傳遞的。** JS 中這種設計的緣由是:**按值傳遞的類型,複製一份存入棧內存,這類類型通常不佔用太多內存,並且按值傳遞保證了其訪問速度。按共享傳遞的類型,是複製其引用,而不是整個複製其值(C 語言中的指針),保證過大的對象等不會由於不停複製內容而形成內存的浪費。...異步
引用類型常常會在代碼中按照下面的寫法使用,或者說容易不知不覺中形成錯誤!函數
var obj = { a: 1, b: [1,2,3] } var a = obj.a var b = obj.b a = 2 b.push(4) console.log(obj, a, b)
雖然obj自己是個引用類型的變量(對象),可是內部的a和b一個是值類型一個是引用類型,a的賦值不會改變obj.a,可是b的操做卻會反映到obj對象上。
JavaScript 是基於原型的語言,原型理解起來很是簡單,但卻特別重要,下面仍是經過題目來理解下JavaScript 的原型概念。
對於這個問題,能夠從下面這幾個要點來理解和回答,下面幾條必須記住而且理解
// 要點一:自由擴展屬性 var obj = {}; obj.a = 100; var arr = []; arr.a = 100; function fn () {} fn.a = 100; // 要點二:__proto__ console.log(obj.__proto__); console.log(arr.__proto__); console.log(fn.__proto__); // 要點三:函數有 prototype console.log(fn.prototype) // 要點四:引用類型的 __proto__ 屬性值指向它的構造函數的 prototype 屬性值 console.log(obj.__proto__ === Object.prototype)...
// 構造函數 function Foo(name, age) { this.name = name } Foo.prototype.alertName = function () { alert(this.name) } // 建立示例 var f = new Foo('zhangsan') f.printName = function () { console.log(this.name) } // 測試 f.printName() f.alertName()...
執行printName時很好理解,可是執行alertName時發生了什麼?這裏再記住一個重點 當試圖獲得一個對象的某個屬性時,若是這個對象自己沒有這個屬性,那麼會去它的__proto__(即它的構造函數的prototype)中尋找,所以f.alertName就會找到Foo.prototype.alertName。...
那麼如何判斷這個屬性是否是對象自己的屬性呢?使用hasOwnProperty,經常使用的地方是遍歷一個對象的時候。
var item for (item in f) { // 高級瀏覽器已經在 for in 中屏蔽了來自原型的屬性,可是這裏建議你們仍是加上這個判斷,保證程序的健壯性 if (f.hasOwnProperty(item)) { console.log(item) } }...
仍是接着上面的示例,若是執行f.toString()時,又發生了什麼?
// 測試 f.printName() f.alertName() f.toString()
由於f
自己沒有toString()
,而且f.__proto__
(即Foo.prototype
)中也沒有toString
。這個問題仍是得拿出剛纔那句話——當試圖獲得一個對象的某個屬性時,若是這個對象自己沒有這個屬性,那麼會去它的__proto__
(即它的構造函數的prototype
)中尋找。
若是在f.__proto__
中沒有找到toString
,那麼就繼續去f.__proto__.__proto__
中尋找,由於f.__proto__
就是一個普通的對象而已嘛!...
f.__proto__
即Foo.prototype
,沒有找到toString
,繼續往上找f.__proto__.__proto__
即Foo.prototype.__proto__
。Foo.prototype
就是一個普通的對象,所以Foo.prototype.__proto__
就是Object.prototype
,在這裏能夠找到toString...
f.toString
最終對應到了Object.prototype.toString
這樣一直往上找,你會發現是一個鏈式的結構,因此叫作「原型鏈」。若是一直找到最上層都沒有找到,那麼就宣告失敗,返回undefined。最上層是什麼 —— Object.prototype.__proto__ === null
全部從原型或更高級原型中獲得、執行的方法,其中的this
在執行時,就指向了當前這個觸發事件執行的對象。所以printName
和alertName
中的this
都是f
。