1昙楚、理解Object和Function
Object和Function都是引用類型,是一種數(shù)據(jù)結(jié)構(gòu)诈嘿,封裝數(shù)據(jù)和功能堪旧,常常被稱為類。
Object類型
既然是類奖亚,就可以用來創(chuàng)建對象淳梦,如 var person = new Object();
此外,JS中還提供另一個創(chuàng)建對象的方式:對象字面量昔字,如 var persion = {};
上面兩種方式的等價的爆袍。
Function類型
Function是類首繁,它的對象是什么呢?其實就是我們常用的函數(shù)陨囊。沒錯弦疮,JS中的函數(shù)是對象,是Function類型的實例蜘醋。如:
function sum(num1,num2){
return num1+num2
};
此外胁塞,JS還提供使用函數(shù)表達式定義函數(shù)的方式,如:
var sum = function(num1,num2){
return num1+num2;
};
- 函數(shù)的內(nèi)部屬性:
在函數(shù)內(nèi)部压语,有兩個特殊的對象:arguments和this啸罢,arguments是一個類數(shù)組對象,包含傳入函數(shù)中的所有參數(shù)胎食。這個對象還有有一個名叫callee的屬性扰才。該屬性是一個指針,指向擁有這個arguments對象的函數(shù)厕怜。
ECMAScript5規(guī)范化了另一個函數(shù)對象的屬性:caller衩匣,它保存著調(diào)用當前函數(shù)的函數(shù)的引用。
- 函數(shù)屬性和方法:
每個函數(shù)都包含兩個屬性:length和prototype酣倾;length表示接受參數(shù)的個數(shù)舵揭;prototype保存函數(shù)類型的所有實例方法,相當與類方法躁锡,在自定義類型和實現(xiàn)繼承時要特別注意午绳。
每個函數(shù)還包含兩個非繼承而來的方法:apply()和call(),它們的區(qū)別在于接受參數(shù)的方式不同映之。這兩個方法能擴充函數(shù)的作用域拦焚,使對象和方法解耦合。
2杠输、理解原型對象
只要創(chuàng)建一個新函數(shù)赎败,就會為該函數(shù)創(chuàng)建一個prototype屬性,該屬性指向函數(shù)的原型對象蠢甲。下面通過實例代碼和圖說明僵刮。
首先通過構(gòu)造函數(shù)和原型創(chuàng)建實例,代碼如下:
function Person(){}
Person.prototype.name = 'xiaoming';
Person.prototype.sayName = function(name){alert(this.name)}
var p1 = new Person();
p1.sayName();// xiaoming
var p2 = new Person();
p2.sayName();// xiaoming
構(gòu)造函數(shù)鹦牛、原型對象即通過構(gòu)造函數(shù)創(chuàng)建的實例對象之間的關(guān)系如下圖所示:
3搞糕、理解原型鏈和繼承
JS將原型鏈作為實現(xiàn)繼承的主要方法,基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法曼追。
原型鏈實現(xiàn)有一種基本模式窍仰,代碼如下:
function Parent(){
this.property = true;
}
Parent.prototype.getParentValue = function(){
return this.property;
}
function Child(){
this.subproperty = false;
}
//子類繼承父類
Child.prototype = new Parent();
Child.prototype.getSubValue = function(){
return this.subproperty;
}
var instance = new Child()
console.log(instance.getSubValue);
構(gòu)造函數(shù)、原型對象即通過構(gòu)造函數(shù)創(chuàng)建的實例對象之間的關(guān)系如下圖所示:
這種模式實現(xiàn)繼承有有個最大問題在于包含引用類型的原型礼殊,這可以通過組合繼承解決驹吮,也就是組合原型鏈和構(gòu)造函數(shù)针史,這種方式是JS中最常用的繼承模式。背后的思路是使用原型鏈實現(xiàn)對原型屬性和方法的繼承碟狞,而通過借用構(gòu)造函數(shù)的方式實現(xiàn)對實例屬性的繼承啄枕。
實例如下:
function Parent(){
this.name = name;
this.colors = ['red','blue','green']
}
Parent.prototype.sayName= function(){
return this.name;
}
function Child(){
//繼承屬性
Parent.call(this,name);
this.age = age;
}
//繼承方法
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.sayAge= function(){
return this.age;
}
var instance = new Child('xiaoming','28')
instance.colors.push("black");
consloe.log(instance.colors);// ['red','blue','green','black']
instance.sayName();//xiaoming
instance.sayAge();//28
var instance2 = new Child('xiaoli',30)
consloe.log(instance2.colors);//['red','blue','green']
instance2.sayName();//xiaoli
instance2.sayAge();//30
組合繼承還是有個小問題,那就是多次調(diào)用超類型構(gòu)造函數(shù)而導致的低效率問題篷就。從而引出實現(xiàn)繼承最有效的方式--寄生組合式繼承
實例如下:
//借助原型基于已有對象創(chuàng)建對象
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritProtype(Parent,Child){
var prototype = object(Parent.prototype);//創(chuàng)建對象
prototype.constructor = Child;//增強對象
Child.prototype = prototype;//指定對象
}
function Parent(){
this.name = name;
this.colors = ['red','blue','green']
}
Parent.prototype.sayName= function(){
return this.name;
}
function Child(){
//繼承屬性
Parent.call(this,name);
this.age = age;
}
inheritProtype(Parent,Child);
Child.prototype.sayAge = function(){
return this.age
}
參考:JavaScript高級程序設計(第三版)