JS中的封裝與繼承

構(gòu)造函數(shù)的封裝與繼承

封裝

就是將屬性和方法封裝成一個(gè)對(duì)象:構(gòu)造函數(shù)模式。就是一個(gè)內(nèi)部使用了this的普通函數(shù),對(duì)構(gòu)造函數(shù)使用new就能生成實(shí)例,this會(huì)綁定在對(duì)象實(shí)例上。

function Cat(name,color){
    this.name=name;
    this.color=color;
}
//生成實(shí)例對(duì)象
var cat1=new Cat('aa','red');

//自動(dòng)含有constructor屬性,指向其構(gòu)造函數(shù)
cat1.constructor==Cat

//instanceof 運(yùn)算符,驗(yàn)證原型對(duì)象與實(shí)例對(duì)象之間的關(guān)系
cat1 instanceof Cat//true

構(gòu)造函數(shù)主要是為了解決生成多實(shí)例時(shí),減少代碼冗余。但是對(duì)于不變的屬性和方法,都指向不同的內(nèi)存地址,浪費(fèi)資源。

每個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性,指向另一個(gè)對(duì)象,這個(gè)對(duì)象的所有屬性和方法都會(huì)被構(gòu)造函數(shù)的實(shí)例繼承。

function Cat(name,color){
    this.name=name;
    this.color=color;
}

Cat.prototype={
    type:"貓科",
    eat:function(){
        console.log("eating");
    }
}
//生成實(shí)例對(duì)象
var cat1=new Cat('aa','red');
cat1.eat()
var cat2=new Cat('bb','blue');
所有實(shí)例從prototype繼承的方法指向同一個(gè)內(nèi)存地址
cat2.eat==cat1.eat  //true

//驗(yàn)證構(gòu)造函數(shù)的prototype對(duì)象和實(shí)例的關(guān)系
Cat.prototype.isPrototypeOf(cat1) 

//查看該屬性為自身還是繼承
cat1.hasOwnProperty('name')

繼承

function Animal(){
    this.species="動(dòng)物";
}

function Cat(name,color){
    this.name=name;
    this.color=color;
}

如何使貓繼承動(dòng)物?

1、 將父對(duì)象的構(gòu)造函數(shù)綁定在子對(duì)象上

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="動(dòng)物";
}
Animal.prototype={
    eat:function(){
        console.log('eating');
    }
}

function Cat(name,color){
    this.name=name;
    this.color=color;
}
//將prototype對(duì)象指向父類(lèi)的實(shí)例
Cat.prototype=new Animal()
//為了使Cat的實(shí)例在原型鏈上不混亂
Cat.prototype.constructor=Cat

Cat.prototype.drink=function(){
    console.log('drinking');
}

var cat1=new Cat("aa","red");

因?yàn)椴蛔兊膶傩远伎梢詫?xiě)入prototype中,所以可以跳過(guò)Animal(),直接繼承Animal.prototype。

//將prototype對(duì)象指向父類(lèi)的prototype
Cat.prototype=Animal.prototype
//為了使Cat的實(shí)例在原型鏈上不混亂,但是也將Animal的prototype修改為了Cat
Cat.prototype.constructor=Cat

效率更高,不用和Animal的實(shí)例建立聯(lián)系,但是兩個(gè)portotype指向了了同一個(gè)對(duì)象,修改會(huì)互相影響。所以利用一個(gè)空對(duì)象作為中介。

因?yàn)榭諏?duì)象幾乎不占內(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方法實(shí)現(xiàn)繼承,非構(gòu)造函數(shù)就是兩個(gè)普通函數(shù),如何繼承?

  1. 使用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
  1. 淺拷貝
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ù)類(lèi)型是參數(shù)傳值,對(duì)象/數(shù)組是引用傳值,所以淺拷貝有可能改變父對(duì)象內(nèi)容。

  1. 深拷貝
function deepCopy(o,c){
    var c=c||{};
    for(var i in o){
        //如果是引用數(shù)據(jù)類(lèi)型
        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ù)類(lèi)型

基本數(shù)據(jù)類(lèi)型:String Number Boolean
特殊類(lèi)型: undefined null
引用類(lèi)型: Object,Function,Array,Date,RegExp

typeof
基本數(shù)據(jù)類(lèi)型OK,
特殊類(lèi)型中 typeof undefined //undifined
引用類(lèi)型中 typeof function(){} //function
其它都是 object

jquery中判斷數(shù)據(jù)類(lèi)型的方式:利用toString()方法。

每個(gè)對(duì)象都有一個(gè)toString()方法,當(dāng)對(duì)象被表示為文本值或者當(dāng)以期望字符串的形式引用對(duì)象時(shí),該方法被自動(dòng)調(diào)用。默認(rèn)情況下,toString()方法被每個(gè)繼承自O(shè)bject的對(duì)象繼承。如果此方法在自定義對(duì)象中未被覆蓋,toString()返回"[object type]",其中type是對(duì)象類(lèi)型。

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()方法,避免在自定義對(duì)象中此方法被覆蓋
        class2type[Object.prototype.toString.call(obj)]:
        typeof obj;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容