美文网首页
探究JavaScript中new操作以及__proto__与pt

探究JavaScript中new操作以及__proto__与pt

作者: 黄努努 | 来源:发表于2017-04-09 15:27 被阅读0次

昨天看了大牛的这篇关于模拟bind函数实现的文章,深受启发。其中有一处涉及到关于bind方法返回的函数作为构造函数的问题令我百思不得其解。于是决定补补基础,探究构造函数和new操作究竟是个什么东西。

The new Operator

首先我去翻了翻MDN关于New操作详解,简单地摘一些比较关键信息:

When the code new Foo(...) is executed, the following things happen:

  1. A new object is created, inheriting from Foo.prototype
  2. The constructor function Foo is called with the specified arguments, and with this bound to the newly created object.

用代码表示如下:

// 模拟var foo = new Foo('foo')的过程

// A new object is created
var foo = {}

// inheriting from Foo.prototype
foo.__proto__ = Foo.prototype

// The constructor function Foo is called with the specified arguments, and with this bound to the newly created object.
Foo.call(foo, 'foo')

为了更好的理解为什么是foo.__proto__ = Foo.prototype,我需要对__proto__prototype之间的关系的作更深入探究。

prototype

  1. prototype是什么?
    • 构造函数的一个属性
    • 包涵constructor字段的一个Object
  2. 谁有prototype
    • 所有非原生函数与原生构造函数
// 原生函数不能成为构造函数,没有prototype属性
var nativeFunction = Function.prototype.call

console.log(nativeFunction.__proto__)           // function () {}
console.log(nativeFunction.prototype)           // undefined
new nativeFunction()                            // Uncaught TypeError: nativeFunction is not a constructor

prototype是构造函数才具备的属性,称呼其“原型”,其实是相当不严谨甚至严重误导的说法。prototype本质是JavaScript这门语言为开发人员操作原型对外暴露的一个接口。开发人员对prototype的操作,最终都会反映到该改构造函数的实例的__proto__

热爱面向对象的朋友一定很熟悉下面这段代码。

var Foo = function () {}
Foo.prototype = {
    constructor: Foo,
    // ...
}

var foo = new Foo()

我们重写了Foo.prototype,都必须手动添加constructor。如果不这样做的话,实例的原型foo.__proto__将找不到constructor

[[proto]]

  1. __proto__是什么?
    • 原型链上的一个原型
  2. 谁有__proto__
    • 所有Object都有(null除外)
var Foo = function () {}
var foo = new Foo()

// 构造函数 Foo => function () {} => Object {} => null
console.log(Foo.__proto__)                      // function () {}
console.log(Foo.__proto__.__proto__)                // Object {} | 注意与构造函数Object区别
console.log(Foo.__proto__.__proto__.__proto__)      // null | 是不是很意外?typeof null === Object并非空穴来风


// 实例 foo => { constructor: (...), __proto__: (...) } => Object {} => null
console.log(foo.__proto__)                      // { constructor, __proto__,... } | 这是由Foo的prototype属性决定的
console.log(foo.__proto__.__proto__)                // Object {}
console.log(foo.__proto__.__proto__.__proto__)      // null

总结

prototype的意义在于开发人员可以以此定义实例的原型,这也是JavaScript面向对象的基础。
__proto__在原型的维度上自成一列,构建了JavaScript强大的原型体系,与prototype不是一个层次上的概念。
如果一定要说二者有什么关系的话,我觉得应该说毫无关系

// 这不是代码
Foo.prototype.constructor => Foo
Foo.prototype.constructor.prototype.constructor => Foo
Foo.prototype.constructor.prototype.constructor.prototype.constructor => Foo
Foo.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor => Foo
// 无穷无尽... 我仿佛看见了循环链表的数据结构

相关文章

网友评论

      本文标题:探究JavaScript中new操作以及__proto__与pt

      本文链接:https://www.haomeiwen.com/subject/jmsdattx.html