繼承就是讓一個對象擁有另外一個對象的屬性和方法app
一、Son.prototype = Father.prototype (原型繼承)函數
(1)Son的實例對象只能繼承Father實例中原型的方法,沒法繼承Father自己的屬性。this
function Father(){ this.age = 50; this.h = 15 } Father.prototype.eat = function(){ console.log(this.age); // 25 console.log(this.h); // undefined } function Son(){ this.age = 25; } Son.prototype = Father.prototype; var son = new Son() son.eat() // son繼承Father原型中的eat函數,因此this.age指向Son,故 25 // this.h 彈出undefined 說明沒法繼承Father自己的屬性
二、Son.prototype = new Father() (實例化對象繼承)spa
原理:就是把構造函數Father()的實例化對象father的屬性和方法繼承到構造函數Son()的原型上。修改的屬性是實例化對象father的屬性,每次實例化一個構造函數Son(),都是從father上繼承,故屬性相通。prototype
(1)優先查找自身屬性,若是有的話優先使用,若是沒有則從繼承中查找code
(2)繼承的構造函數的不一樣實例化對象的屬性不會互相影響;不一樣的Son實例對象會共享繼承Father的實例化對象father的屬性。這樣的話修改一個Son實例化對象son的arr,Son實例化對象son1的arr也會改變,修改被繼承Fathe實例化對象father的屬性時會影響繼承者Son繼承的屬性對象
function Father(){ this.age = 50; this.arr = [1,2,3] this.h = 15; } Father.prototype.eat = function(){ console.log(this.age); console.log(this.h); } function Son(){ this.age = 25; } var father = new Father(); Son.prototype = father; var son = new Son(); son.eat(); // 25 說明當son優先查找自身屬性 // 15 說明son繼承Father實例對象的屬性 son.arr.push(4) console.log(son.arr); // [1,2,3,4] console.log(father.arr) // [1,2,3] var son1 = new Son() console.log(son1.arr);// [1,2,3,4] 說明不一樣的Son實例對象會共享繼承Father的實例化對象father的屬性 father.arr.push(5) console.log(father.arr)// [1,2,3,5] console.log(son.arr);// [1,2,3,4,5] 說明修改被繼承Fathe實例化對象father的屬性時會影響繼承者Son繼承的屬性
對於繼承後 Son.prototype.constructor指向的問題,是否須要修改能夠查看 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/constructorblog
在繼承構造函數裏經過call或者apply或bind修改被繼承函數的this。繼承
一、繼承屬性會覆蓋自身屬性,ip
二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響
三、沒法繼承原型上的方法,
function Father(){ this.age = 50; this.hello = "你好"; this.arr = [1,2,3]; } Father.prototype.cat = function(){ console.log(cat); } function Son(){ // 三種方式 this.age = 25; Father.call(this); // Father.bind(this)(); // Father.apply(this); } var son = new Son(15) console.log(son.age); // 50 // 說明繼承屬性會覆蓋自身屬性 console.log(son.hello); // 你好 try{ son.cat() }catch(e){ console.log(e); // TypeError: son.cat is not a function } son.arr.push(4); console.log(son.arr); // [1,2,3,4] var son1 = new Son(25); console.log(son1.arr); // [1,2,3] // 這說明構造函數Son的不一樣實例化對象的屬性是不相通,修改實例化對象
在原型鏈繼承中Son.prototype = Father.prototype只能繼承Fanther的原型上的方法,在構造函數繼承中,Fathe.call(this)只能繼承構造函數的屬性,二者結合。
一、繼承屬性會覆蓋自身屬性
二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響
function Father(){ this.age = 50; this.hello = "你好"; this.arr = [1,2,3]; }; Father.prototype.eat=function(){ console.log("這是Father構造函數原型上方法"); } function Son(){ this.age = 25; Father.call(this) }; Son.prototype = Father.prototype; var son = new Son(); console.log(son.age); // 50 說明繼承的屬性會覆蓋自身的屬性 console.log(son.hello); //你好 son.arr.push(4) son.eat() var son1 = new Son(); console.log(son.arr); //[1,2,3,4] console.log(son1.arr); // [1,2,3] // 說明同一構造函數的不一樣實例化對象之間屬性不相通;
弊端:經過Father.call() 和Father.prototype ,父類構造函數Father被調用了兩次。繼承屬性會覆蓋原屬性
一、優先查找自身屬性,若是有的話優先使用,若是沒有則從繼承中查找
二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響;
function Father(){ this.age = 50; this.hello = "你好"; this.arr = [1,2,3] }; Father.prototype.eat = function(){ console.log("這是Father原型上的方法"); } function content(obj){ function Son(){ this.age = 25; }; Son.prototype = obj; // 傳入繼承構造函數Father的實例化對象father return new Son(); } var father = new Father(); var son = content(father); console.log(son.hello); //你好 說明繼承構造函數Father實例化對象father上的屬性。 console.log(son.age); // 25 // 說明優先查找自身是否有某屬性,有的話優先調用自身屬性 son.eat() // 這是Father原型上的方法 說明繼承了構造函數Father實例化對象father上的方法 son.arr.push(4) var son1 = content(father) console.log(son.arr); // [1,2,3,4] console.log(son1.arr); // [1,2,3,4] 說明這個不一樣實例間繼承的屬性是相通的
一、優先查找自身屬性,若是有的話優先使用,若是沒有則從繼承中查找
二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響;
function Father(){ this.age = 50; this.hello = "你好"; this.arr = [1,2,4]; }; Father.prototype.eat = function(){ console.log("這是Father構造函數原型上的方法"); } function content(obj){ function Son(){ this.age = 25; }; Son.prototype = obj; return new Son(); } function subObject(obj){ var son = content(obj) son.name = 'son 名字' // 可直接對son添加屬性 return son } var father = new Father() var son1 = subObject(father) console.log(son1.age);//25 console.log(son1.hello);//你好 console.log(son1.name); // son 名字 son1.eat(); // 這是構造函數原型上的方法 son1.arr.push(4) var son2 = content(father) console.log(son1.arr); // [1,2,3,4] console.log(son2.arr); // [1,2,3,4] 說明這個不一樣實例間繼承的屬性是相通的
一、寄生屬性會覆蓋原屬性
二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響
三、與組合式繼承相比效果相同,可是更加複雜。
function Father(){ this.age = 50; this.hello = "你好"; this.arr = [1,2,3]; }; function content(obj){ function Son(){ this.age = 25; }; Son.prototype = obj; return new Son(); }; var son = content(Father.prototype) // var son = content(new Father()) 效果一致 function Sub(){ Father.call(this); // Father.apple(this); // Father.bind(this)(); }; Sub.prototype = son; son.constructor = Sub; var sub = new Sub(); console.log(sub.age); // 50 說明繼承的屬性會覆蓋自身的屬性 console.log(sub.hello); // 你好 sub.arr.push(4) console.log(sub.arr); // [1,2,3,4] var sub1 = new Sub(); console.log(sub1.arr); // [1,2,3] // 說明同一構造函數的不一樣實例化對象之間屬性不相通;
與組合式繼承基本相同,除了Son.prototype = Object.create(Father.prototype),對原型繼承的方式不同
一、寄生屬性會覆蓋原屬性
二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響
// Father - 父類(superclass) function Father() { this.age = 50; this.arr = [1,2,3] } // 父類的方法 Father.prototype.move = function(x, y) { console.info('Father moved.'); }; // Son - 子類(subclass) function Son() { this.age = 25; Father.call(this); // call super constructor. } // 子類續承父類 Son.prototype = Object.create(Father.prototype); // Son.prototype.constructor = Son; var son = new Son(); console.log(son.age); // 50 說明繼承屬性覆蓋原屬性 son.move(); // Father moved son.arr.push(4) console.log(son.arr); // [1,2,3,4] var son1 = new Son(); console.log(son1.arr); // [1,2,3] // 說明不一樣實例之間數據不相通,可複用