日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

前言

面向?qū)ο蟮娜筇匦裕悍庋b、繼承和多態(tài)。上一篇我們簡(jiǎn)單的了解了封裝的過程,也就是把對(duì)象的屬性和方法封裝到一個(gè)函數(shù)中,這一篇講一下JAVAScript中繼承的實(shí)現(xiàn),繼承是面向?qū)ο笾蟹浅V匾奶匦裕梢詭椭覀兲岣叽a的復(fù)用性。繼承主要的思想就是將重復(fù)的代碼邏輯抽取到分類中,子類只需要通過繼承分類,就可以使用分類中的方法,但是在實(shí)現(xiàn)JavaScript繼承之前,需要先了解一個(gè)重要的知識(shí)點(diǎn)“原型鏈”。

1.JavaScript中的原型鏈

在上一篇JavaScript面向?qū)ο?mdash;對(duì)象的創(chuàng)建和操作中已經(jīng)簡(jiǎn)單的了解過了JavaScript中對(duì)象的原型和函數(shù)的原型,當(dāng)我們從一個(gè)對(duì)象上獲取屬性時(shí),如果在當(dāng)前對(duì)象自身沒有找到該屬性的話,就會(huì)去它原型上面獲取,如果原型中也沒有找到就會(huì)去它原型的原型上找,沿著這么一條線進(jìn)行查找,那么這條線就是我們所說的原型鏈了。

示例代碼:

const obj = {
  name: 'curry',
  age: 30
}

obj.__proto__ = {}
obj.__proto__.__proto__ = {}
obj.__proto__.__proto__.__proto__ = { height: 1.83 }

console.log(obj.height) // 1.83

對(duì)應(yīng)的內(nèi)存中的查找過程:

JavaScript面向?qū)ο蟆^承的實(shí)現(xiàn)

 

當(dāng)通過原型鏈查找某個(gè)屬性時(shí),一直找不到的話會(huì)一直查找下去么?肯定是不會(huì)的,JavaScript的原型鏈也是有盡頭的,這個(gè)盡頭就是Object的原型。

2.Object的原型

事實(shí)上,不管是對(duì)象還是函數(shù),它們?cè)玩湹谋M頭都是Object的原型,也稱之為頂層原型,我們可以打印看看這個(gè)頂層原型長什么樣。

(1)打印Object的原型

console.log(Object.prototype)
  • 在node環(huán)境中:
JavaScript面向?qū)ο蟆^承的實(shí)現(xiàn)

 

  • 在瀏覽器中:
JavaScript面向?qū)ο蟆^承的實(shí)現(xiàn)

 

(2)Object原型的特殊之處

  • 如果我們?cè)俅未蛴bject.prototype的原型,這個(gè)原型屬性已經(jīng)指向了null
  • console.log(Object.prototype.__proto__) // null
  • 并且在Object.prototype上有很多默認(rèn)的屬性和方法,像toString、hasOwnProperty等;

(3)上一篇中講到當(dāng)使用new操作符調(diào)用構(gòu)造函數(shù)時(shí),其對(duì)象的[[prototype]]會(huì)指向該構(gòu)造函數(shù)的原型prototype,其實(shí)Object也是一個(gè)構(gòu)造函數(shù),因?yàn)槲覀兛梢允褂胣ew操作符來調(diào)用它,創(chuàng)建一個(gè)空對(duì)象。

  • 示例代碼:
  • const obj = new Object() obj.name = 'curry' obj.age = 30 console.log(obj.__proto__ === Object.prototype) // true console.log(obj.__proto__) // [Object: null prototype] {} console.log(obj.__proto__.__proto__) // null
  • 內(nèi)存表現(xiàn):
  •  

(4)總結(jié)

  • 從Object的原型可以得出一個(gè)結(jié)論“原型鏈最頂層的原型對(duì)象就是Object的原型對(duì)象”,這也就是為什么所有的對(duì)象都可以調(diào)用toString方法了;
  • 從繼承的角度來講就是“Object是所有類的父類”;

3.JavaScript繼承的實(shí)現(xiàn)方案

3.1.方案一:通過原型鏈實(shí)現(xiàn)繼承

如果需要實(shí)現(xiàn)繼承,那么就可以利用原型鏈來實(shí)現(xiàn)了。

  • 定義一個(gè)父類Person和子類Student;
  • 父類中存放公共的屬性和方法供子類使用;
  • 核心:將父類的實(shí)例化對(duì)象賦值給子類的原型;
