自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Javascript面向?qū)ο缶幊蹋ǘ├^承

開(kāi)發(fā) 前端
Javascript是一種基于對(duì)象(object-based)的語(yǔ)言,你遇到的所有東西幾乎都是對(duì)象。但是,它又不是一種真正的面向?qū)ο缶幊陶Z(yǔ)言,因?yàn)樗恼Z(yǔ)法中沒(méi)有class。本文主要介紹Javascript中的繼承,一起來(lái)看。

上一次的文章,主要介紹了Javascript如何"封裝"數(shù)據(jù)和方法,從原型對(duì)象生成實(shí)例。今天要介紹的是,多個(gè)原型對(duì)象之間如何"繼承"。

比如,現(xiàn)在有一個(gè)"動(dòng)物"對(duì)象,

 

  1. function Animal()  
  2. {  
  3. this.species = "動(dòng)物";  

 

還有一個(gè)"貓"對(duì)象,

 

  1. function Cat(name,color)  
  2. {  
  3. this.name = name;  
  4. this.color = color;  

 

怎樣才能使"貓"繼承"動(dòng)物"呢?

1. 原型對(duì)象綁定

最簡(jiǎn)單的方法,大概就是使用call或apply方法,將父對(duì)象綁定在子對(duì)象上,也就是在子對(duì)象函數(shù)中加一行:

 

  1. function Cat(name,color)  
  2. {  
  3. Animal.apply(this, arguments);  
  4. this.name = name;  
  5. this.color = color;  
  6. }   
  7. var cat1 = new Cat("大毛","黃色");  
  8. alert(cat1.species); // 動(dòng)物 

 

2. prototype模式

更常見(jiàn)的做法,則是使用prototype屬性。

如果"貓"的prototype對(duì)象,指向一個(gè)Animal的實(shí)例,那么所有"貓"的實(shí)例,就能繼承Animal了。

 

  1. Cat.prototype = new Animal();  
  2. Cat.prototype.constructor = Cat;  
  3. var cat1 = new Cat("大毛","黃色");  
  4. alert(cat1.species); // 動(dòng)物 

 

代碼的第一行,我們將Cat的prototype對(duì)象指向一個(gè)Animal的實(shí)例。

 

  1. Cat.prototype = new Animal(); 

 

它相當(dāng)于完全刪除了prototype 對(duì)象原先的值,然后賦予一個(gè)新值。但是,第二行又是什么意思呢?

 

  1. Cat.prototype.constructor = Cat; 

 

原來(lái),任何一個(gè)prototype對(duì)象都有一個(gè)constructor屬性,指向它的構(gòu)造函數(shù)。也就是說(shuō),Cat.prototype 這個(gè)對(duì)象的constructor屬性,是指向Cat的。

我們?cè)谇耙徊揭呀?jīng)刪除了這個(gè)prototype對(duì)象原來(lái)的值,所以新的prototype對(duì)象沒(méi)有constructor屬性,所以我們必須手動(dòng)加上去,否則后面的"繼承鏈"會(huì)出問(wèn)題。這就是第二行的意思。

總之,這是很重要的一點(diǎn),編程中務(wù)必要遵守。下文都遵循這一點(diǎn),即如果替換了prototype對(duì)象,

 

  1. o.prototype = {}; 

 

那么,下一步必然是為新的prototype對(duì)象加上constructor屬性,并將這個(gè)屬性指回原來(lái)的構(gòu)造函數(shù)。

 

  1. o.prototype.constructor = o; 

 

3. 直接繼承prototype

由于Animal對(duì)象中,不變的屬性都可以直接寫(xiě)入Animal.prototype。所以,我們也可以讓Cat()跳過(guò) Animal(),直接繼承Animal.prototype。

現(xiàn)在,我們先將Animal對(duì)象改寫(xiě):

 

  1. function Animal(){ }  
  2. Animal.prototype.species = "動(dòng)物"

 

然后,將Cat的prototype對(duì)象,然后指向Animal的prototype對(duì)象,這樣就完成了繼承。

 

  1. Cat.prototype = Animal.prototype;  
  2. Cat.prototype.constructor = Cat;  
  3. var cat1 = new Cat("大毛","黃色");  
  4. alert(cat1.species); // 動(dòng)物 

 

與前一種方法相比,這樣做的優(yōu)點(diǎn)是效率比較高(不用執(zhí)行和建立Animal的實(shí)例了),比較省內(nèi)存。缺點(diǎn)是 Cat.prototype和Animal.prototype現(xiàn)在指向了同一個(gè)對(duì)象,那么任何對(duì)Cat.prototype的修改,都會(huì)反映到Animal.prototype。

所以,上面這一段代碼其實(shí)是有問(wèn)題的。請(qǐng)看第二行

 

  1. Cat.prototype.constructor = Cat; 

 

這一句實(shí)際上把Animal.prototype對(duì)象的constructor屬性也改掉了!

 

  1. alert(Animal.prototype.constructor); // Cat 

 

4. 利用空對(duì)象作為中介

