注:在繼承以前咱們須要瞭解一下構造函數和原型鏈的相關知識,下面我經過例子來講明一下編程
/* * 所謂的構造函數,顧明思議就是函數,但其與普通函數也有不一樣 * 1.構造函數是經過 new 關鍵字建立對象時調用的函數 * 2.一般構造函數咱們會將函數名字的首字母大寫 */
function Animal(name){
this.name = name; // 實例上的屬性
this.ability = ['吃飯', '睡覺', '打豆豆']; // 實例上的屬性
this.eat = function(){ // 實例上的方法
console.log('吃')
}
}
Animal.prototype.address = {location: '大山'}; // 原型上的屬性(公有屬性)
let animal1 = new Animal('老虎');
console.log(animal1) // Animal { name: '老虎', ability: [ '吃飯', '睡覺', '打豆豆' ], eat: [Function] }
let animal2 = new Animal('貓');
console.log(animal2) // Animal { name: '貓', ability: [ '吃飯', '睡覺', '打豆豆' ], eat: [Function] }
console.log(animal1.ability === animal2.ability); // false
console.log(animal1.address === animal2.address); // true
console.log(animal1.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.constructor === Animal); // true
console.log(Animal.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
/* * 一句話總結原型鏈:每個實例都有一個__proto__屬性,指向該實例所屬類的原型(prototype)【須要注意的是原型是Object的實例哦】;每個類的原型上都有一個constructor屬性指向類的自己 */
複製代碼
JS
中我總結了爲有三種繼承場景
function Animal(name){ // 父類
this.name = name;
this.eat = '吃肉'
}
Animal.prototype.address = {location: '大山'};
function Tiger(name){
Animal.call(this);
this.name = name;
this.age = 5;
}
Tiger.prototype.say = function(){ // 子類
console.log('說話')
}
let tiger = new Tiger('老虎')
console.log(tiger) // Tiger { name: '老虎', eat: '吃肉', age: 10 }
console.log(tiger.say) // [Function]
console.log(tiger.address) // undefined
複製代碼
function Animal(name){ // 父類
this.name = name;
this.eat = '吃肉';
}
Animal.prototype.address = {location: '大山'};
function Tiger(name){ // 子類
this.name = name;
this.age = 5;
}
Tiger.prototype.say = function(){
console.log('說話');
}
Tiger.prototype.__proto__ = Animal.prototype;
let tiger = new Tiger('老虎');
console.log(tiger); // Tiger {name: '老虎', age: 10}
console.log(tiger.say); // [Function]
console.log(tiger.address) // {location: '大山'}
複製代碼
function Animal(name){
this.name = name;
this.eat = '吃肉';
}
Animal.prototype.address = {location: '大山'};
function Tiger(name){
this.name = name;
this.age = 5;
}
Tiger.prototype = Object.create(Animal.prototype);
// Tiger.prototype = Object.create(Animal.prototype,{constructor:{value:Tiger}});
// 上行代碼等價於Object.setPrototypeOf(Tiger.prototype,Animal.prototype) ES6
Tiger.prototype.say = function(){
console.log('說話')
}
let tiger = new Tiger('老虎')
console.log(tiger) // Animal { name: '老虎', age: 10 }
/* 這時候你會發現咱們明明建立的是Tiger的實例,可是咱們輸出的缺是Animal的實例,這就關係到Object.create方法的實現了, * 下面代碼咱們手寫一版簡單的Object.create方法(結合下文參考圖) */
Object.create = function(parentPrototype,options={}){
let Fn = function(){};
Fn.prototype = parentPrototype;
let fn = new Fn();
if(options.constructor){
fn.constructor = options.constructor.value
}
return fn;
}
/*不難看出咱們能夠給Object.create傳入options來改變constructor*/
複製代碼
class Animal{
static address(){ // 靜態方法(只能原型調用) 在ES7中能夠直接添加靜態屬性 static address = {location: '大山'}
return {location: '大山'}
}
constructor(name){ // 實例屬性
this.name = name;
this.eat = '吃肉'
}
say(){ // 原型上的方法
return '說話'
}
}
class Tiger extends Animal{
constructor(name){
super(name)
this.name = name;
this.age = 5;
}
sleep(){
return '睡覺'
}
}
let tiger = new Tiger('老虎');
console.log(tiger) // Tiger { name: '老虎', eat: '吃肉', age: 5 }
console.log(tiger.say()) // 說話
console.log(tiger.sleep()) // 睡覺
console.log(Animal.address()) // { location: '大山' }
console.log(Tiger.address()) // { location: '大山' }
複製代碼