// 定義Person父類公共的屬性
function Person() {
  this.name = 'curry'
  this.age = 30
}
// 定義Person父類的公共方法
Person.prototype.say = function() {
  console.log('I am ' + this.name)
}

// 定義Student子類特有的屬性
function Student() {
  this.sno = 101111
}

// 實(shí)現(xiàn)繼承的核心:將父類的實(shí)例化對(duì)象賦值給子類的原型
Student.prototype = new Person()

// 定義Student子類特有的方法
Student.prototype.studying = function() {
  console.log(this.name + ' studying')
}

// 實(shí)例化Student
const stu = new Student()
console.log(stu.name) // curry
console.log(stu.age) // 30
console.log(stu.sno) // 101111
stu.say() // I am curry
stu.studying() // curry studying

內(nèi)存表現(xiàn):

JavaScript面向?qū)ο蟆^承的實(shí)現(xiàn)

 

缺點(diǎn)

  • 從內(nèi)存表現(xiàn)圖中就可以看出,當(dāng)打印stu對(duì)象時(shí),name和age屬性是看不到的,因?yàn)椴粫?huì)打印原型上的東西;
  • 當(dāng)父類中的屬性為引用類型時(shí),子類的多個(gè)實(shí)例對(duì)象會(huì)共用這個(gè)引用類型,如果進(jìn)行修改,會(huì)相互影響;
  • 在使用該方案實(shí)現(xiàn)繼承時(shí),屬性都是寫死的,不支持動(dòng)態(tài)傳入?yún)?shù)來定制化屬性值;

3.2.方案二:借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承

針對(duì)方案一的缺點(diǎn),可以借用構(gòu)造函數(shù)來進(jìn)行優(yōu)化。

  • 在子類中通過call調(diào)用父類,這樣在實(shí)例化子類時(shí),每個(gè)實(shí)例就可以創(chuàng)建自己?jiǎn)为?dú)屬性了;
// 定義Person父類公共的屬性
function Person(name, age) {
  this.name = name
  this.age = age
}
// 定義Person父類的公共方法
Person.prototype.say = function() {
  console.log('I am ' + this.name)
}

// 定義Student子類特有的屬性
function Student(name, age, sno) {
  // 通過call調(diào)用Person父類,創(chuàng)建自己的name和age屬性
  Person.call(this, name, age)
  this.sno = sno
}

// 實(shí)現(xiàn)繼承的核心:將父類的實(shí)例化對(duì)象賦值給子類的原型
Student.prototype = new Person()

// 定義Student子類特有的方法
Student.prototype.studying = function() {
  console.log(this.name + ' studying')
}

// 實(shí)例化Student
const stu1 = new Student('curry', 30, 101111)
const stu2 = new Student('kobe', 24, 101112)
console.log(stu1) // Person { name: 'curry', age: 30, sno: 101111 }
console.log(stu2) // Person { name: 'kobe', age: 24, sno: 101112 }

內(nèi)存表現(xiàn):

JavaScript面向?qū)ο蟆^承的實(shí)現(xiàn)

 

缺點(diǎn):

  • 在實(shí)現(xiàn)繼承的過程中,Person構(gòu)造函數(shù)被調(diào)用了兩次,一次在new Person(),一次在Person.call();
  • 在Person的實(shí)例化對(duì)象上,也就是stu1和stu2的原型上,多出來了沒有使用的屬性name和age;

3.3.方案三:寄生組合式繼承

通過上面兩種方案,我們想實(shí)現(xiàn)繼承的目的是重復(fù)利用另外一個(gè)對(duì)象的屬性和方法,如果想解決方案二中的缺點(diǎn),那么就要減少Person的調(diào)用次數(shù),避免去執(zhí)行new Person(),而解決的辦法就是可以新增一個(gè)對(duì)象,讓該對(duì)象的原型指向Person的原型即可。

(1)對(duì)象的原型式繼承

