深入理解js中實(shí)現(xiàn)繼承的原理和方法

原型對(duì)象繼承

  • ==原理:原型對(duì)象的屬性可以經(jīng)由對(duì)象實(shí)例訪問(wèn)==
  • 下面的例子,所含【對(duì)象繼承】和【構(gòu)造函數(shù)繼承】,用于理解【原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)】
//對(duì)象繼承
var person = {
  name:"gs",
  age:19
}
console.log(person.prototype === undefined );
function Student(){}
Student.prototype = person;//原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)
console.log(new Student());
//構(gòu)造函數(shù)繼承
function Person(){
  this.name = "gs";
  this.age = 19;
}
function Student(){
  this.name = "zk"
}
Student.prototype = new Person();//原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)
var zk = new Student();
console.log(zk);

Object是頂層對(duì)象

  • 所有對(duì)象都繼承自 Object.prototype,除非顯示指定
  • 以對(duì)象字面量定義的對(duì)象,其 prototype 的值都被設(shè)為 Object.prototype

定義在 Object.prototype 上的方法

  • hasOwnProperty
  • propertyIsEnumerable
  • isPrototypeOf
  • valueOf | 返回對(duì)象的值表達(dá)
  • toString | 返回對(duì)象的字符串表達(dá)

valueOf

  • 每當(dāng)一個(gè)操作符被用于一個(gè)對(duì)象時(shí)(自動(dòng))調(diào)用

toString

  • 在進(jìn)行運(yùn)算時(shí),有可能發(fā)生類型轉(zhuǎn)換
let obj = { name:"gs" };
console.log(obj+111)//;[object Object]111
console.log(obj.toString());//[object Object]
console.log(obj.valueOf());//{ "name": "gs" }

最好不要去修改 Object.prototype

最簡(jiǎn)單的一個(gè)對(duì)象繼承

  • 聲明一個(gè)字面量對(duì)象,相當(dāng)于自動(dòng)繼承自 Object
  • 聲明字面量對(duì)象,可以用 Object.create 方法替代,它的繼承作用更加明顯
  • ==注意:Object.prototype 實(shí)際上值是 null==
var student1 = {
  name:"gs"
}
var student2 = Object.create(Object.prototype,{
  name:{
    configurable:true,
    enumerable:true,
    value:"gs",
    writable:true,
  }
})

實(shí)現(xiàn)一個(gè)基本的對(duì)象繼承

//對(duì)象繼承
var person = {
  name:"gs",
  age:19
}
console.log(person.prototype === undefined );
function Student(){}
Student.prototype = person;//原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)
console.log(new Student());

實(shí)現(xiàn)一個(gè)稍復(fù)雜的構(gòu)造函數(shù)繼承

  • 因?yàn)閖s中的繼承是通過(guò)原型對(duì)象鏈來(lái)實(shí)現(xiàn)的,因此沒(méi)有調(diào)用對(duì)象父類的構(gòu)造函數(shù)
  • 所以,要注意!最好重寫(xiě)構(gòu)造器屬性,否則將被設(shè)為父類的值
function Person(school,name,age){
  this.school = "beijing univercity";
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  console.log(this.name);
}
Person.prototype.sayAge = function(){
  console.log(this.age);
}

function Student(name,age){
  this.name = name;
  this.age = age;
}
Student.prototype = new Person();
var gs = new Student("gs",19);
console.log(gs.constructor);//Person
Student.prototype.constructor = Student;//注意!要重寫(xiě)構(gòu)造器屬性,否則將被設(shè)為父類的值
console.log(gs.constructor);//Student
Student.prototype.sayName = function(){
  console.log("student is "+this.name);
}
console.log(gs.sayName());
console.log(gs.sayAge());

實(shí)現(xiàn)一個(gè)偽類繼承(構(gòu)造函數(shù)竊?。?/h4>
  • 實(shí)際上就是使用 call 的方式,將父類的屬性“拷貝”到子類中,同時(shí)還包括了constructor屬性
  • 仍然需要用prototype方式繼承方法,同時(shí)還要設(shè)置constructor
function Person(school,name,age){
  this.school = "beijing univercity";
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  console.log(this.name);
}
Person.prototype.sayAge = function(){
  console.log(this.age);
}

function Teacher(school){
  Person.call(this,...arguments);//因?yàn)閠his指向Teacher,所以constructor屬性仍將是Teacher
  this.school = school;//注意,新的屬性,應(yīng)置于繼承發(fā)生之后,以做覆蓋
}
var zk = new Teacher("haver","zk",23);
console.log(zk.constructor);//constructor屬性正確,為T(mén)eacher
console.log(zk.sayName === undefined);//true,但是,沒(méi)有繼承原型方法和屬性
Teacher.prototype = new Person();
var zk_2 = new Teacher("haver","zk_2",23);//沒(méi)有繼承原型方法
console.log(zk_2.sayName());//拿到方法了
console.log(zk_2.constructor);//Person。不是吧,constructor屬性又不對(duì)了
Teacher.prototype.constructor = Teacher;
console.log(zk_2.constructor);//Teacher。使用call方式繼承屬性,仍然需要用prototype方式繼承方法,同時(shí)還要設(shè)置constructor

父類方法被子類覆蓋,如何仍然可以調(diào)用?

function Person(name,age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  console.log("father method " + this.name);
}
Person.prototype.sayAge = function(){
  console.log(this.age);
}

function Student(){
  Person.call(this,...arguments);
}
Student.prototype = Object.create(Person.prototype,{
  constructor:{
    configurable:true,
    enumerable:true,
    value:Student,
    writable:true,
  }
})
Student.prototype.sayName = function(){
  console.log("child method");
}
Student.prototype.sayName_1 = function(){
  Person.prototype.sayName.call(this);//這是唯一的訪問(wèn)父類的方法
}
var gs = new Student("gs",20);
console.log(gs);

console.log(gs.sayName_1());

創(chuàng)建一個(gè)沒(méi)有原型對(duì)象的對(duì)象

  • 它不會(huì)發(fā)生和繼承來(lái)的屬性名相沖突的問(wèn)題,所以它是一個(gè)完美的【哈希容器】
  • 哈希容器也可以理解為是一種映射容器,采用哈希算法(映射算法,散列算法),將不定長(zhǎng)的數(shù)據(jù)壓縮成定長(zhǎng)的數(shù)據(jù),這串定長(zhǎng)值我們稱為 哈希值
var obj = Object.create(null);
console.log(obj.prototype === undefined);
console.log( valueOf in obj);
console.log( toString in 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ù)。

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