亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

再談javascriptjs原型與原型鏈及繼承相關問題

發布時間:2020-06-27 04:43:44 來源:網絡 閱讀:234 作者:周陸軍 欄目:web開發

什么是原型語言 

  1. 只有對象,沒有類;對象繼承對象,而不是類繼承類。 

  2. “原型對象”是核心概念。原型對象是新對象的模板,它將自身的屬性共享給新對象。一個對象不但可以享有自己創建時和運行時定義的屬性,而且可以享有原型對象的屬性。 

  3. 每一個對象都有自己的原型對象,所有對象構成一個樹狀的層級系統。root節點的頂層對象是一個語言原生的對象,只有它沒有原型對象,其他所有對象都直接或間接繼承它的屬性。 

原型語言創建有兩個步驟 

  1. 使用”原型對象”作為”模板”生成新對象 :這個步驟是必要的,這是每個對象出生的唯一方式。以原型為模板創建對象,這也是”原型”(prototype)的原意。 

  2. 初始化內部屬性 :這一步驟不是必要的。通俗點說,就是,對”復制品”不滿意,我們可以”再加工”,使之獲得不同于”模板”的”個性”。 

所以在JavaScript的世界里,萬物皆對象這個概念從一而終。

js高級---本地對象、內置對象、宿主對象



全局對象:一般全局對象會有兩個,一個是ecma提供的Global對象,一個是宿主提供。如在瀏覽器中是window、在nodejs中是global。【所以啊,在瀏覽器中全局對象Global+window】

通常情況下ecma提供的Global對象對是不存在的,沒有具體的對象

宿主對象-host object:即由 ECMAScript 實現的宿主環境提供的對象,包含兩大類,一個是宿主提供,一個是自定義類對象,ECMAScript官方未定義的對象都屬于宿主對象,所有非本地對象都是宿主對象。宿主提供對象原理--->由宿主框架通過某種機制注冊到ECscript引擎中的對象,如宿主瀏覽器(以遠景為參考)會向ECscript注入window對象,構建其實現javascript。

內置對象-Build-in object:由 ECMAScript 實現提供的、獨立于宿主環境的所有對象,在 ECMAScript 程序開始執行時出現,即在引擎初始化階段就被創建好的對象。這意味著開發者不必明確實例化內置對象,它已被實例化了Global(全局對象)、Math、JSON

基本包裝類型對象:ECMAScript還提供了3個特殊的引用類型: Boolean、Number、String。這些類型與其他內置對象類型相似,但同時具有各自的基本類型相應的特殊行為。實際上,每當讀取一個基本類型值得時候,后臺就會創建一個對應的基本包裝類型的對象,從而讓我們能夠調用一些方法來操作這些數據 包裝類型,是一個專門封裝原始類型的值,并提供對原始類型的值執行操作的API對象

其他內置對象與基本包裝類型對象的區別?

普通的內置對象與基本包裝類型的主要區別就是對象的生命期,使用new操作符創建的引用類型的實例,在執行流離開當前作用域之前都一直保存在內存中,而自動創建的基本包裝類型的對象,則只是存在于一行代碼的執行瞬間,然后立即被立即銷毀。這意味著我們不能再運行時為基本包裝類型值添加屬性和方法。

var s1="some text"; s1.color="red"; var s2=new String("some text"); s2.color="red"; console.log(s1.color);//undefined console.log(s2.color);//red console.log(s1==s2);//true console.log(s1===s2);//false

在第二行為s1添加一個color屬性,第三行代碼執行時,再次訪問s1,結果s1的color屬性被銷毀了。詳情推薦閱讀《JavaScript內置對象--基本包裝類型(Boolean、Number、String)詳解》

原生對象-native object:也叫內部對象、本地對象。獨立于宿主環境的ECMAScript實現提供的對象。與宿主無關,在javascript(遠景瀏覽器)、nodejs(node平臺)、jscript(ie瀏覽器)、typescript(微軟平臺)等等中均有這些對象。簡單來說,本地對象就是 ECMA-262 定義的類(引用類型)。

Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError、Global

