寫給Java開發者看的JavaScript對象機制

幫助面向對象開發者理解關于JavaScript對象機制

本文是以一個熟悉OO語言的開發者視角,來解釋JavaScript中的對象。

對于不了解JavaScript 語言,尤其是習慣了OO語言的開發者來說,由于語法上些許的相似會讓人產生心理預期,JavaScript中的原型繼承機制和class語法糖是讓人迷惑的。

如果你已經對prototype機制已有了解,但是由于兩者對象機制的巨大(本質)差異,對它和構造函數,實例對象的關系仍有疑惑,本文或許可以解答你的問題。

我們看下面的代碼,可以看出和OO語言相比,語法上也有很大分別:

// 定義一個類
class Foo {constructor() {this.a = 'a';}
}//實例化對象
const foo = new Foo();//定義原型的屬性
Foo.prototype.b = 'b';//實例可以訪問屬性
foo.b // "b"//修改原型的屬性
Foo.prototype.b= 'B';//實例屬性值沒有被修改
foo.b // "b"

類已經定義了怎么還能修改呢?prototype又是什么?

不存在面向對象

對于熟悉了面向對象的開發者而言JS中種種非預期操作的存在,都是因為JavaScript中根本沒有面向對象的概念,只有對象,沒有類。

即使ES6新添了class語法,不意味著JS引入了面向對象,只是原型繼承的語法糖。

原型是什么

什么是原型?如果說類是面向對象語言中對象的模版,原型就是 JS中創造對象的模版。

在面向類的語言中,實例化類,就像用模具制作東西一樣。實例化一個類就意味著“把類的形態復制到物理對象中”,對于每一個新實例來說都會重復這個過程。

但是在JavaScript中,并沒有類似的復制機制。你不能創建一個類的多個實例,只能創建多個對象,它們[[Prototype]]關聯的是同一個對象。

//構造函數
function Foo(){
}
//在函數的原型上添加屬性
Foo.prototype.prototypeAttribute0 = {status: 'initial'};const foo0 = new Foo();
const foo1 = new Foo();
foo0.prototypeAttribute0 === foo1.prototypeAttribute0 //true

對象、構造函數和原型的關系

當我們創建一個新對象的時候,發生了什么,對象、構造函數和原型到底什么。

先簡單地概括:

原型用于定義共享的屬性和方法。

構造函數用于定義實例屬性和方法,僅負責創造對象,與對象不存在直接的引用關系。

我們先不用class語法糖,這樣便于讀者理解和暴露出他們之間真正的關系。

// 先創建一個構造函數 定義原型的屬性和方法
function Foo() {this.attribute0 = 'attribute0';
}

當創建了一個函數,就會為該函數創建一個prototype屬性,它指向函數原型。

所有的原型對象都會自動獲得一個constructor屬性,這個屬性的值是指向原型所在的構造函數的指針。

clipboard.png

現在定義原型的屬性和方法


Foo.prototype.prototypeMethod0 = function() {console.log('this is prototypeMethod0');
}Foo.prototype.prototypeAttribute0 = 'prototypeAttribute0';

好了,現在,新建一個對象,

const foo = new Foo();foo.attribute0 // "attribute0"
foo.prototypeAttribute0 //"prototypeAttribute0"
foo.prototypeMethod0() // this is prototypeMethod0

它擁有自己的實例屬性attribute0,并且可以訪問在原型上定義的屬性和方法,他們之間的引用關系如圖所示。

clipboard.png

當調用構造函數創建實例后,該實例的內部會包含一個指針(內部對象),指向構造函數的原型對象。

當讀取實例對象的屬性時,會在實例中先搜尋,沒有找到,就會去原型鏈中搜索,且總是會選擇原型鏈中最底層的屬性進行訪問。<!--原型對象自己也可以有原型對象,這樣就構成了原型鏈。關于原型鏈這里不作過多介紹-->

對象的原型可以通過__proto__在chrome等瀏覽器上訪問。

__proto__是對象的原型指針,prototype是構造函數所對應的原型指針。

語法糖做了什么

ES6推出了class語法,為定義構造函數和原型增加了便利性和可讀性。

class Foo {constructor(){this.attribute0 = 'attribute0';}prototypeMethod0(){console.log('this is prototypeMethod0')}
}/* 相當于下面的聲明*/
function Foo() {this.attribute0 = 'attribute0';
}Foo.prototype.prototypeMethod0 = function() {console.log('this is prototypeMethod0')
}

class中的constractor相當于構造函數,而class中的方法相當于原型上的方法。、

值得注意的特性

屬性屏蔽 —— 避免實例對象無意修改原型

看這段代碼,思考輸出的結果。

class Foo {prototypeMethod0(){console.log('this is prototypeMethod0')}
}const foo0 = new Foo();
const foo1 = new Foo();foo0.prototypeMethod0 === foo0.__proto__.prototypeMethod0 // truefoo0.prototypeMethod0 = () => console.log('foo0 method');
foo0.prototypeMethod0(); //??
foo1.prototypeMethod0(); //??
foo0.prototypeMethod0 === foo0.__proto__.prototypeMethod0 // ??

輸出的結果是

foo0.prototypeMethod0(); // foo0 method
foo1.prototypeMethod0(); // this is prototypeMethod0
foo0.prototypeMethod0 === foo0.__proto__.prototypeMethod0 // false

我們知道對象(即便是原型對象),都是運行時的。

創建之初,foo本身沒有prototypeMethod0這個屬性,訪問foo0.prototypeMethod0將會讀取foo0.__proto__.prototypeMethod0

直接修改foo0.prototypeMethod0沒有改變__proto__上的方法原因是存在屬性屏蔽

現在的情況是:想要修改foo0.prototypeMethod0prototypeMethod0foo中不存在而在上層(即foo.__proto__中存在),并且這不是一個特殊屬性(如只讀)。

那么會在foo中添加一個新的屬性。

這便是為什么直接修改卻沒有影響__proto__的原因。

<!--更多屬性屏蔽的場景也不做贅述-->

小結

再溫習一遍這些定義:

原型用于定義共享的屬性和方法。

構造函數用于定義實例屬性和方法,僅負責創造對象,與對象不存在直接的引用關系。

__proto__是對象的原型指針,prototype是構造函數的原型指針。

在解釋原型作用的文章或書籍中,我們會聽到繼承這樣的術語,其實更準確地,委托對于JavaScript中的對象模型來說,是一個更合適的術語。

委托行為意味著某些對象在找不到屬性或者方法引用時會把這個請求委托給另一個對象。對象之間的關系不是復制而是委托。


參考

《JavaScript高級程序設計》

《你不知道的JavaScript》

本文僅供解惑,要在腦袋里形成系統的概念,還是要看書呀。

有疑問歡迎大家一起討論。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/389924.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389924.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389924.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Pythonic---------詳細講解

作者&#xff1a;半載流殤 鏈接&#xff1a;https://zhuanlan.zhihu.com/p/35219750 來源&#xff1a;知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權&#xff0c;非商業轉載請注明出處。Pythonic&#xff0c;簡言之就是以Python這門語言獨特的方式寫出既簡潔又優美的代碼…

大數據ab 測試_在真實數據上進行AB測試應用程序

大數據ab 測試Hello Everyone!大家好&#xff01; I am back with another article about Data Science. In this article, I will write about what is A-B testing and how to use it on real life data-set to compare two advertisement methods.我回來了另一篇有關數據科…

492. 構造矩形

492. 構造矩形 作為一位web開發者&#xff0c; 懂得怎樣去規劃一個頁面的尺寸是很重要的。 現給定一個具體的矩形頁面面積&#xff0c;你的任務是設計一個長度為 L 和寬度為 W 且滿足以下要求的矩形的頁面。要求&#xff1a; 你設計的矩形頁面必須等于給定的目標面積。 寬度 …

node:爬蟲爬取網頁圖片

前言 周末自己在家閑著沒事&#xff0c;刷著微信&#xff0c;玩著手機&#xff0c;發現自己的微信頭像該換了&#xff0c;就去網上找了一下頭像&#xff0c;看著圖片&#xff0c;自己就想著作為一個碼農&#xff0c;可以把這些圖片都爬取下來做成一個微信小程序&#xff0c;說干…

如何更好的掌握一個知識點_如何成為一個更好的講故事的人3個關鍵點

如何更好的掌握一個知識點You’re launching a digital transformation initiative in the middle of the ongoing pandemic. You are pretty excited about this big-ticket investment, which has the potential to solve remote-work challenges that your organization fac…

centos 搭建jenkins+git+maven

gitmavenjenkins持續集成搭建發布人:[李源] 2017-12-08 04:33:37 一、搭建說明 系統&#xff1a;centos 6.5 jdk&#xff1a;1.8.0_144 jenkins&#xff1a;jenkins-2.93-1.1 git&#xff1a;git-2.9.0 maven&#xff1a;Maven 3.3.9 二、部署 2.1、jdk安裝 1&#xff09;下…

638. 大禮包

638. 大禮包 在 LeetCode 商店中&#xff0c; 有 n 件在售的物品。每件物品都有對應的價格。然而&#xff0c;也有一些大禮包&#xff0c;每個大禮包以優惠的價格捆綁銷售一組物品。 給你一個整數數組 price 表示物品價格&#xff0c;其中 price[i] 是第 i 件物品的價格。另有…

記錄一次spark連接mysql遇到的問題

在使用spark連接mysql的過程中報錯了&#xff0c;錯誤如下 08:51:32.495 [main] ERROR - Error loading factory org.apache.calcite.jdbc.CalciteJdbc41Factory java.lang.NoClassDefFoundError: org/apache/calcite/linq4j/QueryProviderat java.lang.ClassLoader.defineCla…

什么事數據科學_如果您想進入數據科學,則必須知道的7件事

什么事數據科學No way. No freaking way to enter data science any time soon…That is exactly what I thought a year back.沒門。 很快就不會出現進入數據科學的怪異方式 ……這正是我一年前的想法。 A little bit about my data science story: I am a complete beginner…

python基礎03——數據類型string

1. 字符串介紹 在python中&#xff0c;引號中加了引號的字符都被認為是字符串。 1 namejim 2 address"beijing" 3 msg My name is Jim, I am 22 years old! 那單引號、雙引號、多引號有什么區別呢&#xff1f; 1) 單雙引號木有任何區別&#xff0c;部分情況 需要考慮…

Java基礎-基本數據類型

Java中常見的轉義字符: 某些字符前面加上\代表了一些特殊含義: \r :return 表示把光標定位到本行行首. \n :next 表示把光標定位到下一行同樣的位置. 單獨使用在某些平臺上會產生不同的效果.通常這兩個一起使用,即:\r\n. 表示換行. \t :tab鍵,長度上相當于四個或者是八個空格 …

季節性時間序列數據分析_如何指導時間序列數據的探索性數據分析

季節性時間序列數據分析為什么要進行探索性數據分析&#xff1f; (Why Exploratory Data Analysis?) You might have heard that before proceeding with a machine learning problem it is good to do en end-to-end analysis of the data by carrying a proper exploratory …

TortoiseGit上傳項目到GitHub

1. 簡介 gitHub是一個面向開源及私有軟件項目的托管平臺&#xff0c;因為只支持git 作為唯一的版本庫格式進行托管&#xff0c;故名gitHub。 2. 準備 2.1 安裝git&#xff1a;https://git-scm.com/downloads。無腦安裝 2.2 安裝TortoiseGit(小烏龜)&#xff1a;https://torto…

496. 下一個更大元素 I

496. 下一個更大元素 I 給你兩個 沒有重復元素 的數組 nums1 和 nums2 &#xff0c;其中nums1 是 nums2 的子集。 請你找出 nums1 中每個元素在 nums2 中的下一個比其大的值。 nums1 中數字 x 的下一個更大元素是指 x 在 nums2 中對應位置的右邊的第一個比 x 大的元素。如果…

利用PHP擴展Taint找出網站的潛在安全漏洞實踐

一、背景 筆者從接觸計算機后就對網絡安全一直比較感興趣&#xff0c;在做PHP開發后對WEB安全一直比較關注&#xff0c;2016時無意中發現Taint這個擴展&#xff0c;體驗之后發現確實好用&#xff1b;不過當時在查詢相關資料時候發現關注此擴展的人數并不多&#xff1b;最近因為…

美團騎手檢測出虛假定位_在虛假信息活動中檢測協調

美團騎手檢測出虛假定位Coordination is one of the central features of information operations and disinformation campaigns, which can be defined as concerted efforts to target people with false or misleading information, often with some strategic objective (…

869. 重新排序得到 2 的冪

869. 重新排序得到 2 的冪 給定正整數 N &#xff0c;我們按任何順序&#xff08;包括原始順序&#xff09;將數字重新排序&#xff0c;注意其前導數字不能為零。 如果我們可以通過上述方式得到 2 的冪&#xff0c;返回 true&#xff1b;否則&#xff0c;返回 false。 示例 …

org.apache.maven.archiver.MavenArchiver.getManifest

eclipse導入新的maven項目時&#xff0c;pom.xml第一行報錯&#xff1a; org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.MavenProject, org.apache.maven.archiver.MavenArchiveConfiguration) 解決辦法&#xff1a; help -> Install New…

殺進程常用命令

殺進程命令pkill 進程名killall 進程名 # 平緩kill -HUP pid # 平緩kill -USR2 pidkill pid &#xff08;-9 不要使用&#xff09;轉載于:https://www.cnblogs.com/jmaly/p/9492406.html

CertUtil.exe被利用來下載惡意軟件

1、前言 經過國外文章信息&#xff0c;CertUtil.exe下載惡意軟件的樣本。 2、實現原理 Windows有一個名為CertUtil的內置程序&#xff0c;可用于在Windows中管理證書。使用此程序可以在Windows中安裝&#xff0c;備份&#xff0c;刪除&#xff0c;管理和執行與證書和證書存儲相…