关于前端:多图详解一次性啃懂原型链上万字

56次阅读

共计 11804 个字符,预计需要花费 30 分钟才能阅读完成。

前言

  • 在线音乐戳我呀!
  • 音乐博客源码上线啦!
  • 糊里糊涂在前端畛域磕磕碰碰了靠近三年,想看看 Vue 源码,不晓得有没有最近想看源码的猿友,如果 JS 不够硬,倡议跟我一起来 重学 JS,重学完置信再去看源码,会事倍功半。
  • 尤其清晰的记得毕业期间有一次上课期间手机响起来,接了个面试电话,就问了原型、原型链,真的是怕什么来什么,过后对这块常识较含糊,支支吾吾答复不上来很难堪。
  • 真花了几天几夜,只为出现最好的文章。可能一次性看不完,倡议点赞珍藏,花再多工夫也要硬啃下来,肯定拿下原型链这块盲区常识,好嘛!!!
  • 接下来咱们来看看 JS 的原型、原型链知识点都能够考些什么。
  • 请脑子清晰,跟着我的节奏,保障一回彻底啃下,Are you ready?

每日一面:
面试官:晓得什么是对象吗?
晓得,不过我工作致力,上进心强,临时还没有对象。然而打算找对象了。

先来问本人六七八道面试题

  • 说一下原型?
  • 说一下原型链过程?
  • Object.prototype.__proto__ 值为啥?
  • 什么的显式原型、隐式原型都指向它本人?
  • 任何函数都是 new Function 创立的?
  • Function 的显式原型是不是都是 new Object 进去的?
  • 所有的函数的__proto__都是一样的?
  • 所有函数的显式原型指向对象默认是空 object 实例对象?

想看答案,间接划到最上面
如果会了,面试官轻易拿捏好吧。
如果不会,咱们先来了解原型、原型链的概念。
只有晓得问题背地的原理常识,解题必然顺手拈来。

原型与原型链

  • 原型(prototype)
  • 显式原型与隐式原型
  • 原型链

一、原型

1.1 函数的 prototype 属性

1.1.1. 每个函数都有一个 prototype 属性, 它默认指向一个 Object 空对象(即称为: 原型对象)

上段代码不便了解这段话:

function Fun () {}

console.log(Fun.prototype)  // 默认指向一个 Object 空对象(没有咱们的属性)

咱们定义的 Fun 函数有一个 prototype 属性,而且打印进去默认指向 Object 空对象。

❓ 杠精上身:我不信,那为什么 Date 函数怎么一创立就默认有很多办法?

有图有假相。

你不是说 prototype 属性, 它默认指向一个 Object 空对象,打印进去这么多办法(揭穿你),不过 typeof Date.prototype 的确是 object 对象类型。

🙋这个问题我能够答复一下:

其实 Date 原型 prototype 上的办法是 Date 初始化本人往原型上增加的,次要是给实例对象应用的,谁把我创立进去,就给谁用。

关上 Date 函数,从源码能够看到 Date 往 prototype 增加了很多办法。

懂了,原来是 Date 函数创立的时候本人往 prototype 上增加属性办法。

❓ 你说函数的显式原型指向对象默认是空 object 实例对象?

console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true

Object 除外。

1.1.2. 原型对象中有一个属性 constructor, 它指向函数对象

咱们用代码了解一下:

Date 的原型 prototype 有一个属性 constructor,这个属性 constructor 指向 Date 对象。

Date.prototype.constructor === Date

咱们再用画图了解一下(说好肯定要带懂你)

构造函数和原型对象有互相援用的关系图如下:

你外面有个属性 prototype 能找到我,我外面有个属性 constructor 也能找到你。

1.2 给原型对象增加属性(个别都是增加办法)

有何作用:

为了给函数的所有实例对象主动领有原型中的属性(办法)。

// 给 Fun 原型增加属性 test
Fun.prototype.test = function () {console.log('test()')
}