在運行過程中動態創建的對象,需要new,以Number為例:

var n1=Number('1'); var n2=1; n2.xxx=2;console.log(n2); //undefined console.log(n1===n2)//false console.log(n1.toString()===n2.toString())//true console.log(n1.__proto__===Number)//false console.log(n2.__proto__===Number)//false console.log(n1.__proto__===n2.__proto__)//true

n1和n2雖然數值都是1,但n2的類型屬于'object',n1則為'number',身為基本類型number的n1直接指向了數字1,而n2指向了一個地址,這個地址中存放了數值1,這就是對象和基本類型的區別。

再談javascriptjs原型與原型鏈及繼承相關問題

但是原型對象只存在于函數對象。也就是本質上只要是通過new Function創建的函數對象會有一個原型對象

而對于其他非Function的引用類型歸根結底也是通過new Function創建的

如上面提到的Array類型、Object類型。

實際上,在每個函數對象創建的時候,都會自帶一個prototype的屬性,這個屬性相當于一個指針,指向他本身的原型對象,這個原型對象里包含著自定義的方法屬性,

function a(){       this.name='xiaoming';       this.sayName=function () {           console.log(this.name);       }   }

在默認情況下,a.prototype下會帶有一個constructor屬性,這個屬性指向創建當前函數對象的構造函數,比如這里

constructor指向構造函數a本身也就是說:a.prototypr.constructor==a   //true

另外默認還有一個_proto_屬性,這個屬性指向由創建這個函數對象的引用類型中繼承而來的屬性和方法。

當通過構造函數實例化一個對象b時,即new a();

首先這個new出來的對象屬于普通對象,所以沒有prototype屬性。但他有_proto_這個屬性,這個屬性指向創建它的引用類型的原型對象,在這個例子中指向a.prototype,從而繼承來自引用類型a的屬性和方法。推薦閱讀《JS 的 new 到底是干什么的?》

var 對象 = new 函數對象 這個聲明形式可以引申出:

函數.__proto__ ===Function.prototype Function.__proto__ === Function.prototype Object.__proto__ === Function.prototype //Objec也是個函數,函數都是由Function構造出來的。 Number.__proto__ === Function.prototype 構造函數.prototype.__proto__ ===Object.prototype Function.prototype.__proto__ ===Object.prototype Number.prototype.__proto__ ===Object.prototype Object.__proto__ .__proto__ ===null

理解了以上的關系后,'__proto__'是對象的屬性、'prototype'是函數的屬性這句話也就懂了

null是對象原型鏈的終點,其值既有(是一個對象)又無(不引用任何對象),代表著對象本源的一種混沌、虛無的狀態,正與老子《道德經》中的“道”,有著同等的意義(心中一萬只艸尼瑪奔騰而過,還是寫java爽啊)。比如:《undefined與null的區別》

再談javascriptjs原型與原型鏈及繼承相關問題

在JS中,undefined是全局對象的一個屬性,它的初始值就是原始數據類型undefined,并且無法被配置,也無法被改變。undefined從字面意思上理解為“未定義”,即表示一個變量沒有定義其值。

而null是一個JS字面量,表示空值,即沒有對象。與undefined相比,null被認為是“期望一個對象,但是不引用任何對象的值”,而undefined是純粹的“沒有值”。

// null為對象原型鏈的終點 console.log(Object.getPrototypeOf(Object.prototype)); // null // null是一個對象 console.log(typeof null); // object // null 為空 console.log(!null); // true

JS中的所有事物都是對象,對象是擁有屬性和方法的數據

為了描述這些事物,JS便有了“原型(prototype)”的概念

原型模式是js對繼承的一種實現:使用原型,能復用代碼,節省內存空間 (java類的代碼在內存只有一份,然后每個對象執行方法都是引用類的代碼,所有子類對象調用父類方法的時候,執行的代碼都是同一份父類的方法代碼。但是JS沒有類,屬性和方法都是存在對象之中,根本沒有辦法做到java那樣通過類把代碼共享給所有對象)。

