聊一聊Javasript繼承

  前先後後已經快寫了2年左右javaScript,剛開始只是簡單用於一些表單驗證和操做dom節點,並無深刻的使用,隨着漸漸的深刻,開始不想去寫重複的代碼(懶的開始),從而寫簡單的繼承,封裝,抽象等等,最終效果寫重複代碼少、可用性高(主要:迭代快、代碼能夠持續使用,加班也少)java

Demo構造函數聲明類

function Person(name){
    this.name = name;
}複製代碼
new生成實例

new生成實例的缺點:沒法共享屬性和方法,每次new新的實例會開闢新的內存空間,形成極大的資源浪費。bash

var personA = new Person('小明');
console.log(personA.name);複製代碼

構造函數的this指向新的實例
如:app

function Person(name){
    this.name = name;
    this.sex = '女'
}

var personA = new Person('小明');
var personB = new Person('小妞');
personA.sex = '男';
console.log(personB.sex);  //女複製代碼

在這裏咱們該採用聲明解決方案呢?設計者很好的解決了這個問題,那麼就是prototype屬性(包含對象)的引入dom

prototype屬性

它的好處是,實例一旦建立,將自動共同持有共享屬性和方法,如:函數

function Person(name){
    this.name = name;
}
Person.prototype.sex = '女';
var personA = new Person('小明');
var personB = new Person('小妞');
console.log(personA.sex);  //女
console.log(personB.sex);  //女

//證實它們是共享的
Person.prototype.sex = '男';
console.log(personA.sex);  //男
console.log(personB.sex);  //男複製代碼

也許在這裏你看不出prototype的好處,可是當你有不少方法和屬性時,你的運行效率還高嘛?那麼:ui

function Person(name, sex){
    this.name = name;
    this.sex = sex,
    this.country = '中國',
    this.show = function(){
        console.log(this.name + '的國籍是:'+this.country+',性別:'+this.sex);
    }
}
var personA = new Person('小明'.'男');
personA.show();   //小明的國籍是是中國,性別:男
var personB = new Person('小妞','女');
personB.show();  //小妞的國籍是是中國,性別:女複製代碼

感受彷佛沒有什麼問題,可是personA和personB都包含有country、show屬性方法如出一轍的內容,這樣就形成了空間的浪費,效率也下降了,那麼咱們能夠它們共享屬性和方法this

function Person(name, sex){
    this.name = name;
    this.sex = sex,
}

Person.prototype.country = '中國';
Person.prototype.show = function(){
    console.log(this.name + '的國籍是:'+this.country+',性別:'+this.sex);
}

var personA = new Person('小明'.'男');
var personB = new Person('小妞','女');
personA.show();   //小明的國籍是是中國,性別:男
personB.show();  //小妞的國籍是是中國,性別:女複製代碼

配合protorype使用的屬性--isPrototypeOf(),hasOwnPrototype(),inspa

function Person(name, sex){
    this.name = name;
    this.sex = sex,
}

Person.prototype.country = '中國';
Person.prototype.show = function(){
    console.log(this.name + '的國籍是:'+this.country+',性別:'+this.sex);
}

//isPrototypeOf() 判斷實例和對象之間的關係
console.log(Person.prototype.isPrototype(personA))  //true
console.log(Person.prototype.isPrototype(personB))  //true

//hasOwnPrototype() 判斷屬性是本地屬性,仍是繼承自prototype屬性
console.log(personA.hasOwnPrototy('name'))  //true
console.log(personA.hasOwnPrototy('country'))  //false

//in 判斷是否含有屬性,無論本地仍是繼承prototype
console.log('name' in personA)  //true
console.log('country' in personA)  //true複製代碼

constructor屬性

繼續使用前面Person原型對象prototype

function Person(name){
    this.name = name;
}
Person.prototype.sex = '女';
var personA = new Person('小明');
var personB = new Person('小妞');
//新增的實例自動包含有constructor屬性
console.log(personA.constructor == Person);  //true
console.log(personB.constructor == Person);  //true複製代碼

