原型和原型鏈
示例
- 如何準確判斷一個變量是數組類型
- 寫一個原型鏈繼承的例子
- 描述 new 一個對象的過程
- zepto(或其他框架)源碼中如何使用原型鏈
知識點
構造函數{#t1}
function Foo (name, age) {
this.name = name
this.age = age
this.class = 'class-1'
// return this // 默認有這一行
}
var f = new Foo('zhangsan', 20) // new的時候,this變成一個空對象
// var f1 = new Foo('lisi', 21) // 創建多個對象
構造函數的擴展{#t2}
所有引用類型都有構造函數
-
var a = {}
是var a = new Object()
的語法糖 -
var a = []
是var a = new Array()
的語法糖 -
function Foo(){...}
是var Foo = new Function(...)
的語法糖 - 使用instanceof判斷一個函數是否是一個變量的構造函數
arr instanceof Array
原型鏈規則和示例
原型規則是原型鏈的基礎
- 所有的引用類型(數組、對象、函數),都具有對象特性,即可以自由擴展屬性(除了
null
以外)
var obj = {}
obj.a = 100
var arr = []
arr.a = 100
function fn() {...}
fn.a = 100
- 所有的引用類型(數組、對象、函數,
null
除外),都有__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)
- 當試圖得到一個引用類型(對象、數組、函數)的某個屬性時,如果這個引用類型(對象、數組、函數)本身沒有這個屬性,那會去其
__proto__
(其構造函數的prototype
中尋找
自身的屬性
var item
for( item in f) {
// 高級瀏覽器已經在for in中屏蔽了來自原型的屬性
// 實際還是建議加上判斷,保證程序的健壯性
if(f.hasOwnProperty(item)){
console.log(item)
}
}
原型鏈
// 構造函數
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()
f.toString() // 要從f.__proto__.__proto__ 中查找
微信圖片_20171226160104.png
instanceof
用于判斷引用類型對象屬于哪個構造函數的方法
f instanceof Foo 的判斷邏輯是:
f 的__proto__
一層一層往上,能夠對應到Foo.prototype
f instanceof Object也是f 的__proto__
一層一層往上,能夠對應到Object.prototype
實例
- 寫一個原型鏈繼承的例子
// 動物示例
function Animal () {
this.eat = function () {
console.log('Animal eat')
}
}
// 狗
function Dog () {
this.bark = function () {
console.log('Dog bark')
}
}
Dog.prototype = new Animal()
// 哈士奇
var hashiqi = new Dog()
hashiqi.bark()
hashiqi.eat()
// DOM 封裝 的原型示例
function Elem (id) {
this.elem = document.getElementById(id)
}
Elem.prototype.html = function (val) {
var elem = this.elem
if (val) {
elem.innerHTML = val
return this // 鏈式操作
} else {
return elem.innerHTML
}
}
Elem.prototype.on = function (type, fn) {
var elem = this.elem
elem.addEventListener(type, fn)
return this
}
var div1 = new Elem('id')
div1.html('<p>Javascript start</p>').on('click', function () {
alert('click')
}).html('<p>Javascript end</p>')
- 描述new 一個對象的過程
// 構造函數
function Foo (name, age) {
this.name = name
this.age = age
this.class = 'class-1'
// return this // 默認有這一行
}
var f = new Foo('zhangsan', 20) // new的時候,this變成一個空對象
- 創建一個新對象
- this指向這個新對象
- 執行代碼,即對this賦值
- 返回this