推薦閱讀《深刻理解JavaScript基于原型的面向對象》

從一張圖看懂原型對象、構造函數、實例對象之間的關系

再談javascriptjs原型與原型鏈及繼承相關問題

  • prototype:構造函數中的屬性,指向該構造函數的原型對象。

  • constructor:原型對象中的屬性,指向該原型對象的構造函數

  • _proto_:實例中的屬性,指向new這個實例的構造函數的原型對象

再談javascriptjs原型與原型鏈及繼承相關問題

在JavaScript 中,每個對象都有一個指向它的原型(prototype)對象的內部鏈接。這個原型對象又有自己的原型,直到某個對象的原型為 null 為止(也就是不再有原型指向),組成這條鏈的最后一環。這種一級一級的鏈結構就稱為原型鏈(prototype chain)

要清楚原型鏈,首先要弄清楚對象

普通對象

    最普通的對象:有__proto__屬性(指向其原型鏈),沒有prototype屬性。

    原型對象(Person.prototype 原型對象還有constructor屬性(指向構造函數對象))

函數對象:

    凡是通過new Function()創建的都是函數對象。

    擁有__proto__、prototype屬性(指向原型對象)。


JavaScript 對象是動態的屬性“包”(指其自己的屬性)。JavaScript 對象有一個指向一個原型對象的鏈。當試圖訪問一個對象的屬性時,它不僅僅在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依此層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾。

再談javascriptjs原型與原型鏈及繼承相關問題

原型-顯式原型-隱式原型-共享原型鏈 

顯式原型(explicit prototype property )每一個函數在創建之后都會擁有一個名為prototype的屬性,這個屬性指向函數的原型對象。用來實現基于原型的繼承與屬性的共享。

隱式原型 (implicit prototype link) JS中任意對象都有一個內置屬性__proto__(部分瀏覽器為[[prototype]]),指向創建這個對象的函數(即構造函數)constructor的prototype。用來構成原型鏈,同樣用于實現基于原型的繼承。



再談javascriptjs原型與原型鏈及繼承相關問題

當我們「讀取」 obj.toString 時,JS 引擎會做下面的事情:

1. 看看 obj 對象本身有沒有 toString 屬性。沒有就走到下一步。

2. 看看 obj.__proto__ 對象有沒有 toString 屬性,發現 obj.__proto__ 有 toString 屬性,于是找到了

3. 如果 obj.__proto__ 沒有,那么瀏覽器會繼續查看 obj.__proto__.__proto__,如果 obj.__proto__.__proto__ 也沒有,那么瀏覽器會繼續查,obj.__proto__.__proto__.proto__

直到找到 toString 或者 __proto__ 為 null(不管你從那個屬性開始,連續引用__proto__的指針,最后輸出的那個值就是null)。

上面的過程,就是「讀」屬性的「搜索過程」。

而這個「搜索過程」,是連著由 __proto__ 組成的鏈子一直走的。

這個鏈子,就叫做「原型鏈」。


要搞清楚 valueOf / toString / constructor 是怎么來的,就要用到 console.dir 了。

再談javascriptjs原型與原型鏈及繼承相關問題

共享原型鏈(Shared prototype chain)此模式所有子對象及后代對象都共享一個原型(都是通過b.prototype=a.prototype;這種模式連接的對象),在這些后代對象上修改原型,會影響所以處在同一共享原型鏈上的所有對象。而且此模式只繼承原型鏈上的屬性和方法,通過this定義的屬性和方法無法訪問和繼承

再談javascriptjs原型與原型鏈及繼承相關問題


那么 obj.toString 和 obj2.toString 其實是同一個東西,也就是 obj2.__proto__.toString。

這有什么意義呢?

如果我們改寫 obj2.__proto__.toString,那么 obj.toString 其實也會變!