將對(duì)象的原型指向構(gòu)造函數(shù)的原型的過程就叫做對(duì)象的原型式繼承,主要可以通過以下三種方式實(shí)現(xiàn):

  • 封裝一個(gè)函數(shù),將傳入的對(duì)象賦值給構(gòu)造函數(shù)的原型,最后將構(gòu)造函數(shù)的實(shí)例化對(duì)象返回;
  • function createObj(o) { // 定義一個(gè)Fn構(gòu)造函數(shù) function Fn() {} // 將傳入的對(duì)象賦值給Fn的原型 Fn.prototype = o // 返回Fn的實(shí)例化對(duì)象 return new Fn() } const protoObj = { name: 'curry', age: 30 } const obj = createObj(protoObj) // 得到的obj對(duì)象的原型已經(jīng)指向了protoObj console.log(obj.name) // curry console.log(obj.age) // 30 console.log(obj.__proto__ === protoObj) // true
  • 改變上面方法中的函數(shù)體實(shí)現(xiàn),使用Object.setPrototypeOf()方法來實(shí)現(xiàn),該方法設(shè)置一個(gè)指定的對(duì)象的原型到另一個(gè)對(duì)象或null;
  • function createObj(o) { // 定義一個(gè)空對(duì)象 const newObj = {} // 將傳入的對(duì)象賦值給該空對(duì)象的原型 Object.setPrototypeOf(newObj, o) // 返回該空對(duì)象 return newObj }
  • 直接使用Object.create()方法,該方法可以創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來提供新創(chuàng)建的對(duì)象的__proto__;
  • const protoObj = { name: 'curry', age: 30 } const obj = Object.create(protoObj) console.log(obj.name) // curry console.log(obj.age) // 30 console.log(obj.__proto__ === protoObj) // true

(2)寄生組合式繼承的實(shí)現(xiàn)

寄生式繼承就是將對(duì)象的原型式繼承和工廠模式進(jìn)行結(jié)合,即封裝一個(gè)函數(shù)來實(shí)現(xiàn)繼承的過程。而這樣結(jié)合起來實(shí)現(xiàn)的繼承,又可以稱之為寄生組合式繼承。下面就看看具體的實(shí)現(xiàn)過程吧。

  • 創(chuàng)建一個(gè)原型指向Person父類的對(duì)象,將其賦值給Student子類的原型;
  • 在上面的實(shí)現(xiàn)方案中,Student子類的實(shí)例對(duì)象的類型都是Person,可以通過重新定義constructor來優(yōu)化;
// 定義Person父類公共的屬性
function Person(name, age) {
  this.name = name
  this.age = age
}
// 定義Person父類的公共方法
Person.prototype.say = function() {
  console.log('I am ' + this.name)
}

// 定義Student子類特有的屬性
function Student(name, age, sno) {
  // 通過call調(diào)用Person父類,創(chuàng)建自己的name和age屬性
  Person.call(this, name, age)
  this.sno = sno
}

// 調(diào)用Object.create方法生成一個(gè)原型指向Person原型的對(duì)象,并將這個(gè)對(duì)象賦值給Student的原型
Student.prototype = Object.create(Person.prototype)
// 定義Student原型上constructor的值為Student
Object.defineProperty(Student.prototype, 'constructor', {
  configurable: true,
  enumerable: false,
  writable: true,
  value: Student
})

// 定義Student子類特有的方法
Student.prototype.studying = function() {
  console.log(this.name + ' studying')
}

// 實(shí)例化Student
const stu1 = new Student('curry', 30, 101111)
const stu2 = new Student('kobe', 24, 101112)
console.log(stu1) // Student { name: 'curry', age: 30, sno: 101111 }
console.log(stu2) // Student { name: 'kobe', age: 24, sno: 101112 }

內(nèi)存表現(xiàn):

JavaScript面向?qū)ο蟆^承的實(shí)現(xiàn)

 

總結(jié):

  • 多個(gè)地方用到了繼承,可以將上面的核心代碼賦值在一個(gè)函數(shù)里面,如果不想用Object.create(),也可以使用上面封裝的createObj函數(shù);
  • function createObj(o) { function Fn() {} Fn.prototype = o return new Fn() } /** * @param {function} SubClass * @param {function} SuperClass */ function inherit(SubClass, SuperClass) { SubClass.prototype = createObj(SuperClass.prototype) Object.defineProperty(SubClass.prototype, 'constructor', { configurable: true, enumerable: false, writable: true, value: SubClass }) }
  • 寄生組合式實(shí)現(xiàn)繼承的原理其實(shí)就是創(chuàng)建一個(gè)空對(duì)象用于存放子類原型上的方法,并且這個(gè)對(duì)象的原型指向父類的原型,在ES6中推出的class的實(shí)現(xiàn)原理就在這;

 

原文地址:
https://www.cnblogs.com/MomentYY/p/15999285.html

分享到:
標(biāo)簽:JavaScript
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定