摘要:有一函數若是用來生成對象,則稱為構造函數名。屬性指定了使用該構造函數生成的對象實例繼承了哪個對象實例。因此,只要利用,就能在構造函數中,為未來利用此構造函數生成的對象實例,添加成員屬性和成員方法了。
與其它編程語言不一樣的是,javascript的面向對象并非依賴于抽象的類,而是通過原型鏈,將一個個具體的對象實例進行連接,位于原型鏈下游的對象實例可以讀取/使用位于上游的對象實例的屬性/方法。
下文由簡及深,試圖一步步理清javascript面向對象的本質。
javascript定義了最基礎的對象類型Object,并且為這一對象類型定義了許多成員方法。其它許多原生對象類型,實際上都是繼承自Object,比如說Function、Date等。想要生成一個Object對象類型的對象實例也不是一件什么難事:
var obj = {a: 2333}; //又或者是利用Object()這一構造函數 var obj = new Object();
實際上,更符合面向對象思想的應該是利用構造函數來生成對象實例。
生成對象實例的運算符new,以及構造函數constructor 如何使用new這一運算符來生成對象實例在其它編程語言中,new往往也是用來生成對象實例的,用法一般是這樣:new ClassName[([arguments])],而生成出來的對象實例也被冠以“ClassName對象”這樣的稱謂;而javascript則大不相同,由于原生沒有類這一概念,因此構造函數便取而代之:new constructor[([arguments])],而稱謂也改為“constructor對象”或"constructor類型的對象",構造函數名直接就等同于數據類型了。
function A() {} //有一函數(若是用來生成對象,則稱為構造函數)名A。 var obj = new A(); //使用構造函數A來生成實例對象obj console.dir(obj); //打印實例對象obj
從上圖可知,利用構造函數A生成的實例對象obj的數據類型為A,另外,我們留意到obj有且只有一個__proto__屬性,這是什么呢?先別急,下面就說到。
詳述構造函數constructor從上文可知,要想生成對象實例,必須使用構造函數(constructor),即便是var arr = [];或var obj = {}這樣的形式,javascript也會在內部調用Function()、Object()這樣預設的構造函數(由于是預設的構造函數/數據類型,因此不需顯式指定)。
繼續沿用上述例子,這次我們把構造函數A打印出來看看長什么樣兒:
function A() {} var obj = new A(); console.dir(A);
實際上,構造函數跟普通的函數并無二致,只是因為用途(用來生成對象實例),因此才冠以“構造函數”的大名。從上圖看,我們略過一些與面向對象無關的屬性(arguments/caller/length/name),以及其函數作用域(
特別注明是“構造函數中的prototype屬性”,是因為,對于一般的函數來說,prototype屬性沒什么意義。prototype屬性指定了使用該構造函數生成的對象實例繼承了哪個對象實例。
如上述的function A()的prototype屬性指向了一個默認的Object類型的對象實例(在javascript中,變量只是對象實例的一個引用,因此此處用“指向”比較準確),那么,用function A()作為構造函數實例化的obj實際上就是繼承了那默認的Object類型的對象實例,雖然obj本身并沒有自定義的屬性/方法,但是能通過obj調用繼承回來的所有屬性/方法。
既然構造函數的prototype屬性能指定繼承的對象實例,那么只要我們修改這prototype屬性,使其指向其它對象實例,那么就可以達到實現繼承任意對象的效果了,看下面代碼:
var car = { //一個普通的Object類型實例對象 status: "stop" } function audi() {} //構造函數audi audi.prototype = car; //修改構造函數audi的prototype屬性,使其指向car console.dir(audi); var audiQ3 = new audi(); //利用構造函數audi生成的數據類型為audi的實例對象 console.dir(audiQ3);
先來看看構造函數audi打印出來的結果:
從audi.prototype.status可以看出,此時的audi.prototype的確是指向{status: "stop"}這個對象實例了。
那么接下來看看利用修改后的構造函數audi所生成的對象實例audiQ3:
我們可以發現audiQ3這一實例對象的數據類型是audi(與構造函數同名),另外,audiQ3其下只有__proto__這唯一一個成員屬性,繼續查看__proto__,赫然發現,里面竟然有status: "stop"。沒錯,__proto__屬性正是指向{status: "stop"}這個對象實例的一個引用。
原型鏈的接點:__proto__通過對象實例中的__proto__屬性,繼承的對象實例得以與被繼承的對象實例鏈接起來,于是,一環扣一環,形成了一條由對象實例、指向被繼承對象實例的引用所構成的鏈條:原型鏈。
由于__proto__是由構造函數的prototype屬性決定的(也可以說是prototype直接賦值給__proto__),因此我們可以通過修改prototype屬性來操縱這條原型鏈。
再談構造函數構造函數,主要用來在創建對象時初始化對象, 即為對象成員變量賦初始值,那么,javascript里的構造函數,是怎么實現這樣的功能的呢?以下面的DEMO作為示例說明:
function car() { //定義了一個名為car的構造函數 this.status = "stop"; //為日后使用car這一構造函數來生成的對象實例添加個status成員變量,并賦初始值"stop" this.start = function() { //為對象實例添加一個名為start的成員方法 this.status = "running"; } } var audiQ3 = new car(); //利用car生成一個對象實例,并將其賦給變量audiQ3 console.dir(audiQ3); audiQ3.start(); //調用audiQ3的start方法 console.dir(audiQ3);
首先來看構造函數car,我們看到this.status = "stop";,這this是指代car這一function嗎?不是的,這個this實際上是指向當前函數執行時的上下文環境,用在構造函數時,指的則是新生成的對象實例(在本DEMO中指的是audiQ3)。因此,只要利用this,就能在構造函數中,為未來利用此構造函數生成的對象實例,添加成員屬性和成員方法了。
javascript原生支持的原型繼承方式:Object.createECMAScript 5定義了一種原生的原型繼承方式:Object.create,我們可以通過這種方式更簡便地實現原型繼承。
語法Object.create(proto, [ propertiesObject ])參數
proto 一個對象,作為新創建對象的原型。示例
propertiesObject 可選。該參數對象是一組屬性與值,該對象的屬性名稱將是新創建的對象的屬性名稱,值是屬性描述符(這些屬性描述符的結構與Object.defineProperties()的第二個參數一樣)。注意:該參數對象不能是undefined,另外只有該對象中自身擁有的可枚舉的屬性才有效,也就是說該對象的原型鏈上屬性是無效的。
var car = { status: "stop", start: function() { this.status = "running" } } var audiQ3 = Object.create(car); console.dir(audiQ3);
怎么樣,利用Object.create這種方法是不是很簡單就實現了原型繼承呢?實際上,這是ECMAScript 5給我們做了一下封裝,相當于:
function (proto) { var constructor = function(){} constructor.prototype = proto; return new constructor(); }瀏覽器兼容性修復
考慮到ECMAScript 5在IE上到IE10才完全支持,因此我們有必要對低版本的IE瀏覽器進行兼容,實際上也很簡單,對上面的代碼稍作修改即可:
if(typeof Object.create !== "function") { Object.create = function(proto) { var constructor = function(){} constructor.prototype = proto; return new constructor(); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78481.html
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:學習,總繞不開原型,原型鏈,繼承等等這些知識。對象那么好,怎么才能找一個呸,其實是創建創建對象的方法對象字面量工廠模式構造函數模式原型模式等。原型鏈有什么用來談談繼承,繼承可以利用構造函數,使用屬性等來實現。 初學者學習javascript可能會感覺很困擾,但是你一旦真正了解了它,我相信你會愛上它。學習ECMAScript,總繞不開原型,原型鏈,繼承等等這些知識。今天把它們放在一塊兒,...
摘要:首先,需要來理清一些基礎的計算機編程概念編程哲學與設計模式計算機編程理念源自于對現實抽象的哲學思考,面向對象編程是其一種思維方式,與它并駕齊驅的是另外兩種思路過程式和函數式編程。 JavaScript 中的原型機制一直以來都被眾多開發者(包括本人)低估甚至忽視了,這是因為絕大多數人沒有想要深刻理解這個機制的內涵,以及越來越多的開發者缺乏計算機編程相關的基礎知識。對于這樣的開發者來說 J...
閱讀 874·2021-10-25 09:45
閱讀 3298·2021-09-22 14:58
閱讀 3856·2021-08-31 09:43
閱讀 919·2019-08-30 15:55
閱讀 923·2019-08-29 13:51
閱讀 1235·2019-08-29 13:02
閱讀 3490·2019-08-29 12:52
閱讀 1965·2019-08-26 13:27