這樣 obj 和 obj2 就是具有某些相同行為的對象,這就是意義所在。

如果我們想讓 obj.toString 和 obj2.toString 的行為不同怎么做呢?

直接賦值就好了:

obj.toString = function(){ return '新的 toString 方法' }

原型對象

每創建一個函數都會有一個prototype屬性,這個屬性是一個指針,指向一個對象(通過該構造函數創建實例對象的原型對象)原型對象是包含特定類型的所有實例共享的屬性和方法。原型對象的好處是,可以讓所有實例對象共享它所包含的屬性和方法

原型對象屬于普通對象。Function.prototype是個例外,它是原型對象,卻又是函數對象,作為一個函數對象,它又沒有prototype屬性。

再談javascriptjs原型與原型鏈及繼承相關問題


對象與函數

擁有了描述事物的能力,卻沒有創造事物的能力,顯然是不完整的,因此需要一個Object的生成器來進行對象的生成。


JS將生成器以構造函數constructor來表示,構造函數是一個指針,指向了一個函數

函數(function) 函數是指一段在一起的、可以做某一件事的程序。構造函數是一種創建對象時使用的特殊函數

再談javascriptjs原型與原型鏈及繼承相關問題

對象的構造函數function Object同時也是一個對象,因此需要一個能夠描述該對象的原型,該原型便是Function.prototype,函數的原型用來描述所有的函數。對象的構造函數的__proto__指向該原型。

再談javascriptjs原型與原型鏈及繼承相關問題

函數的原型本身也是對象,因此其__proto__指向了對象的原型。同樣,該對象也需要一個對應的生成器,即其構造函數function Function。

再談javascriptjs原型與原型鏈及繼承相關問題

函數的構造函數是由函數生成的一個對象,所以其原型即為函數的原型,其隱式原型也同樣為函數的原型Function.prototype。

instanceof操作符的內部實現機制和隱式原型、顯式原型有直接的關系。instanceof的左值一般是一個對象,右值一般是一個構造函數,用來判斷左值是否是右值的實例。它的實現原理是沿著左值的__proto__一直尋找到原型鏈的末端,直到其等于右值的prototype為止。

instanceof 的作用是判斷一個對象是不是一個函數的實例。比如 obj instanceof fn, 實際上是判斷fn的prototype是不是在obj的原型鏈上。所以

instanceof運算符的實質:用來檢測 constructor.prototype是否存在于參數 object的原型鏈上。

根據上圖展示的Object和Function的繼承依賴關系,我們可以通過instanceof操作符來看一下Object和Function的關系:

console.log(Object instanceof Object); // true console.log(Object instanceof Function); // true console.log(Function instanceof Object); // true console.log(Function instanceof Function); // true

函數與對象相互依存,分別定義了事物的描述方法和事物的生成方法,在生成JS萬物的過程中缺一不可。

Function instanceof Function    // true, why? Function.prototype是原型對象,卻是函數對象
  • Object特殊在Object.prototype是憑空出來的。語法上,所有的{}都會被解釋為new Object();

  • Function特殊在__proto__ == prototype。語法上,所有的函數聲明都會被解釋為new Function()。

我們來看Function和Object的特殊之處:

  1. Object是由Function創建的:因為Object.__proto__ === Funciton.prototype;

  2. 同理,Function.prototype是由Object.prototype創建的;

  3. Funciton是由Function自己創建的!

  4. Object.prototype是憑空出來的!

推薦閱讀 《JavaScript 內置對象與原型鏈結構》與《JavaScript中的難點之原型和原型鏈》

這幾句話能解釋一切關于原型方面的問題:

  1. 當 new 一個函數的時候會創建一個對象,『函數.prototype』 等于 『被創建對象.__proto__』

  2. 一切函數都是由 Function 這個函數創建的,所以『Function.prototype === 被創建的函數.__proto__』

  3. 一切函數的原型對象都是由 Object 這個函數創建的,所以『Object.prototype === 一切函數.prototype.__proto__』

