美文网首页
探究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