構(gòu)造函數(shù)的封裝與繼承
封裝
就是將屬性和方法封裝成一個對象:構(gòu)造函數(shù)模式。就是一個內(nèi)部使用了this的普通函數(shù),對構(gòu)造函數(shù)使用new就能生成實例,this會綁定在對象實例上。
function Cat(name,color){
this.name=name;
this.color=color;
}
//生成實例對象
var cat1=new Cat('aa','red');
//自動含有constructor屬性,指向其構(gòu)造函數(shù)
cat1.constructor==Cat
//instanceof 運算符,驗證原型對象與實例對象之間的關(guān)系
cat1 instanceof Cat//true
構(gòu)造函數(shù)主要是為了解決生成多實例時,減少代碼冗余。但是對于不變的屬性和方法,都指向不同的內(nèi)存地址,浪費資源。
每個構(gòu)造函數(shù)都有一個prototype屬性,指向另一個對象,這個對象的所有屬性和方法都會被構(gòu)造函數(shù)的實例繼承。
function Cat(name,color){
this.name=name;
this.color=color;
}
Cat.prototype={
type:"貓科",
eat:function(){
console.log("eating");
}
}
//生成實例對象
var cat1=new Cat('aa','red');
cat1.eat()
var cat2=new Cat('bb','blue');
所有實例從prototype繼承的方法指向同一個內(nèi)存地址
cat2.eat==cat1.eat //true
//驗證構(gòu)造函數(shù)的prototype對象和實例的關(guān)系
Cat.prototype.isPrototypeOf(cat1)
//查看該屬性為自身還是繼承
cat1.hasOwnProperty('name')
繼承
function Animal(){
this.species="動物";
}
function Cat(name,color){
this.name=name;
this.color=color;
}
如何使貓繼承動物?
1、 將父對象的構(gòu)造函數(shù)綁定在子對象上
function Cat(name,color){
Animal.apply(this,arguments);
this.name=name;
this.color=color;
}
var cat1=new Cat("aa","red");
cat1.species
2、 prototype模式
function Animal(){
this.species="動物";
}
Animal.prototype={
eat:function(){
console.log('eating');
}
}
function Cat(name,color){
this.name=name;
this.color=color;
}
//將prototype對象指向父類的實例
Cat.prototype=new Animal()
//為了使Cat的實例在原型鏈上不混亂
Cat.prototype.constructor=Cat
Cat.prototype.drink=function(){
console.log('drinking');
}
var cat1=new Cat("aa","red");
因為不變的屬性都可以寫入prototype中,所以可以跳過Animal(),直接繼承Animal.prototype。
//將prototype對象指向父類的prototype
Cat.prototype=Animal.prototype
//為了使Cat的實例在原型鏈上不混亂,但是也將Animal的prototype修改為了Cat
Cat.prototype.constructor=Cat
效率更高,不用和Animal的實例建立聯(lián)系,但是兩個portotype指向了了同一個對象,修改會互相影響。所以利用一個空對象作為中介。
因為空對象幾乎不占內(nèi)存,所以利用nullObj.prototype=Parent.prototype,繼承了所有的共享屬性和方法,然后Child.prototype=new nullObj();
var F=function(){}
F.prototype=Animal.prototype;
Cat.prototype=new F();
Cat.prototype.constructor=Cat
封裝成方法:
function extend(Child,Parent){
var F=function(){};
F.prototype=Parent.prototype;
Child.prototype=new F();
Child.prototype.constructor=Child;
}
使用:
extend(Cat,Animal);
Cat.prototype.drink=function(){
console.log('drinking');
}
var cat1=new Cat("aa","red");
cat1.eat();
cat1.drink();
非構(gòu)造函數(shù)的繼承
非構(gòu)造函數(shù)與構(gòu)造函數(shù)的區(qū)別:
- 不用new方法
- 內(nèi)部不建議用this
- 可以return
構(gòu)造函數(shù)有prototype方法實現(xiàn)繼承,非構(gòu)造函數(shù)就是兩個普通函數(shù),如何繼承?
- 使用prototype鏈
var Chinese={
country:'China'
}
function object(o){
function F(){}
F.prototype=o;
return new F();
}
Doctor=object(Chinese);
Doctor.career="doctor";
Doctor.country==='China'//true
- 淺拷貝
function extendCopy(p){
var c={}
for(var i in p){
c[i]=p[i];
}
return c;
}
var Doctor=extendCopy(Chinese);
Doctor.career='doctor';
基本數(shù)據(jù)類型是參數(shù)傳值,對象/數(shù)組是引用傳值,所以淺拷貝有可能改變父對象內(nèi)容。
- 深拷貝
function deepCopy(o,c){
var c=c||{};
for(var i in o){
//如果是引用數(shù)據(jù)類型
if (typeof o[i] ==="object") {
if (o[i] instanceof Array) {
o[i]=[]
}else{
o[i]={}
}
deepCopy(o[i],c[i]);
}else{
c[i]=o[i];
}
}
}
如何判斷數(shù)據(jù)類型
基本數(shù)據(jù)類型:String Number Boolean
特殊類型: undefined null
引用類型: Object,Function,Array,Date,RegExp
typeof
基本數(shù)據(jù)類型OK,
特殊類型中 typeof undefined //undifined
引用類型中 typeof function(){} //function
其它都是 object
jquery中判斷數(shù)據(jù)類型的方式:利用toString()方法。
每個對象都有一個toString()方法,當(dāng)對象被表示為文本值或者當(dāng)以期望字符串的形式引用對象時,該方法被自動調(diào)用。默認(rèn)情況下,toString()方法被每個繼承自O(shè)bject的對象繼承。如果此方法在自定義對象中未被覆蓋,toString()返回"[object type]",其中type是對象類型。
var class2type={};
"Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(function(e,i){
class2type["[object "+e+"]"]=e.toLowerCase();
});
function _typeof(obj){
if (obj==null || undefined) {
return String(obj);
}
return typeof obj===("object"|| "function")?
//使用原型Object的toString()方法,避免在自定義對象中此方法被覆蓋
class2type[Object.prototype.toString.call(obj)]:
typeof obj;
}