// 你问我有什么用?还不是给你 fun 实例对象能够调用 test 办法用的
var fun = new Fun()
fun.test()

二、显式原型与隐式原型

2.1 每个函数 function 都有一个 prototype,即显式原型(属性)

// 定义构造函数

function Fn() {// 外部语句: this.prototype = {}
}  

console.log(Fn.prototype)  // {}

而函数的 prototype 属性在什么时候会被加上?

函数的 prototype 属性: 在定义函数时主动增加的, 默认值是一个空 Object 对象

2.2 每个实例对象都有一个__proto__,可称为隐式原型(属性)

// 创立实例对象

var fn = new Fn()  // 外部语句: this.__proto__ = Fn.prototype

console.log(fn.__proto__)   // {}

而对象的__proto__属性: 创建对象时主动增加的, 默认值为构造函数的 prototype 属性值

2.3 对象的隐式原型的值为其对应构造函数的显式原型的值

其实也的确是相等,因为实例对象的__proto__属性在创建对象时主动增加的, 默认值为构造函数的 prototype 属性值。

二者的地址值都是同一个,天然相等。

function Fn() {}
var fn = new Fn()

console.log(Fn.prototype === fn.__proto__) // true

咱们再来上张图更透底搞懂他们的关系:

⭐请容许我啰嗦两句(倡议依据阿泽以下说的,而后画下来,画着画着就懂了):

  • 1. 第一行代码定义了 Fn 函数,那么栈空间产生 Fn,因为函数是援用类型,所以赋予 0x123(栈空间命名不是这样子叫,只不过在这里给它一个名字)
  • Fn 是构造函数,外部语句:this.prototype = {},所以有显式原型 prototype 属性,指向空 object 对象 0x234。
  • 输入 Fn.prototype,打印{constructor: ƒ, prototype:{...}}
  • 2. 创立以 Fn 实例对象的 fn,在栈空间新建 fn,指向堆空间的 0x3456。
  • 实例对象有__proto__属性,实例对象被创立外部语句是:this.__proto__ = Fn.prototype
  • 对应上方2.3 对象的隐式原型的值为其对应构造函数的显式原型的值
  • fn 的__proto__和 Fn.prototype 指向同一个值为 0x234。
  • 3. 在 Fn 构造函数的原型上增加 test 属性,即 0x234 空 object 对象上增加 test 属性。
  • 接着执行 fn.test(),所谓点. 就是去堆空间外面找对应的属性值,它先去自身 0x345 找,发现并没有找到,持续去它的隐式__proto__原型链 0x234 上找,找到了 test 属性,返回!

误区:
找属性的时候,不会去显式原型上找,它是回去找隐式原型__proto__属性上查找,因为一开始该属性创立的时候,就是将显式原型 prototype 属性赋给隐式原型__proto__属性。

❓ 杠精上身:为什么构造函数有 prototype 属性了,实例对象还要搞一个__proto__的值为构造函数 prototype 的值呢?

大略作用就是共享内存,缩小办法对内存占用,test 办法变成公交车,prototype 就是现金,__proto__就是扫码,只有给钱都能上(都能拜访 test)。

2.4 能间接操作显式原型, 但不能间接操作隐式原型(ES6 之前)

咱们失常都是间接给 Fn 原型上增加属性办法,而不会间接去操作 fn 实例对象的__proto__属性去增加办法。

也就是能够间接操作显式原型,而不要间接去操作隐式原型。(尽管当初 ES6 时代能够去操作隐式原型,但最好不要)。

function Fn() {}
var fn = new Fn()

// 给显式原型增加 test 办法
Fn.prototype.test = function () {console.log('test()')
}

// 通过实例调用原型的办法
fn.test()

三、原型链

⭐倡议跟着以下剖析,本人把图画进去,程序员的入手能力很重要(如果切实懒,再关上一个窗口放把下面的图,一边看图一边看剖析),如果图、剖析不联合,有可能无奈 GET 到点哦 ~

