要理解JS中的prototype, 首先必須先弄清楚下列幾個概念
1. JS中所有的東西都是物件
2. JS中所有的東西都是由Object衍生而來, 即所有東西原型鏈的終點指向Object.prototype
// ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", // "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", // "__lookupSetter__"] console.log(Object.getOwnPropertyNames(Object.prototype));
3. JS中建構子與實例(物件)之間的微妙關係
建構函數透過定義prototype來約定其實例的規格, 再透過 new 來建構出實例, 他們的作用就是生產物件.
而建構函數(方法)本身又是方法(Function)的實例, 因此也可以查到它的__proto__(原型鏈)
Object / function F() {} 這樣子的是建構子囉, 一個是JS原生API提供的, 一個是自訂的
new Object() / new F() 外觀的則為實例囉
實例就"只能"查看__proto__來得知自己是基於什麼prototype被製造出來的,
而"不能"再重新定義實例的prototype妄想創造出實例的實例了.
實踐真知, 只有自己動手觀察/思考才能真正領悟:
// 先来看看构造函数到底是什么 // function Empty() {} function Empty() {} console.log(Function.prototype, Function.__proto__); // Object {} function Empty() {} console.log(Object.prototype, Object.__proto__); function F() {} // F {} function Empty() {} console.log(F.prototype, F.__proto__);
你可能已經暈了, 我們來分解一下。
prototype
prototype輸出的格式為: 建構子名 原型
先看下Object.prototype輸出了什麼?
Object {} -> 前面的Object為建構子的名稱, 後面的那個表示原型, 這裡是一個{}, 即一個Object物件的實例(空物件)
那麼 F {} 我們就明白是什麼意思了, F 就是建構函數的名稱, 原型也是一個空物件
// 再来看看由构造函数构造出来的实例 var o = new Object(); // var o = {}; // undefined Object {} console.log(o.prototype, o.__proto__); function F() {} var i = new F(); // undefined F {} console.log(i.prototype, i.__proto__);
我們再深入一點, 定義下 F 的原型看看到底會發生些什麼?
function F() {} F.prototype.a = function() {}; var i = new F(); // undefined F {a: function} console.log(i.prototype, i.__proto__);
這樣我們就清楚的看到 i 是由 F 構造出來的, 原型是 {a: function}, 就是原本的空對象原型新增了一個 a 方法
我們再換一個情況, 完全覆蓋 F 的原型會怎麼樣?
function F() {} F.prototype = { a: function() {} }; var i = new F(); // undefined Object {a: function} console.log(i.prototype, i.__proto__);
咦~ 為什麼這裡顯示 i 是由 Object 建構出來的? 不對吧!
因為我們完全將 F 的prototype覆蓋, 其實也就是將原型指定為物件{a: function}, 但這會造成原本的constructor資訊遺失, 變成了物件{a: function}指定的constructor.
那麼物件{a: function}的constructor是什麼呢?
因為物件{a: function}其實相對於
var o = {a: function() {}} // new了一个Object
那麼o的constructor當然是 Object 啦
我們來修正下這個錯誤
function F() {} F.prototype = { a: function() {} } // 重新指定正确的构造函数 F.prototype.constructor = F; var i = new F(); // undefined F {a: function, constructor: function} console.log(i.prototype, i.__proto__);
現在又能得到正確的原型資訊了~
原型鏈
然後來看看什麼原型鏈又是什麼東西?
簡單的來講和OOP中的繼承關係(鏈)是一樣的, 一層一層往上找, 直至最終的 Object.prototype
最關鍵的是要弄清楚JS中哪些東西是(實例)物件, 這個簡單了, JS中所有東西都是物件!
再要弄清楚就是任何一個物件都是有一個原型的!
那我們來證明一下:
Object // 这是一个函数, 函数是 Function 的实例对象, 那么就是由 Function 构造出来的 Object.__proto__ == Function.prototype // 那么Object的原型, true // 这个是一个普通对象了, 因此属于 Object 的实例 Function.prototype.__proto__ == Object.prototype // true // 这已经是原型链的最顶层了, 因此最终的指向 null Object.prototype.__proto__ == null // true Function // 这也是一个函数, 没错吧! Function.__proto__ == Function.prototype // true function A() {} // 这是一个自定义的函数, 终归还是一个函数, 没错吧! A.__proto__ == Function.prototype // 任何函数都是 Function 的实例, 因此A的原型是? var a = new A() a.__proto__ == A.prototype // 实例a是由A构造函数构造出来的, 因此a的原型是由A的prototype属性定义的 A.prototype.__proto__ == Object.prototype // 普通对象都是 Object 的示例
Prototype和__proto__
每個物件都包含一個__proto__,指向這個的物件的「原型」。
類似的事情是,每一個函數都包含一個prototype,這個prototype物件幹什麼的了?
咱們看看如下程式碼,用建構函式來建立一個物件(上面是用字面量的形式建立物件)。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__);
試想想,這個foo物件的__proto__會指向什麼?
一個包含constructor屬性的物件?看不太懂沒關係,把函數Foo的prototype屬性印出來,比較一下就知道了。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__); console.log(Foo.prototype); console.log(foo.__proto__ === Foo.prototype);
原來,new出來的物件foo的__proto__就只指向函數Foo的prototype。
foo.__proto__ --> Foo.prototype
JS这么设计有何意义了?回忆下上面说的,在JS的世界中,对象不是根据类(模具)创建出来的,而是从原型(另一个对象)衍生出来的。
当我们执行new操作创建一个新的对象时,先不深入new操作的具体实现,但有一点我们是肯定的——就是为新对象的__proto__指向一个原型对象。
就刚才这段代码
function Foo(){}; var foo = new Foo();
foo.__proto__到底要指向谁了?你怎么不能指向Foo这个函数本身吧,虽然函数也是对象,这个有机会会详细讲。但如何foo.__proto__指向Foo固然不合适,因为Foo是一个函数,有很多逻辑代码,foo作为一个对象,继承逻辑处理没有任何意义,它要继承的是“原型对象”的属性。
所以,每个函数会自动生成一个prototype对象,由这个函数new出来的对象的__proto__就指向这个函数的prototype。
foo.__proto__ --> Foo.prototype
总结
说了这么多,感觉还是没完全说清楚,不如上一张图。我曾经参考过其他网友的图,但总觉得哪里没说清楚,所以我自己画了一张图,如果觉得我的不错,请点个赞!(老子可是费了牛劲才画出来)。
咱们就着这张图,记住如下几个事实:
1. 每个对象中都有一个_proto_属性。
JS世界中没有类(模具)的概念,对象是从另一个对象(原型)衍生出来的,所以每个对象中会有一个_proto_属性指向它的原型对象。(参考左上角的那个用字面量形式定义的对象obj,它在内存中开辟了一个空间存放对象自身的属性,同时生成一个_proto_指向它的原型——顶层原型对象。)
2. 每个函数都有一个prototype属性。
“构造函数”为何叫构造函数,因为它要构造对象。那么根据上面第一条事实,构造出来的新对象的_proto_属性指向谁了?总不能指向构造函数自身,虽然它也是个对象,但你不希望新对象继承函数的属性与方法吧。所以,在每个构造函数都会有一个prototype属性,指向一个对象作为这个构造函数构造出来的新对象的原型。
3. 函数也是对象。
每个函数都有一些通用的属性和方法,比如apply()/call()等。但这些通用的方法是如何继承的呢?函数又是怎么创建出来的呢?试想想,一切皆对象,包括函数也是对象,而且是通过构造函数构造出来的对象。那么根据上面第二条事实,每个函数也会有_proto_指向它的构造函数的prototype。而这个构造函数的函数就是Function,JS中的所有函数都是由Function构造出来的。函数的通用属性与方法就存放在Function.prototype这个原型对象上。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

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

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能