這裏也能夠使用instanceof判斷實例和原型對象之間的關係設計

console.log(personA instanceof Person);  //true
console.log(personB instanceof Person);  //true複製代碼

經常使用Object之間「繼承」(構造函數繼承)(5種)

假設如今有Person和Teacher兩個Object,想讓Teacher繼承Person

//Person對象
function Person(name){
    this.name = name;
}

//Teacher對象
function Teacher(age,sex){
    this.age = age;
    this.sex = sex;
}複製代碼
一、:利用構造函數綁定(call或者apply)
function Teacher(age,sex,name){
    Person.apply(this,name);//Person.call(this,name);
    this.age = age;
    this.sex =sex;
}複製代碼
二、:使用prototype,也就是咱們前面說prototype屬性,修改constructor指向
Teacher.prototype = new Person('xiaoming'); //修改prototy對象原先的值
Teacher.prototype.constructor = Teacher;
var teacher1 = new Teacher(19,'女');複製代碼
三、:直接繼承prototype
function Person(){}
person.prototype.name = "xiaoming";

function Teacher(age,sex){
    this.age = age;
    this.sex = sex;
}

//Teacher的prototype對象直接指向Person的prototype對象
Teacher.prototype = Person.prototype;
Teacher.prototype.constructor = Teacher
var teacher1 = new Teacher(19,"女");複製代碼
四、中介new function(){}空對象
var Fn = new function(){};
Fn.prototype = Person.prototype;
Teacher.prototype = new Fn();
Teacher.prototype.constructor = Teacher;

//擴展封裝
function Extend(ChildObj,ParentObj){
    var Fn = new function(){};
    Fn.prototype = ParentObj.prototype;
    ChildObj.prototype = new Fn();
    ChildObj.prototype.constructor = ChildObj;
    ChildObj.uber = ParentObj.prototype;  //直接指向父對象prototype屬性
}

//Teacher繼承Person
Extend(Teacher,Person);
var teacher1 = new Teacher(19,'女');複製代碼
五、拷貝繼承(徹底)
function Extend(ChildObj, ParentObj) {
    var p = ParentObj.prototype;
    var c = ChildObj.prototype;
    for (var i in p) { 
        c[i] = p[i];
  }
  c.uber = p;
} 
//Teacher繼承Person
Extend(Teacher,Person);
var teacher1 = new Teacher(19,'女');複製代碼

非構造函數「繼承」(3種)

//原始
var Person = {
    name: '小明'
}
var Teacher ={
    age:19,
    sex:'女'
}複製代碼

這裏咱們如何可讓Teacher繼承Person

一、:object方法
function object(obj){
    function Fn(){}
    Fn.prototype = obj;
    return new Fn();
}
var teacher1 = object(Person);
teacher1.age = 19;
teacher1.sex = '女';複製代碼
二、:淺拷貝方法
function extendCopy(ParentObj){
    var c = {};
    for(var i in ParentObj){
        c[i] = p[i];
    }
    c.uber = p;
    return c;
}
//使用extendCopy
var teacher1 =  extendCopy(Person);
teacher1.age = 19;
teacher1.sex = '女';複製代碼
三、:深拷貝方法
function extendDeepCopy(ParentObj,ChildObj){
    var ChildObj = ChildObj || {};
    for(var i in ParentObj){
        if(typeof  ParentObj[i] === 'object'){
            c[i] = (ParentObj[i].constructor === Array) ? [] : {};
            extendDeepCopy(ChildObj[i],ParentObj[i]);
        }else{
            ChildObj[i] = ParentObj[i];
        }
    }
    return ChildObj;
}

//使用
var teacher1 = extendDeepCopy(Person1);
teacher1.age = 19;
teacher1.sex = '女';複製代碼

本文版權歸做者共有,歡迎轉載,須保留此段聲明,並給出原文連接,謝謝!

相關文章
相關標籤/搜索