如果临时没工夫,倡议珍藏,等有工夫缓缓看。

3.1 聊原型链前,咱们先来看一道面试题目。(请耐下性子,好好看上来,必有收货)

请输入以下程序执行的后果。

function Fn() {this.test1 = function () {console.log('test1()')
    }
}

Fn.prototype.test2 = function () {console.log('test2()')
}

var fn = new Fn()

fn.test1()  // test1()
fn.test2()  // test2()
console.log(fn.toString())  // '[object Object]'
fn.test3()  // Uncaught TypeError: fn.test3 is not a function

偷笑😁,这面试官也太小看我了吧!

面试官:别急,请根据上述代码块画出函数的栈堆、以及原型链指向。

是不是很多面试者忽然不晓得怎么画了呢?

其实也失常,对原型链概念隐隐约约,画不进去,失常,不过这也是本篇存在的意义。

记住三句话:

  • 每个函数都有一个 prototype 属性, 它默认指向一个 Object 空对象。
  • 每个实例对象都有一个__proto__,可称为隐式原型。
  • 实例对象的隐式原型属性等于构造函数显式原型属性的值。

来吧,唐伯虎附体。冲!

  • 右边的程序块大局观大略是:

    • Object 对象 0x567 是引擎创立了它,程序再执行的时候也就有了左边堆空间的产生;
    • 无论是 Fn 函数的显式原型也好,隐式原型也罢,都是 Object 的实例对象;
    • 然而 Object 尽管是大家的爸爸,但也是有原型的,是 0x345。(爸爸的爸爸叫爷爷)

