摘要:那么也一并被刪除了。然后我們基本就沒法寫代碼了不存在,因為沒有定義過啊的意義就是把共有屬性預先定義好,給之后的對象用。
本文為饑人谷講師方方原創文章。
你的 JS 代碼還沒運行的時候,JS 環境里已經有一個 window 對象了
window 對象有一個 Object 屬性,window.Object 是一個函數對象
window.Object 這個函數對象有一個重要屬性是 prototype,干什么用的等會說
window.Object.prototype 里面有這么幾個屬性 toString(函數)、valueOf(函數)
好,目前先知道這些就夠了。
然后我們寫一句代碼
var obj = {} obj.toString()
這句代碼做了啥?為什么 obj 有 toString() 屬性?
這句話大概是讓 obj 變量指向一個空對象,這個空對象有個 proto 屬性指向 window.Object.prototype。
這樣你在調用 obj.toString() 的時候,obj 本身沒有 toString,就去 obj.__proro__ 上面去找 toString。
所以你調用 obj.toString 的時候,實際上調用的是 window.Object.prototype.toString
那么 window.Object.prototype.toString 是怎么獲取 obj 的內容的呢?
那是因為 obj.toString() 等價于 obj.toString.call(obj)
同時 obj.toString.call(obj) 等價于 window.Object.prototype.toString.call(obj)
這句話把 obj 傳給 toString 了。
再看復雜一點的回到第一幅圖
我們寫一句代碼
var arr = [] arr.push(1) // [1]
請問這兩句話做了什么?
看紅色部分,var arr = [] 大概會讓 arr 指向一個空對象,然后 arr.__proto__ 指向 window.Array.prototype。(其實 arr 有一個 length:0,不過這里就忽略吧)
這樣你在調用 arr.push 的時候,arr 自身沒有 push 屬性,就去 arr.__proto__ 上找 push
因此 arr.push 實際上是 window.Array.prototype.push
arr.push(1) 等價與 arr.push.call(arr,1)
arr.push.call(arr,1) 等價于 window.Array.prototype.push.call(arr, 1)
再再復雜一點arr.valueOf() 做了什么?
arr 自身沒有 valueOf,于是去 arr.__proto__ 上找
arr.__proto__ 只有 pop、push 也沒有 valueOf,于是去 arr.__proto__.__proto__ 上找
arr.__proto__.__proto__ 就是 window.Object.prototype
所以 arr.valueOf 其實就是 window.Object.prototype.valueOf
arr.valueOf() 等價于 arr.valueOf.call(arr)
arr.valueOf.call(arr) 等價于 window.Object.prototype.valueOf.call(arr)
看,JavaScript 其實很優美很簡單。
只是你想復雜了而已:
prototype 指向一塊內存,這個內存里面有共用屬性
proto 指向同一塊內存
prototype 和 proto 的不同點在于
prototype 是構造函數的屬性,而 proto 是對象的屬性
難點在于……構造函數也是對象!
如果沒有 prototype,那么共用屬性就沒有立足之地
如果沒有 __proto__,那么一個對象就不知道自己的共用屬性有哪些。
反證法假設我們把 proto 去掉,那么
var obj = {} obj.toString() // 報錯,沒有 toString 方法
所以你只能這樣聲明一個對象咯:
var obj = { toString: window.Object.prototype.toString, valueOf: window.Object.ptototype.valueOf } obj.toString() // "[object Object]"
知道 proto 幫你省多少代碼了嗎?
假設我們刪掉 prototype,包括 window.Object.prototype 和 window.Array.prototype。
那么 window.Object.prototype.toString 也一并被刪除了。
然后我們基本就沒法寫代碼了……
var obj = {} obj.toString() // toString 不存在,因為 toString 沒有定義過啊
prototype 的意義就是把共有屬性預先定義好,給之后的對象用。
自己想想吧~
新人搞不懂原型大抵是因為
不懂內存、引用
不懂鏈表、樹等數據結構
不知道函數是一種對象
被 Java 的 class 關鍵字毒害了
還有一種可能是因為沒遇到我方應杭:
「每日一題」什么是 JS 原型鏈?
JS 的 new 到底是干什么的?
this 的值到底是什么?一次說清楚
以上是「方三篇」新人一定要看哦。
想看視頻版本可以購買我的網課(收費):
JS 深入淺出 - 寫代碼啦!
這幅圖我還可以繼續講,把 JS 所有基礎知識都能串起來。
比如很多人不懂什么是偽數組,很簡單:
如果一個數組的 proto 直接或間接指向 Array.prototye(用到了數組的共用屬性),那么就是真數組
如果一個數組的 proto 沒有直接或間接指向 Array.prototye,那么就是偽數組
var realArr = {0: "a", 1:"b", length: 2} realArr.__proto__ = Array.prototye // 這就是真數組 // 等價于 realArr = ["a", "b"] realArr.push !== undefined // true var fakeArr = {0: "a", 1:"b", length: 2} // 這就是偽數組 realArr.push === undefined // true
完。
加微信號: astak10或者長按識別下方二維碼進入前端技術交流群 ,暗號:寫代碼啦
每日一題,每周資源推薦,精彩博客推薦,工作、筆試、面試經驗交流解答,免費直播課,群友輕分享... ,數不盡的福利免費送
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107396.html
首先明確兩個概念: 構造函數和 instance 分別是什么 構造函數JS 中并沒有在語法層面上面區分構造函數和普通函數, 唯一的區別是調用方式使用 new 調用的函數就是構造函數, 沒有則是普通函數. 實例new Constructor() 返回的對象稱為 Constructor 的一個實例 然后提出一個規則:在構造函數的原型上面附加的屬性或者方法, 可以被其所有的實例共用. 可以推導出: ...
摘要:另外常說的的構造函數,就是指這個。按照理解,可能會這樣的疑問指向構造函數再次提醒,是一個對象的,所以這個對象的構造函數是它自己自己創建自己么額。。。 本文由用途意義,進行腦測解析,從需求角度走一遍原型鏈的發展。 用對象模擬類的繼承 js中沒有類(沒有類,沒有類,重要的事情說3遍)只有對象,怎么才能做到繼承的效果? var a={x:1} var b={}; b.__proto__=a...
摘要:上面的代碼,運行以后,我們可以看到因為的原型是指向的實例上的,所以可以訪問他的屬性值,那如果我不想讓訪問的構造函數里聲明的屬性值,那怎么辦呢只需要將指向的原型而不是實例就行了。 走在前端的大道上 本篇將自己讀過的相關 javascript原型和原型鏈 文章中,對自己有啟發的章節片段總結在這(會對原文進行刪改),會不斷豐富提煉總結更新。 文章——深入理解javascript之原型 一般的...
摘要:原型鏈首先,的對象普通對象和函數對象都會有屬性,指向創建它的構造函數的原型對象,比如上面的例子這就形成了原型鏈,會一直查找原型對象的屬性,直到為。,保證原型鏈能夠正常結束。 前言 一般談到js中的繼承的時候,一定會遇到原型,原型鏈的問題,原型里面又有prototype,__proto__,constructor屬性,講到這兒,很多同學是不是都一頭霧水,傻傻分不清楚,因為工作中用到的地方...
閱讀 1104·2021-09-22 15:37
閱讀 1131·2021-09-13 10:27
閱讀 2466·2021-08-25 09:38
閱讀 2445·2019-08-26 11:42
閱讀 1524·2019-08-26 11:39
閱讀 1554·2019-08-26 10:58
閱讀 2317·2019-08-26 10:56
閱讀 2569·2019-08-23 18:08