Javascript 中實現對象原型繼承的三種方式

Javacript 中有一個思想:萬物皆對象,幾個基礎類型(String, Number, Boolean, Null, Undefined, Symbol),幾個引用類型(Array, Date, Function, Object, Regexp)本質上都是對象。es6

那麼對象之間如何實現關聯(也就是OO裏面的繼承)呢?js中經過prototype(原型)來實現。每一個對象都有一個__proto__指針,指向上一個原型,這就像是一個鏈表。最頂端的object的原型指向null, 表明終結。 因此,當咱們定義一個變量:瀏覽器

let name = new String('allen')
//let name = 'allen'
console.log('name:', name)
console.log('name.__proto__:', name.__proto__)
console.log('name.__proto__.__proto__:',name.__proto__.__proto__)	
console.log('name.__proto__.__proto__.__proto__:', name.__proto__.__proto__.__proto__)
複製代碼

輸出:bash

name: [String: 'allen']
name.__proto__: [String: '']
name.__proto__.__proto__: {}
name.__proto__.__proto__.__proto__: null
[Finished in 0.1s]
複製代碼

咱們要實現繼承(至少看上去是繼承的樣子)有三種方法:函數

  1. Object.create(),
  2. Function.prototype={},
  3. class extend

1. Object.create()

看例子:ui

let dog = {
	name: 'dog'
	}
	
let mardDog = Object.create(dog)
複製代碼

這裏 mardDog 是一個新的空對象,存有一個指針__proto__,指向的是 dog 對象, dog對象中也有一個__proto__,指向的是ObjectObject中也有一個__proto__,指向的是null。 這就是原型鏈。利用Object.create(),咱們能夠建立多個對象,dog對象都是他們的原型,那麼他們可不能夠改變dog裏面的屬性呢。答案是能夠 的,但不建議。代碼以下:this

mardDog.name = 'mardDog'

/*
dog ====> {name: 'dog'}
mardDog ====> {name: 'mardDog'}
*/
複製代碼

能夠看到,咱們並無能改變原型中的屬性。而下面這種方式:spa

mardDog.__proto__.name = 'xxxDog'

/*
	dog ====> {name: 'xxxDog'}
	mardDog ====> {name: 'mardDog'}
*/
複製代碼

咱們成功改變了上一層的屬性。 那麼,爲何咱們不推薦使用__proto__去改變原型中的共有屬性呢?由於這種方法很是慢,而且會嚴重影響進程。事實上,__proto__歷來沒有被寫進規範,可是瀏覽器廠商都實現了它。prototype

2. Function.prototype = {}

這個方法實際上是利用構造函數來實現 先看例子:指針

function dog (){
	this.name = 'dog'
	this.age = 1
}

let dog1 = new dog()

function mardDog (){
	this.yiel = function (){
		console.log(this.name)
	}
}

mardDog.prototype = new dog()

let mardDog1 = new mardDog()
mardDog1.yiel()
複製代碼

輸出:code

dog
[Finished in 0.1s]
複製代碼

能夠看到,咱們成功實現了mardDog 對 dog的繼承

3. class extend

es6中實現了 class 這個關鍵字,雖然只是語法糖,本質上是方法二的封裝,但這種思路對熟悉OO的開發者是很友好的,而且把js中使人迷惑的原型封裝了起來,使它變得更容易開發。

例子:

class dog {
   constructor () {
   	this.name = 'dog'
   	this.age = 1
   }
}

class mardDog extends dog {
	constructor () {
		super()
	}
	yiel () {
		console.log(this.name)
	}
}
let mardDog1 = new mardDog()
mardDog1.yiel()
複製代碼

輸出:

dog
複製代碼

這樣咱們成功地實現了繼承

總結

因爲es6 是大勢所趨,建議在工程環境中使用clas來實現對象的繼承。固然原型以及原型鏈的原理是必須掌握的。es6中還有一些方法也是十分有用。如下:

Object.getPrototypeOf(childobj) 顧名思義,該方法獲得childobj的prototype,也能夠理解爲父類。


Object.setPrototypeOf(childObj, obj)這個方法是將childObj設爲obj的繼承類。因爲前面提到過,對prototype的操做十分微妙,因此這個方法仍是能不用就不用,能夠用Object.create(obj)來代替


其餘方法參照MDN上的解釋

相關文章
相關標籤/搜索