⭐请容许我啰嗦两句(倡议依据阿泽说的,而后画下来,画着画着就懂了):

  • 1. 第一行代码定义了 Fn 函数,那么栈空间产生 Fn,因为函数是援用类型,所以赋予 0x123(栈空间命名不是这样子叫,只不过在这里给它一个名字)
  • 堆空间也产生 0x123 的 function 对象,并有 prototype 属性。
  • prototype默认会指向一个 Object 空对象,咱们给这个空对象命名 0x234。
  • 对应下面 1.1.1 每个函数都有一个 prototype 属性, 它默认指向一个 Object 空对象(即称为: 原型对象)
  • 0x234 有一个__proto__属性。既然都有__prototy__隐式原型,那 0x234 是 Object 的实例对象。
  • __proto__指向一个 Object 对象,咱们给这个原型对象命名为 0x345。
  • 对应下面 2.2 每个实例对象都有一个__proto__,可称为隐式原型(属性)
  • 要讲这个 0x345,咱们先来引进 Object 对象。
  • 先问大家一个问题,Object 对象先创立还是咱们代码块的 Fn 函数先创立?
  • Object 对象在咱们代码还没有执行的时候,JS 引擎曾经创立了 Object。
  • 验证下:看图的 0x234 实例对象的__proto__隐式原型属性 = 构造函数 Object 的显式原型,那居然是等于(赋值运算),那必定是左边先有的。右先创立才有的右边。
  • 所以 Fn 之前,Object 曾经先创立了,咱们给 Object 命名为 0x567。
  • 0x567 的 Object 函数对象有一个 prototype 属性。
  • prototype指向 Object 原型对象,咱们给这个对象命名 0x3456。
  • 咱们晓得 prototype 默认会指向一个 Object 空对象,那这里 Object 的 prototype 也是指向一个空对象?
  • 总得有个尾吧,这里就是尾了。所以 0x3456 外面有很多属性。如:toString()、valueof()、…
  • 当然,它还有__proto__属性,只不过值为 null。
  • 所以 toString 办法,咱们在函数对象就能够调用它,因为函数也是对象,对象的原型最终为 Object,Object 的 prototype 显式原型就有 toString 办法。
  • 回归上方的 0x234 的__proto__指向的就是 Object 的 prototype 显式原型。
  • 2.OK,到这里咱们画完代码块中的 Fn 函数的创立(是不是感觉我就定义一个函数,就这么简单了,其实再走上来就通了),来,咱们持续 GO!
  • 3. 接着 Fn.prototype.test2 给 Fn 原型增加 test2 属性,咱们在 0x234 对象外面增加 test2 属性。
  • 4.var fn = new Fn(),创立了一个 Fn 的实例对象 fn,在栈中创立 fn,命名为 0x456。
  • 堆空间有 0x456 这块内存,有着 test1 属性。
  • 有人可能会问了,test1 不是 Fn 构造函数的吗?为什么 test1 写在 fn 实例对象外面?
  • 请留神:在 Fn 中的 test1 是 this.test1 = function(){} 创立的,上篇讲到想写好面向对象的代码,这篇肯定要看讲到 this 指向,谁调用我,this 就指向谁,在这里是 fn 调用的,那 this.test1 当然是写在 fn 外面。
  • 当然,0x456 是一个实例对象,那就应该有__proto__隐式属性。
  • 该隐式属性指向 Who?
  • 对应后面2.3 对象的隐式原型的值为其对应构造函数的显式原型的值
  • 所以,这里的 0x456 实例对象隐式原型的值指向 0x123 构造函数显式原型的值,即指向:0x234。
  • 5.OK,右边代码块持续走,fn.test1 办法执行,输入 test1()
  • 6.fn.test2()办法执行,先找到 fn(先在本身属性中查找,找到返回)。
  • 然而并没有找到,fn 外面只有 test1、__proto__属性。(如果没有, 再沿着__proto__这条链向上查找, 找到返回)
  • 咱们沿着__proto__这条线寻找上来,找到 0x234,0x234 有 test2、__proto__属性,OK,找到 test2,返回,进行查找。输入 test2。
  • 7. 持续走,打印fn.toString(),先找到 fn,并没有 toString,再沿着__proto__这条链向上查找,找到 0x234,还是没有找到,再沿着__proto__这条链向上查找,来到 0x345 的 Object 原型对象,找到了 toString 属性,打印[object Object]。
  • 8. 最初一步,fn.test3(),先找到 fn,并没有 toString,再沿着__proto__这条链向上查找,找到 0x234,还是没有找到,再沿着__proto__这条链向上查找,来到 0x345 的 Object 原型对象,还是没有找到,再沿着__proto__这条链向上查找,但此时的__proto__为 null。
  • 说到这里,咱们再来聊一个状况。
  • 如果是fn.test3,到 Object 的__proto__隐式原型为 null,那到最止境了,找不到怎么办呢?会报错?还是返回 null?
  • 其实都不是,是 undefined。
  • 所以 fn.test3 输入 undefined,但你 fn.test3(),undefined() 执行,把 undefined 当做函数执行,那不得报错。

打完出工。

⭐倡议跟着以上剖析,本人把图画进去,程序员的入手能力很重要(如果切实懒,再关上一个窗口放把下面的图,一边看图一边看剖析),如果图、剖析不联合,有可能无奈 GET 到点哦 ~

看完临时还隐隐约约,请重复看以上剖析。

如果临时没工夫,倡议珍藏,等有工夫缓缓看。

PS:
1. Object.prototype.__proto__从上图得悉,尽管 Object 的原型曾经是最底层了,但它也是有__proto__,只不过值为 null,那其实从某种角度来说,它也是实例对象,因为有__proto__属性就是实例对象。
2. 最小的孩子为 null。
3. 对于 Object 相干常识:
Object 在一开始就有一个原型对象 0x345,object 的函数对象和实例对象都指向了原型对象;的确,不论是我 Object 的实例对象 0x234 还是别的函数 fn 都最终指向了我 0x345。
同时 object 的实例 0x234 对象也是别的函数的 prototype 默认指向的一个 object 空对象。(请联合以上图,倡议关上一个窗口而后把图利落过来,一一对应这些 0x 某某某,是很清晰明了的)