推薦閱讀:《對原型、原型鏈、 Function、Object 的理解》

原型鏈是實現繼承的主要方法

先說一下繼承,許多OO語言都支持兩張繼承方式:接口繼承、實現繼承。

    |- 接口繼承:只繼承方法簽名

    |- 實現繼承:繼承實際的方法

由于函數沒有簽名,在ECMAScript中無法實現接口繼承,只支持實現繼承,而實現繼承主要是依靠原型鏈來實現。

原型鏈基本思路:

利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。


每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數想指針(constructor),而實例對象都包含一個指向原型對象的內部指針(__proto__)。如果讓原型對象等于另一個類型的實例,此時的原型對象將包含一個指向另一個原型的指針(__proto__),另一個原型也包含著一個指向另一個構造函數的指針(constructor)。假如另一個原型又是另一個類型的實例……這就構成了實例與原型的鏈條。

原型鏈基本思路(圖解):

再談javascriptjs原型與原型鏈及繼承相關問題

推薦閱讀《JS重點整理之JS原型鏈徹底搞清楚》



類-對象冒充-class

類(Class)是面向對象程序設計(OOP,Object-Oriented Programming)實現信息封裝的基礎。類是一種用戶定義類型,也稱類類型。每個類包含數據說明和一組操作數據或傳遞消息的函數。類的實例稱為對象

在ECMAScript 2015 中引入的JS類(classes)之前,要在JS中實現類便是采用原型繼承的方式。

當把一個函數作為構造函數,使用new關鍵字來創建對象時,便可以把該函數看作是一個類,創建出來的對象則是該類的實例,其隱式原型__proto__指向的是該構造函數的原型。


在訪問該對象的屬性或方法時,JS會先搜索該對象中是否定義了該屬性或方法,若沒有定義,則會回溯到其__proto__指向的原型對象去搜索,若仍然未搜索到,則會繼續回溯該原型的原型,直到搜索到原型鏈的終點null;


這種特性可以理解為:構造函數生成的實例,繼承于該構造函數的原型


得益于這種特性,我們可以使用定義構造函數的方式來定義類。

再談javascriptjs原型與原型鏈及繼承相關問題

function Person() {} // 定義Person構造函數 // 通常以大寫字母開頭來定義類名 console.log(new Person() instanceof Person); // true

以上定義了Person類,該構造函數是由Function構造而來,所以其隱式原型指向函數的原型,而為了描述該事物,同時生成了該類的原型Person.prototype,該原型又是由Object構造而來,所以其隱式原型指向了對象的原型。

后記:文字有點亂,就是多篇文章的精華提煉。發現把一個自己懂的事情,深入淺出講明白,并非易事。文有不妥之處,請留言告知,謝謝。

文章首發于:https://www.zhoulujun.cn/html/webfront/ECMAScript/js/2015_0715_119.html,如果不妥之處,請到官網留言,謝謝!

參考文字:

【道生萬物】理解Javascript原型鏈

js高級---本地對象、內置對象、宿主對象

js原型與原型鏈

「每日一題」什么是 JS 原型鏈?

JS理解原型、原型鏈

一張圖弄清Javascript中的原型鏈、prototype、__proto__的關系

js中的原型、原型鏈、繼承模式

說說原型(prototype)、原型鏈和原型繼承

淺談JS原型和原型鏈

原型語言解釋

基于類 vs 基于原型


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新宁县| 射阳县| 明光市| 林芝县| 皋兰县| 闸北区| 博客| 武隆县| 洛宁县| 塘沽区| 遵义县| 乾安县| 丹凤县| 安国市| 都昌县| 富宁县| 新营市| 呼玛县| 安远县| 长沙县| 叙永县| 类乌齐县| 左云县| 辽宁省| 湘潭市| 安阳县| 漳平市| 济宁市| 乳山市| 佳木斯市| 青岛市| 尚志市| 云梦县| 江阴市| 西青区| 青川县| 象山县| 平山县| 林口县| 肃北| 汝州市|