摘要:根據(jù)定義,沒(méi)有原型,并作為這個(gè)原型鏈中的最后一個(gè)環(huán)節(jié)。偷偷貼在這里再知道了原型原型鏈,那一個(gè)對(duì)象的過(guò)程知道嗎,能手寫(xiě)一個(gè)嗎。
似乎生活中常常會(huì)遇到這種情況,你去一家公司面試,前面面的都挺好,你覺(jué)得你對(duì)基礎(chǔ)算法的了解很好,各種排序,紅黑樹(shù),二叉樹(shù),深度/廣度優(yōu)先算法都答出來(lái)了,leetcode上的若干困難題目也都答上來(lái)了,然后面試官說(shuō),"那么好吧,介紹一下你對(duì)原型的看法吧。"
???我頭發(fā)。我leetcode上刷了100天,我費(fèi)勁心思研究了各種算法和數(shù)據(jù)結(jié)構(gòu),你叫我講講原型?
為了應(yīng)對(duì)這種情況,本文通過(guò)如下代碼展示下js的原型僅供參考。
上CODEconst c = (...v) => console.log(...v); function People(name, age) { this.name = name; this.age = age; } /*你想這么寫(xiě)也沒(méi)關(guān)系 const People = function(name, age) { this.name = name; this.age = age; } */ People.prototype.info = function() { c(`My name is ${this.name}, my age is ${this.age}.`); }; // 在原型上定義方法 function Student(name, age, school) { People.call(this, ...arguments); this.school = school; } Student.prototype = People.prototype; // 這里推薦用new People(),直接指定People.prototype會(huì)污染People原型,如下結(jié)果 Student.prototype.constructor = Student; //修正constructor指向 Student.prototype.talk = function() { c(`My school is ${this.school}`); }; // 需要在改變了Student的原型后定義,否則無(wú)法獲取到該方法 const xiaoD = new Student("xiaoD", 4, "小星星幼兒園"); xiaoD.info(); xiaoD.talk(); const somebody = new People("somebody", 22); somebody.talk(); c(xiaoD.__proto__ === Student.prototype); c(Student.__proto__ === Function.prototype); c(Function.prototype === Function.__proto__); c(Function.__proto__ === Object.__proto__); c(Object.__proto__ === Function.prototype); c(Object.prototype === Function.prototype.__proto__); c(Object.prototype.__proto__ === null);
可以先猜一下是什么結(jié)果。。
好吧,不用猜了。結(jié)果如下
My name is xiaoD, my age is 4. My school is 小星星幼兒園 My school is undefined true true true true true true true
每個(gè)實(shí)例對(duì)象( object )都有一個(gè)私有屬性(稱之為 proto )指向它的原型對(duì)象( prototype )。該原型對(duì)象也有一個(gè)自己的原型對(duì)象( proto ) ,層層向上直到一個(gè)對(duì)象的原型對(duì)象為 null。根據(jù)定義,null 沒(méi)有原型,并作為這個(gè)原型鏈中的最后一個(gè)環(huán)節(jié)。至于誰(shuí)指誰(shuí),應(yīng)該從上面的代碼中就可以清晰的看出來(lái)了。這里注意的是只有函數(shù)中才有 prototype 屬性。
類的繼承class People { constructor(name, age) { this.name = name; this.age = age; } info() { c(`My name is ${this.name}, my age is ${this.age}.`); } } class Student extends People { constructor(name, age, school) { super(...arguments); // 繼承屬性 this.school = school; this.talk = this.talk.bind(this); // 綁定this /* 或者這樣綁定 this.talk = () => { this.info(); // 箭頭函數(shù)中的this在定義時(shí)綁定 c(`My school is ${this.school}`); }; */ } talk() { this.info(); c(`My school is ${this.school}`); } } const xiaoD = new Student("xiaoD", 4, "小星星幼兒園"); xiaoD.talk(); const { talk } = xiaoD; talk(); // 不綁定this這里會(huì)報(bào)錯(cuò) const somebody = new People("somebody", 22); somebody.talk(); // 報(bào)錯(cuò),父類中沒(méi)有該方法
這里有三個(gè)注意點(diǎn):
父類中不會(huì)存在子類的方法(面向?qū)ο罅笤瓌t還記得嗎,開(kāi)閉,單一職責(zé),依賴倒轉(zhuǎn),里氏置換,知道最少,接口隔離,合成聚合復(fù)用)
上面代碼中,talk方法中的this,默認(rèn)指向Student類的實(shí)例。但是,如果將這個(gè)方法提取出來(lái)多帶帶使用,this會(huì)指向該方法運(yùn)行時(shí)所在的環(huán)境(由于 class 內(nèi)部是嚴(yán)格模式,所以 this 實(shí)際指向的是undefined),從而導(dǎo)致找不到info方法而報(bào)錯(cuò)。解決辦法如代碼中所示。
關(guān)于箭頭函數(shù)的this指向問(wèn)題,眾所周知,普通函數(shù)的this是指向調(diào)用它的那個(gè)對(duì)象,所以普通函數(shù)可以通過(guò)apply,call,bind來(lái)改變this的指向。而箭頭函數(shù)中的this是在定義函數(shù)的時(shí)候就已經(jīng)確定了,指向外層作用域鏈中的普通函數(shù),若沒(méi)有,this則指向undefined。
PS(那么問(wèn)題又來(lái)了,手寫(xiě)個(gè)apply,call,bind的polyfill吧)
const obj = { name: "xiaoD" }; const fn = function(...args) { c(this.name, ...args); }; Function.prototype.myApply = function(obj, [...args]) { return this.call(obj, ...args); }; fn.myApply(obj, ["真", "棒"]); // xiaoD 真 棒 fn.apply(obj, ["真", "棒"]); // xiaoD 真 棒
拿走,不謝。
Function.prototype.myApply = function(obj, [...args]) { obj.fn = this; let ret = obj.fn(...args); delete obj.fn; return ret; }; Function.prototype.myBind = function(obj) { obj.fn = this; return function(...args) { return obj.fn(...args); }; }; // 偷偷貼在這里再PS
知道了原型、原型鏈,那new一個(gè)對(duì)象的過(guò)程知道嗎,能手寫(xiě)一個(gè)嗎。
new一個(gè)對(duì)象的過(guò)程大概分成三步:
新建一個(gè)空對(duì)象
改變?cè)玩溨赶颍{(diào)用構(gòu)造函數(shù)
返回這個(gè)新對(duì)象
const myNew = function(fn, ...args) { let obj = {}; obj.__proto__ = fn.prototype; let ret = fn.call(obj, ...args); return ret ? ret : obj; }; function People(name, age) { this.name = name; this.age = age; } let xiaoD = myNew(People, "xiaoD", 4); let xiaoY = new People("xiaoY", 4); // 可以對(duì)比一下,看看兩者區(qū)別
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/109276.html
摘要:可以看出這個(gè)構(gòu)造函數(shù)是由創(chuàng)建出來(lái)的,而我們看下的隱式原型,竟然是指向了的原型,也就是也是由創(chuàng)建出來(lái)的。例如,其他構(gòu)造函數(shù)的原型將覆蓋屬性并提供自己的方法。將構(gòu)造函數(shù)的執(zhí)行對(duì)象賦給這個(gè)空對(duì)象并且執(zhí)行。把對(duì)象的隱式原型指向構(gòu)造函數(shù)的原型。 構(gòu)造函數(shù)與實(shí)例對(duì)象 又是這個(gè)經(jīng)典的問(wèn)題,嗯,我先來(lái)寫(xiě)個(gè)構(gòu)造函數(shù),然后實(shí)例化一個(gè)對(duì)象看看。 function Person(name) { this....
摘要:先來(lái)一個(gè)構(gòu)造函數(shù)構(gòu)造一個(gè)人類實(shí)例化一個(gè)對(duì)象看看的名字是什么打印結(jié)果先說(shuō)一個(gè)前提只要是函數(shù),就會(huì)有一個(gè)屬性,可以理解為子代的原型遺傳基因只要是對(duì)象,就會(huì)有一個(gè)方法,可以理解為向上尋找原型的方法。 關(guān)于javascript中的原型和原型鏈 我GitHub上的菜鳥(niǎo)倉(cāng)庫(kù)地址: 點(diǎn)擊跳轉(zhuǎn)查看其他相關(guān)文章 文章在我的博客上的地址: 點(diǎn)擊跳轉(zhuǎn) ? ? ? ? 關(guān)于javascript中的原型和原...
摘要:的隱式原型是母,母是由構(gòu)造函數(shù)構(gòu)造的,但函數(shù)的隱式原型又是。。。。可能是考慮到它也是由構(gòu)造函數(shù)生成的吧,所以返回的值也是。 showImg(https://segmentfault.com/img/bVyLk0); 首先,我們暫且把object類型和function類型分開(kāi)來(lái),因?yàn)?function是一個(gè)特殊的對(duì)象類型,我們這里這是便于區(qū)分,把function類型單獨(dú)拿出來(lái)。順便一提,...
摘要:之二關(guān)于原型開(kāi)篇我記得初學(xué)時(shí),最難懂的概念就是的原型,而且這個(gè)概念在筆試面試中常常提到,因此今天我們把這個(gè)概念拿出來(lái),好好聊一聊。 之二:關(guān)于js原型 1. 開(kāi)篇 我記得初學(xué)js時(shí),最難懂的概念就是js的原型,而且這個(gè)概念在筆試面試中常常提到,因此今天我們把這個(gè)概念拿出來(lái),好好聊一聊。 在仔細(xì)講解之前,我們先來(lái)看一道題,這道題來(lái)自JavaScript高級(jí)程序設(shè)計(jì)中原型鏈那一節(jié): fun...
摘要:寄生組合式繼承終于寫(xiě)到最后一個(gè)繼承了,我們?cè)谥爸v了種繼承方式,分別是原型鏈,借用構(gòu)造函數(shù)繼承,組合繼承,原型式繼承,寄生式繼承,其中,前三種聯(lián)系比較緊密,后面兩種也比較緊密,而我們要講的最后一種,是和組合繼承還有寄生式繼承有關(guān)系的。 前言 趁周末結(jié)束之前趕緊先把坑填上。上回我們說(shuō)到了原型鏈,并且留下了幾個(gè)思考題,先把答案公布一下。 在最后一個(gè)例子里,console.log(b1.c...
摘要:原文鏈接關(guān)于的原型和原型鏈,看我就夠了一參考鏈接闖關(guān)記之原型及原型鏈之原型與原型鏈一篇文章帶你理解原型和原型鏈徹底理解原型鏈一的默認(rèn)指向圖解和的三角關(guān)系原型和原型鏈三張圖搞懂的原型對(duì)象與原型鏈 溫故 創(chuàng)建對(duì)象的三種方式 通過(guò)對(duì)象直接量 通過(guò)new創(chuàng)建對(duì)象 通過(guò)Object.create() js中對(duì)象分為兩種 函數(shù)對(duì)象 普通對(duì)象 仔細(xì)觀察如下代碼 function Foo(na...
閱讀 2167·2021-11-15 11:36
閱讀 1511·2021-09-23 11:55
閱讀 2501·2021-09-22 15:16
閱讀 2037·2019-08-30 15:45
閱讀 1873·2019-08-29 11:10
閱讀 1039·2019-08-26 13:40
閱讀 927·2019-08-26 10:44
閱讀 3180·2019-08-23 14:55