3.2 再来一条?(易出错)

请输入以下程序执行的后果。

function Fn() {this.test1 = function () {console.log('test1()')
    }
}

console.log(Fn.prototype) // {constructor: ƒ}
Fn.prototype.test2 = function () {console.log('test2()')
}
console.log(Fn.prototype) // {test2: ƒ, constructor: ƒ}

其实下面输入的答案是错的。

啊?

正确答案如下:看图

能够看到开展前,并没有test2(下面的答案是对的),但如果开展后,第一个打印却又有 test2 函数。

来,请听我剖析一波。

  • 第一个输入 Fn.prototype 开展有 test2 这个属性,但没有 test2 的本质内容。
  • JS 申明的变量都会提前,所以这里 prototype 在一开始就晓得有个叫 test2 的属性的。
  • 然而理论的内容 prototype 不晓得,只有当 Fn.prototype.test2 = function () {} 执行实现才晓得。能够在增加原型后,打印输出再看一次 prototype。
  • 会发现 test2 的样子和没增加原型不一样了。此时 test2 正式作为函数退出了 prototype 中。
  • 是开始的时候变量申明提前造成的。即一开始就有 test2 存在了。

3.3 拜访一个对象属性时,原型链的内心世界

  • 拜访一个对象的属性时:

    • 先在本身属性中查找,找到返回
    • 如果没有, 再沿着__proto__这条链向上查找, 找到返回
    • 如果最终没找到, 返回 undefined
  • 原型链的别名:隐式原型链
  • 其实从下面的例子得悉,每次拜访对象属性,其实都会去寻找__proto__隐式原型链下来找,所以原型链被人起了别名叫隐式原型链。
  • 小误区:var fn = new Fn()这段代码的 fn,这个是不是也在原型链中找?
  • 不是,它是在作用域里,变量查找是在作用域中找的;原型链查找的是对象的属性。
  • 原型链的作用:查找对象的属性(办法)

都看到这了,再保持保持就完结了(前面更精彩,后面那段剖析算啥😁,前面才是重头戏)

3.4 构造函数 / 原型 / 实体对象的关系(图解一)

var o1 = new Object()
var o2 = {}

面试官:这段代码执行完,栈堆空间是怎么的?

  • 首先:o1、o2 都是 Object 构造函数的实例对象,那实例对象必然有__proto__属性。
  • 其次:实例对象的__proto__隐式原型属性指向构造函数显式原型属性的值。
  • 最终:能够看到图中 o1、o2 的__proto__属性与 Object 的 prototype 都指向同一个值 Object.prototype

3.5 构造函数 / 原型 / 实体对象的关系(图解二)

面试官:置信我,最初一道了。(说进去你可能不信)

最初一道咱们就轻松一点,请画出 function Foo(){} 原型链。

间接上图。

⭐请容许我再多啰嗦两句:

  • 能够看到 Foo 函数有两条线,一条是 function Foo(),还有一条是__proto__。
  • 第一条线为什么会存在?
  • 1.function Foo()它是一个构造函数,这没问题吧,在下面2.1 每个函数 function 都有一个 prototype,即显式原型(属性) 一开始咱们就讲到了,所以天然有这条线存在。
  • 构造函数有显式原型属性 prototype。
  • 第二条线为什么会存在呢?
  • 2. 看到了图中第二条线有__proto__这个属性,谁有这个属性,实例对象吧,啥,你不是说 function Foo() 是构造函数吗?当初又说是实例对象?
  • 别急,function Foo(){},其实是一个省略的写法,它还能够写成var Foo = new Function(),这种写法是相等的,那我这样一写,Foo 岂不是是 Function 的实例对象,那也很天然有了第二条线是__proto__。
  • 透过实质去看问题,将迎刃而解。
  • 换句话说:所有的函数对象都有隐式、显式原型属性;隐式原型属性指向大写 Function 的显式原型属性。(你怎么不早说 ….. 当初这不是说了嘛)
  • 3.Foo 的__proto__和 function Function 的显式原型 prototype 都指向了 Function.prototype。
  • Foo 是 Function 构造函数 new 进去的吧,Foo 是实例对象;function Function 是构造函数,构造函数有 prototype 不过分吧。所以有了 __proto__、function Function() 都指向 Function.prototype 这条线,再次验证下面的2.3 对象的隐式原型的值为其对应构造函数的显式原型的值。(留神联合上图)
  • 4. 有个奇怪的景象:Function 的显式、隐式原型都指向本人?

  • 有隐式原型,那就是实例对象;有 prototype 显式原型,那就是构造函数。
  • 阐明 Function,也是本人 new 进去的,即:Function = new Function(这个其实就是先有鸡,还是先有蛋的问题)
  • 只有这样能力说显著式、隐式原型都相等,别的函数是没有这个特点的,如:下面的var Foo = new Function(),Foo 分了两条线,显式原型一条、隐式原型另一条。
  • 只有一个显式、隐式原型属性都是本人的,就是 Function。(⭐画重点,面试要考的)
  • 也就是说:任何函数创立都是 new Function 进去的,Function 本人也不例外。
  • 5. 函数的显式原型是 new Object。
  • 解释一下:

    • 函数是由 Function 生的,你本人的函数它的__proto__隐式原型指向它父亲,也就是 Function 的 prototype 显式原型。
    • Function 惟一不同的就是它的__proto__指向它本人。
    • 也就是说 Function.__proto__找不到它的父亲了(这个很要害)
    • 然而 Function 的 prototype 在 Function 创立后就存在了。
    • Function.prototype 是一个对象,是对象,所以它的__proto__当然指向的是 Object。
  • 6. 为什么会有 Object 的__proto__指向 Function.prototype 这条线?

  • 隐式原型怎么有的?(构造函数的显式原型给的)
  • Object 怎么来的?(其实 Object 也是 new Function 进去的,哈哈哈😁)
  • 又因为 Object 是 Function 的实例对象。线是从 Object 的__proto__指向 Function 的。
  • 所有 Function 都是 new Function,所以 Function 才是这原型链的胁从。
  • 能够看到下图 function Object()的隐式原型指向 Function 的显式原型,所有对象函数都是 Function 创立进去的。
  • 好,大家不是说所有皆对象吗?那你这什么都是 Function 创立的,不是应该所有皆函数吗?
  • 是啊,函数是最底层的,函数能够叫函数对象,函数只是对象的一种非凡示意,所以所有皆对象。这里有一篇不服,老湿说的万物皆对象,你也信?
  • 7. 所有函数的__proto__都是一样的。因为都是 new Function 产生的。
  • new Function 显式原型是不会变的,那实例对象的__proto__隐式原型指向着我的显式原型 prototype,那大家都是我创立的,我不会变,天然大家也不会变。

聊一聊所有函数的__proto__都是一样的
1. 其实就是两条路:函数能够看做是构造函数,这时走的是 object,这条显式原型链;
2. 构造函数的显式原型链用 prototype 走,这条路和他本人的所有实例的__proto__关联。
3. 另一条路,函数也能够看做是 Function 的实例,这时走的是 Function 的这条隐式原型链,用本人的__proto__走。
4. 此时所有函数都是一个妈生的,就是 new Function() 失去的。而 Function 自身也是函数,所以也应该合乎 Function 通过 new Function()失去。
5. 这样推导出必须满足 Function 由 new Function()失去,即 Function.__proto__ === Function.prototype
6. 艰深的讲就是:所有鸡都是鸡妈生的,而且鸡妈也是鸡,所以鸡妈也是鸡妈生的。
鸡 (fn) 有本人的 prototype,这只鸡 (fn) 其实又是鸡妈生的,所以有__proto__

3.6 原型继承