由于"直接繼承prototype"存在上述的缺點(diǎn),所以可以利用一個(gè)空對(duì)象作為中介。

 

  1. var F = function(){};  
  2. F.prototype = Animal.prototype;  
  3. Cat.prototype = new F();  
  4. Cat.prototype.constructor = Cat; 

 

F是空對(duì)象,所以幾乎不占內(nèi)存。這時(shí),修改Cat的prototype對(duì)象,就不會(huì)影響到Animal的prototype對(duì)象。

 

  1. alert(Animal.prototype.constructor); // Animal 

 

5. prototype模式的封裝函數(shù)

我們將上面的方法,封裝成一個(gè)函數(shù),便于使用。

 

  1. function extend(Child, Parent)   
  2. {  
  3. var F = function(){};  
  4. F.prototype = Parent.prototype;  
  5. Child.prototype = new F();  
  6. Child.prototype.constructor = Child;  
  7. Child.uber = Parent.prototype;  

 

使用的時(shí)候,方法如下

 

  1. extend(Cat,Animal);  
  2. var cat1 = new Cat("大毛","黃色");  
  3. alert(cat1.species); // 動(dòng)物 

 

這個(gè)extend函數(shù),就是YUI庫(kù)如何實(shí)現(xiàn)繼承的方法。

另外,說(shuō)明一點(diǎn)。函數(shù)體最后一行

  1. Child.uber = Parent.prototype; 

意思是為子對(duì)象設(shè)一個(gè)uber屬性,這個(gè)屬性直接指向父對(duì)象的prototype屬性。這等于是在子對(duì)象上打開(kāi)一條通道,可以直接調(diào)用父對(duì)象的方法。這一行放在這里,只是為了實(shí)現(xiàn)繼承的完備性,純屬備用性質(zhì)。

6. 拷貝繼承

上面是采用prototype對(duì)象,實(shí)現(xiàn)繼承。我們也可以換一種思路,純粹采用"拷貝"方法實(shí)現(xiàn)繼承。簡(jiǎn)單說(shuō),如果把父對(duì)象的所有屬性和方法,拷貝進(jìn)子對(duì)象,不也能夠?qū)崿F(xiàn)繼承嗎?

首先,還是把Animal的所有不變屬性,都放到它的prototype對(duì)象上。

 

  1. function Animal(){}  
  2. Animal.prototype.species = "動(dòng)物"

 

然后,再寫(xiě)一個(gè)函數(shù),實(shí)現(xiàn)屬性拷貝的目的。

 

  1. function extend2(Child, Parent) {   
  2. var p = Parent.prototype;  
  3. var c = Child.prototype;  
  4. for (var i in p) {   
  5. c[i] = p[i];  
  6. }  
  7. c.uber = p;  
  8. }  

 

這個(gè)函數(shù)的作用,就是將父對(duì)象的prototype對(duì)象中的屬性,一一拷貝給Child對(duì)象的prototype對(duì)象。

使用的時(shí)候,這樣寫(xiě):

 

  1. extend2(Cat, Animal);  
  2. var cat1 = new Cat("大毛","黃色");  
  3. alert(cat1.species); // 動(dòng)物 

 

原文地址:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

【編輯推薦】

  1. Javascript面向?qū)ο缶幊蹋ㄉ希?封裝
  2. WordPress的JavaScript本地化
  3. 關(guān)于 JavaScript 的 with 語(yǔ)句
  4. Web移動(dòng)應(yīng)用 HTML5 CSS和JavaScript
  5. JavaScript 假如default不是switch的最后一項(xiàng)
責(zé)任編輯:于鐵 來(lái)源: 阮一峰的博客
相關(guān)推薦

2010-10-08 09:13:15

oop模式JavaScript

2011-05-25 11:15:02

Javascript繼承

2017-04-21 09:07:39

JavaScript對(duì)象編程

2012-01-17 09:34:52

JavaScript

2012-02-27 09:30:22

JavaScript

2023-09-27 23:28:28

Python編程

2011-05-25 10:21:44

Javascript

2011-05-13 10:51:25

javascript

2011-06-28 14:11:33

JavaScript

2018-12-14 11:30:00

JavaScript編程前端

2009-01-04 09:08:30

面向?qū)ο?/a>繼承接口

2010-03-05 14:44:36

Python繼承

2011-07-14 17:37:02

C++面向?qū)ο缶幊趟枷?/a>

2010-11-17 11:31:22

Scala基礎(chǔ)面向?qū)ο?/a>Scala

2023-02-22 18:06:35

函數(shù)javascript面向?qū)ο缶幊?/a>

2019-11-18 17:05:02

JavaScript面向?qū)ο蟪绦蚓幊?/a>Java

2022-07-30 23:41:53

面向過(guò)程面向?qū)ο?/a>面向協(xié)議編程

2021-10-21 18:47:37

JavaScript面向對(duì)象

2012-12-13 11:01:42

IBMdW

2024-09-18 08:13:01

C#封裝繼承
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)