DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> 淺談JavaScript對象與繼承
淺談JavaScript對象與繼承
編輯:關於JavaScript     

JavaScript是我在C語言之後接觸的第二門編程語言,大一暑假的時候在圖書館找了一本中國人寫的JavaScript程序設計來看。那個時候在編程方面幾乎還是小白,再加上那本書根本沒有提JavaScript的編程機制,又有一些誤導性的話,一直以來對JavaScript有很深的誤解,認為JavaScript只是一門在浏覽器上運行的面向對象語言,值此文來寫下JavaScript當中很具有迷惑性和容易誤解的地方。當然限於作者水平有限,也沒有什麼開發經驗,所以難免有疏漏之處,還望批評指正。

JavaScript的對象

對象是什麼

JavaScript代碼當中隨處可見new關鍵字,很容易讓人產生誤解,認為JavaScript是Java一樣是基於類繼承的語言。但是事實並非如此,JavaScript當中並沒有類,那JavaScript的對象不是類那又是什麼呢?某種意義上說,JavaScript的對象就是Python當中的字典(哈希表),其實也就是類似這樣的鍵值對:

me={
  "fisrtName" : "seek",
  "lastName" : "truth" ,
  "getName" : function(){
    return this.firstName+this.lastName; //this相當於指向這個對象的指針
  }
}

這是一個比較有誤解性的地方,初次看到時候覺得有點無法理解,但仔細用一用還是覺得合理,我們既可以像Python一樣用[]運算符來獲取元素,也可以用.操作符來獲取元素:

me.firstName // => seek
me["lastName"] //=> truth
me.getName() // => seektruth

new運算符

既然JavaScript當中是沒有類的,那麼new運算符又是在干什麼呢?這是JavaScript設計的最讓人誤解的地方之一。JavaScript是一門函數式編程語言,JavaScript當中函數是一等公民,JavaScript當中函數也是對象,函數對象在被創建的時候會被添加調用屬性,比較坑的是JavaScript函數有兩種調用方式,一種是加了new關鍵字的調用,一種是沒有new關鍵字的調用,前者會返回一個對象,後者會返回return語句當中的內容。考慮下面的一段函數:

function Obj(name){
  this.name=name;
  return name;
}

如果我們用new運算符來調用:

obj = new Obj("seektruth") //obj會是一個對象:{"name": "seektruth"}

如果我們直接調用:

obj = Obj("seektruth") //obj會是一個字符串:"seektruth"

確實設計的挺坑的,我們在調用的時候需要分清楚是否需要使用new,一般來說需要用new關鍵字來調用的函數會采用大寫開頭。

還有更坑的是如果返回的返回值是一個對象:

function Obj(name){
  this.name=name;
  return {};
}

這樣無論我們是否用new運算符來調用都會返回return語句裡的值:

new Obj("seektruth") //=> {}
Obj("seektruth") //=> {}

設計的是什麼鬼......

對象繼承

原型

前面已經說到過JavaScript當中是沒有類的,那JavaScript又是怎麼來實現繼承的呢?答案是通過原型鏈。在JavaScript當中,每個對象都會有一個原型,在創建對象的時候,如果不加說明的話,對象繼承的原型是Object.prototype,函數對象會繼承Function.prototype(Function.prototype繼承Object.prototype):

Object.prototype // => {}
Function.prototype // => [Function]

我們可以通過對象的__proto__熟悉來查看對象的原型:

a={}
a.__proto__ // => {}

JavaScript通過指定對象的原型來實現繼承,指定對象的原型主要有三種方式,一是在構造函數當中指明原型,二是直接修改對象的__proto__屬性,三是利用Object.create函數,下面我們依次來看一看

在構造函數當中指定原型

我們可以在構造函數當中指定對象的原型:

me={
  "firstName" : "seek",
  "lastName" : "truth" ,
  "getName" : function(){
    return this.firstName+this.lastName; //this相當於指向這個對象的指針
  }
}

function Obj(name){
  this.firstName = name;
  this.__proto__ = me; //指定原型為me對象
}

指定了原型之後,我們新建了對象之後就可以訪問原型的屬性:

obj = new Obj("foo"); // => { firstName: 'foo' }
obj.firstName // => foo
obj.lastName // => truth
obj.getName() // => "footruth"

當訪問一個對象的時候,首先會嘗試在改對象當中尋找該屬性,如果沒有就回到原型當中尋找,直到Object.prototype。如果我們在新的對象當中重寫了原型當中的屬性(方法),那麼實際使用的時候我們新寫的屬性(方法)會覆蓋掉原型當中的定義,這有點像基於類的語言的函數重載。

注意如果原型me對象的lastname屬性有改變,因為obj對象是在原型當中尋找屬性,那麼這個obj對象的lastname屬性也會改變:

me.lastName = "me"
obj.lastName // => "me"
obj.getName() // => "foome"

直接改變對象的原型

我們也可以直接指定(改變)對象的原型:

obj2 = {}
obj2.__proto__ = me
obj2.firstName // => seek
obj2.lastName // => "me"
obj2.getName() // => "seekme"

使用Object.create函數

盡管說前兩種方法可以解決問題,但是這兩種寫法並不優雅,因為JavaScript並不是基於類的語言,第一寫法很容易給人以誤解,JavaScript語言精粹的作者Crockford認為new就不應該出現在JavaScript語言當中,而推薦使用Object.create函數來基於原型來創建對象。Object.create函數的用法很簡單:

obj3 = Object.create(me) // 以me為原型創建新的對象
obj3.firstName // => seek
obj3.lastName // => "me"
obj3.getName() // => "seekme"

obj3 = Object.create(me) 與obj2 = {};obj2.proto = me是等價的,但是前一種寫法更優雅也更易於理解。

總結

JavaScript作為一門基於原型的,函數式的編程語言在設計上有很多優雅與強大之處,但同時又有很多糟粕和坑,正式如此,JavaScript也是被誤解最多語言。學習了JavaScript的對象繼承機制,感覺自己的水平還是大有長進的。

以上這篇淺談JavaScript對象與繼承就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved