目錄
建構函數本身就是一個函數,與普通函數沒有任何區別,不過
2.2 proto(隐式原型)
2.3 constructor
补充,易错点
首頁 web前端 js教程 不可錯過的從原型到原型鏈,修練JavaScript內功

不可錯過的從原型到原型鏈,修練JavaScript內功

Mar 17, 2021 am 10:12 AM
javascript 原型 原型鏈

不可錯過的從原型到原型鏈,修練JavaScript內功

  • 前言
  • 一、建構子
  • #二、原型
  • 三、實例與原型
  • 四、原型的原型
  • 五、原型鏈
  • 六、總結
  • 寫在最後

(免費學習推薦:

javascript影片教學

前言

不可錯過的從原型到原型鏈,修練JavaScript內功

又到了回憶過去的時候了,知識就是這樣,原型和原型鏈在我之前的實習生涯中用到的很少——幾乎沒有(噗!我菜我攤牌了),但是它和this指向問題一樣,是初級、中級前端開發在面試時永遠繞不開的話題。是不是大家每次看面經的時候都會去搜尋原型相關的知識點?

你看這知識,總是在考的時候,才能知道它的重要,就好像曾經有一段賊拉真摯的面試題擺在我面前…話題拉回來,今天我們就收了這個孽障

一、建構子

#1.1 什麼是建構子?

建構函數本身就是一個函數,與普通函數沒有任何區別,不過
為了規範一般將其首字母大寫

。建構子和普通函數的差別在於,使用new產生實例的函數就是建構函數,直接呼叫的就是普通函數。

function Person() {
	this.name = 'yuguang';};var person = new Person();console.log(person.name) // yuguang
登入後複製

在這個例子中,Person 就是一個建構子。 不可錯過的從原型到原型鏈,修練JavaScript內功
1.2 constructor?

constructor 傳回建立實例物件時建構函數的參考。此屬性的值是對函數本身的引用,而不是一個包含函數名稱的字串。

可以看到實例物件的constructor指向了它的建構函數,而它和原型的關係我們在之後會連結在一起。 1.3 都有哪些資料型別或函式擁有constructor呢? 在JavaScript中,每個具有原型的物件都會自動獲得constructor屬性。除了:argumentsEnumeratorErrorGlobalMathRegExp等在一些特殊物件之外,其他所有的JavaScript內建物件都具備constructor屬性。例如:ArrayBooleanDate

Function
Number

Object
  • String等。所有主流瀏覽器均支援該屬性。開啟控制台我們可以驗證一下
    // 字符串console.log('str'.constructor) // ƒ String() { [native code] }console.log('str'.constructor === String) // true// 数组console.log([1,2,3].constructor) // ƒ Array() { [native code] }console.log([1,2,3].constructor === Array) // true// 数字var num = 1console.log(num.constructor) // ƒ Number() { [native code] }console.log(num.constructor === Number) // true// Dateconsole.log(new Date().constructor) // ƒ Date() { [native code] }// 注意!!!不要混淆哦console.log(new Date().getTime().constructor) // ƒ Number() { [native code] }// Booleanconsole.log(true.constructor) // ƒ Boolean() { [native code] }console.log(true.constructor === Boolean) // true// 自定义函数function show(){
    	console.log('yuguang');};console.log(show.constructor) // ƒ Function() { [native code] }// 自定义构造函数,无返回值function Person(){
    	this.name = name;};var p = new Person()console.log(p.constructor) // ƒ Person()// 有返回值function Person(){
    	this.name = name;
    	return {
    		name: 'yuguang'
    	}};var p = Person()console.log(p1.constructor) // ƒ Object() { [native code] }
    登入後複製
  • 1.4 模擬實作一個new
  • 既然建構函式與普通函式的差別只在於呼叫方式上,我們就應該了解new。

當呼叫

new運算子時,該函數總是會傳回一個物件;

通常情況下,建構器裡的this就指向傳回的這個物件;

不可錯過的從原型到原型鏈,修練JavaScript內功

程式碼如下:

通常情况下var MyClass = function(){
	this.name = 'yuguang';};var obj = new MyClass();obj.name; // yuguang特殊情况var MyClass = function(){
	this.name = 'yuguang';
	return {
		name: '老王'
	}};var obj = new MyClass();obj.name // 老王
登入後複製
我們利用__proto__(隱含原型,下文會提到)屬性來模擬new 呼叫建構子的過程:
var objectNew = function(){
    // 从object.prototype上克隆一个空的对象
    var obj = new Object(); 
    // 取得外部传入的构造器,这里是Person
    var Constructor = [].shift.call( arguments );
    // 更新,指向正确的原型
    obj.__proto__ = Constructor.prototype; //知识点,要考、要考、要考 
    // 借用外部传入的构造器给obj设置属性
    var ret = Constructor.apply(obj, arguments);
    // 确保构造器总是返回一个对象
    return typeof ref === 'object' ? ret : obj;}
登入後複製

二、原型

2.1 prototype(顯式原型)
不可錯過的從原型到原型鏈,修練JavaScript內功JavaScript 是一種基於原型的語言(prototype-based language),在設計的時候模仿了Java的兩組型別機制:
基本型別

    物件型別
  • 。可見原型很重要! 每個對像都擁有一個原型對象,類別是以函數的形式來定義的。 prototype表示該函數的原型,也表示一個類別的成員的集合。看下圖:
  • 可以發現Person函數自己的原型都有什麼:

#constructor

(Person.prototype.constructor => Person )

不可錯過的從原型到原型鏈,修練JavaScript內功

__proto__

(我們稱它為隱式原型)

######此時我們得到了第一張表示建構子和實例原型之間的關係圖:###############那我們該怎麼表示實例與建構子原型,也就是person 與Person.prototype 之間的關係呢,這時候我們就要講到第二個屬性:###
2.2 proto(隐式原型)

这是每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这是一个访问器属性(即 getter 函数和 setter 函数),通过它可以访问到对象的内部[[Prototype]] (一个对象或 null )。

function Person() {}var person = new Person();console.log(person.__proto__ === Person.prototype); // true
登入後複製

于是我们更新下关系图:

不可錯過的從原型到原型鏈,修練JavaScript內功

小结: 每个引用类型的隐式原型都指向它的构造函数的显式原型

2.3 constructor

前文提到了constructor,它与原型的关系也可以添加到这张图里,更新下关系图:

不可錯過的從原型到原型鏈,修練JavaScript內功
根据上图的关系,下面这段的结果,大家就一目了然了:

function Person() {}var person = new Person();console.log(person.__proto__ == Person.prototype) // trueconsole.log(Person.prototype.constructor == Person) // true// 顺便学习一个ES5的方法,可以获得对象的原型console.log(Object.getPrototypeOf(person) === Person.prototype) // true
登入後複製

接下来我们要继续思考实例和原型的关系:

三、实例与原型

当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。这样一个查找过程

举个例子:

function Person() {}Person.prototype.name = '老王';var person = new Person();person.name = '余光';console.log(person.name) // 余光delete person.name;console.log(person.name) // 老王
登入後複製

在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 余光(is me)。

描述:

但是当我们删除了 person 的 name 属性后,再次读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.proto ,也就是 Person.prototype中查找,幸运的是我们找到了 name 属性,结果为 老王(这…)

总结:

  • 尝试遍历实例a中的所有属性,但没有找到目标属性;
  • 查找name属性的这个请求被委托给该实例a的构造器(A)的原型,它被a.__proto__ 记录着并且指向A.prototype;
  • A.prototype存在目标属性,返回他的值;

但是万一还没有找到呢?原型的原型又是什么呢?

四、原型的原型

在前面,我们已经讲了原型也是一个对象,既然是对象,我们就可以用最原始的方式创建它,那就是:

var obj = new Object();obj.name = '余光'console.log(obj.name) // 余光
登入後複製

其实原型对象就是通过Object构造函数生成的,结合之前所讲,实例的 __proto__ 指向构造函数的 prototype ,可以理解成,Object.prototype()是所有对象的根对象,所以我们再次更新下关系图:

不可錯過的從原型到原型鏈,修練JavaScript內功

五、原型链

每个对象拥有一个原型对象,通过 __proto__ 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null这种关系被称为原型链 (prototype chain),通过原型链一个对象会拥有定义在其他对象中的属性和方法。

这个链条存在着终点,是因为:Object.prototype 的原型是——null,引用阮一峰老师的 《undefined与null的区别》 就是:

null 表示“没有对象”,即该处不应该有值。这句话也意味着 Object.prototype 没有原型
登入後複製

我们最后更新一次关系图,蓝色线条就可以表示原型链这种关系。

不可錯過的從原型到原型鏈,修練JavaScript內功

补充,易错点

1.constructor
首先是 constructor 属性,我们看个例子:

function Person() {}var person = new Person();console.log(person.constructor === Person); // true
登入後複製

当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:

person.constructor === Person.prototype.constructor
登入後複製

2.__proto__

其次是 proto ,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.proto 时,可以理解成返回了 Object.getPrototypeOf(obj)。

3.真的是继承吗?

最后是关于继承,前面我们讲到“每一个对象都会从原型‘继承’属性”,实际上,继承是一个十分具有迷惑性的说法,引用《你不知道的JavaScript》中的话,就是:

繼承意味著複製操作,然而JavaScript 預設並不會複製物件的屬性,相反,JavaScript 只是在兩個物件之間建立一個關聯,這樣,一個物件就可以透過委託存取另一個物件的屬性和函數,所以與其叫繼承,委託的說法反而更準確些。

六、總結

  • 使用new#產生實例的函數就是建構函數,直接呼叫的就是普通函數;
  • 每個物件都擁有一個原型物件;
  • 每個引用類型的隱式原型都指向它的建構子的明確原​​型;
  • Object.prototype是所有物件的根物件;
  • 原型鏈存在終點,不會無限地尋找下去;

#相關免費學習推薦:javascript(影片)

以上是不可錯過的從原型到原型鏈,修練JavaScript內功的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1659
14
CakePHP 教程
1415
52
Laravel 教程
1310
25
PHP教程
1258
29
C# 教程
1232
24
如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

如何在JavaScript中取得HTTP狀態碼的簡單方法 如何在JavaScript中取得HTTP狀態碼的簡單方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務

See all articles