构造函数的实例对象主动领有构造函数原型对象的属性(办法)

利用的就是原型链。

原型上的属性办法就是为了给实例对象用的,也就是它的孩子,谁创立了我,我就给谁用。

四、面试

当初轻易问你几道题,应该能对答如流了吧!

Are You OK?

4.1 Object.prototype.__proto__ 值为啥?

🙋:null。最小的孩子为 null。

Object 的原型对象才是原型链的止境。

4.2 什么的显式原型、隐式原型都指向它本人?

🙋:Function。

显式原型 Function 是构造函数;隐式原型 Function 也是实例对象。

要是你能给面试官再画上【3.5 构造函数 / 原型 / 实体对象的关系(图解二)】这张图,那今天来下班。

4.3 任何函数都是 new Function 创立的?

🙋:是的,甚至 Function 它本人也不例外。

Function.__proto__ === Function.prototype

看,所有的都指向了 Function 的显式原型属性。

不太明确的童鞋能够再看看【3.5 构造函数 / 原型 / 实体对象的关系(图解二)】这张图。

好,大家不是说所有皆对象吗?那你这什么都是 Function 创立的,不是应该所有皆函数吗?

是啊,无论是内置函数、自定义函数、object 都是通过 new Function 进去的,函数是最底层的,函数能够叫函数对象,函数只是对象的一种非凡示意,所以所有皆对象。这里有一篇不服,老湿说的万物皆对象,你也信?

4.4 Function 的显式原型是不是都是 new Object 进去的?

🙋:是的。

  • Function.prototype.__proto__ === Object.prototype
  • 函数是由 Function 生的,你本人的函数它的__proto__隐式原型指向它父亲,也就是 Function 的 prototype 显式原型。
  • Function 惟一不同的就是它的__proto__指向它本人。
  • 也就是说 Function.__proto__找不到它的父亲了(这个很要害)
  • 然而 Function 的 prototype 在 Function 创立后就存在了。(A = B,必定是 B 先产生才有了 A)
  • Function.prototype 是一个对象,是对象,所以它的__proto__当然指向的是 Object。

4.5 所有的函数的__proto__都是一样的?

🙋:是的。

因为所有的函数都是通过 new Function 进去的。

new Function 的隐式原型和 Function 的显式原型相等。(隐式是实例,谁赋值给它的,构造函数的显式原型)

Function 是不会变的。

所以所有的函数的__proto__都是一样的。

不太明确的童鞋能够再看看【3.5 构造函数 / 原型 / 实体对象的关系(图解二)】最初的总结。

4.6 所有函数的显式原型指向对象默认是空 object 实例对象?

🙋:并不是。

console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true

Object 除外。Object 内置很多属性。

最初

想起有一次加班的时候,一个开发五年的大佬再向我解说本人的代码的时候,说到 hasOwnPrototype()这个办法的时候,说这个办法是 for in 遍历对象的时候 VS Code 主动生成的 hasOwnPrototype,如下图:

大佬说我也不晓得这个办法是干嘛的,我看他人都有加,最好还是加上吧。

也是笑了笑,其实就是为了谨严,确保我这个对象的属性都是自定义增加的。

很多开发了很多年的大佬,说到底层原理难堪的摸了摸头。

不晓得,不明了,不重要,重要的是不懂就要学,写了不止八小时,好几天拼凑起来的文章。

如果对您有帮忙,你的点赞是我后退的润滑剂。

以往举荐

尤大大说我的代码全副不加分号

老湿说的万物皆对象,你也信?

Vue-Cli3 搭建组件库

Vue 实现动静路由(和面试官吹我的项目亮点)

我的项目中你不晓得的 Axios 骚操作(手写外围原理、兼容性)

VuePress 搭建我的项目组件文档

koa2+vue+nginx 部署

vue-typescript-admin-template 后盾管理系统

原文链接

https://juejin.cn/post/7010942653915201543/

正文完
 0