美文网首页
学习原型中的各个难点

学习原型中的各个难点

作者: zoe_wang | 来源:发表于2019-02-01 11:13 被阅读0次
  • 本文主要是原型中的各个难点,基础知识不要不要滴。


    大家可以仔细分析下该图

prototype

先来介绍 prototype 属性。这是一个显示原型属性,只有函数才拥有该属性。基本上所有函数都有这个属性,但是也有一个例外

let fun = Function.prototype.bind()

如果是以上述方法创建一个函数,那么可以发现这个函数是不具有prototype 属性的。

prototype 如何产生的
  • 当我们声明一个函数时,这个属性就被自动创建了。
function Foo() {}

并且这个属性的值是一个对象(也就是原型),只有一个属性constructor

prototype 产生
constructor 对应着构造函数,也就是Foo
constructor

constructor 是一个公有且不可枚举的属性。一旦我们改变了函数的prototype,那么新对象就没有这个属性了(当然可以通过原型链取到constructor)。

constructor
至于这个属性到底有什么作用呢,我也不知道。参考诸多文章,这里总结了两个作用:
  • 让实例对象知道是什么函数构造了它
  • 如果想给某些类库中的构造函数增加一些自定义的方法,就可以通过xx.constructor.method 来扩展
proto

这是每个对象都有的隐式原型属性,指向了创建该对象的构造函数的原型。其实这个属性指向了[[prototype]], 但是[[prototype]] 是内部属性,我们并不能访问到,所以使用proto属性。

function Foo() {}
// 这个函数是 Function 的实例对象
// function 就是一个语法糖
// 内部调用了 new Function(...)

所以可以说,在new 的过程中,新对象被添加了proto 并且链接到构造函数的原型上。

new 的过程
  1. 新生成了一个对象
  2. 链接到原型
  3. 绑定this
  4. 返回新对象
    在调用new 的过程中会发生以上四件事情,我们也可以试着来自己实现一个new
function create() {
    // 创建一个空的对象
    let obj = new Object()
    // 获得构造函数
    let Con = [].shift.call(arguments)
    // 链接到原型
    obj.__proto__ = Con.prototype
    // 绑定 this,执行构造函数
    let result = Con.apply(obj, arguments)
    // 确保 new 出来的是个对象
    return typeof result === 'object' ? result : obj
}

对于实例对象来说,都是通过 new 产生的,无论是 function Foo() 还是 let a = { b : 1 }

对于创建一个对象来说,更推荐使用字面量的方式创建对象。因为你使用 new Object() 的方式创建对象需要通过作用域链一层层找到Object,但是你使用字面量的方式就没这个问题。

function Foo() {}
// function 就是个语法糖
// 内部等同于 new Function()
let a = { b: 1 }
// 这个字面量内部也是使用了 new Object()
Function.proto === Function.prototype

对于对象来说,xx.__proto__.contrcutor 是该对象的构造函数,但是在图中我们可以发现 Function.__proto__ === Function.prototype,难道这代表着 Function 自己产生了自己?

答案肯定是否认的,要说明这个问题我们先从 Object 说起。

从图中我们可以发现,所有对象都可以通过原型链最终找到 Object.prototype ,虽然 Object.prototype 也是一个对象,但是这个对象却不是 Object 创造的,而是引擎自己创建了 Object.prototype 。所以可以这样说,所有实例都是对象,但是对象不一定都是实例。

接下来我们来看 Function.prototype 这个特殊的对象,如果你在浏览器将这个对象打印出来,会发现这个对象其实是一个函数。

image.png
我们知道函数都是通过 new Function()生成的,难道 Function.prototype 也是通过 new Function() 产生的吗?答案也是否定的,这个函数也是引擎自己创建的。首先引擎创建了 Object.prototype ,然后创建了 Function.prototype ,并且通过 __proto__ 将两者联系了起来。这里也很好的解释了上面的一个问题,为什么let fun = Function.prototype.bind()没有 prototype 属性。因为 Function.prototype 是引擎创建出来的对象,引擎认为不需要给这个对象添加 prototype 属性。

所以我们又可以得出一个结论,不是所有函数都是 new Function() 产生的。

有了 Function.prototype 以后才有了 function Function() ,然后其他的构造函数都是 function Function() 生成的。

现在可以来解释Function.__proto__ === Function.prototype 这个问题了。因为先有的 Function.prototype 以后才有的function Function(),所以也就不存在鸡生蛋蛋生鸡的悖论问题了。对于为什么 Function.__proto__会等于 Function.prototype ,个人的理解是:其他所有的构造函数都可以通过原型链找到 Function.prototype ,并且 function Function() 本质也是一个函数,为了不产生混乱就将 function Function()__proto__ 联系到了 Function.prototype 上。

总结


  • Object 是所有对象的爸爸,所有对象都可以通过 __proto__找到它
  • Function 是所有函数的爸爸,所有函数都可以通过 __proto__ 找到它
  • Function.prototypeObject.prototype 是两个特殊的对象,他们由引擎来创建
  • 除了以上两个特殊对象,其他对象都是通过构造器 new出来的
  • 函数的 prototype 是一个对象,也就是原型
  • 对象的 __proto__指向原型, __proto__将对象和原型连接起来组成了原型链

相关文章

  • 学习原型中的各个难点

    本文主要是原型中的各个难点,基础知识不要不要滴。大家可以仔细分析下该图 prototype 先来介绍 protot...

  • 深入javascript之原型和原型链

    原型和原型链是js中的难点也是重点,明白了原型和原型链会让我们在后面不管是学习还是工作都会更加高效,并且原型和原型...

  • JavaScript难点之原型和原型链

    这篇文章主要是学习一下JavaScript中的难点------原型和原型链 自定义一个对象 我们学习一门编程语言,...

  • JS闭包问题(一)

    之前我写过一篇JavaScript原型与原型链的文章,此属于JS中的重难点。 而闭包,是JS中除了原型链之外又一个...

  • Javascript: 原型

    在学习Javascript过程中,免不了要涉及到原型的知识,但这也正是Javascript的难点之一。其中一些属性...

  • JS进阶系列

    在JS入门难点解析系列中,我们对JS的一些重要概念,比如:作用域,作用域链,原型,原型链,继承,活动对象,this...

  • 浅谈Js原型的理解

    转载------ 一、js中的原型毫无疑问一个难点,学习如果不深入很容易就晕了! 在参考了多方面的资料后,发现解释...

  • 大白话通俗易懂的讲解javascript原型与原型链(__pro

    javascript原型和原型链是js中的重点也是难点,理论上来说应该是属于面向对象编程的基础知识,那么我们今天为...

  • 2019-05-15 深度解析原型链中的难点

    本文不会过多介绍基础知识,而是把重点放在原型的各个难点上。 大家可以先仔细分析下该图,然后让我们进入主题 prot...

  • 前端开发必须知道的JS(一) 原型和继承(转载)

    前端开发必须知道的JS(一) 原型和继承 原型和闭包是Js语言的难点,此文主要讲原型及原型实现的继承,在(二)中会...

网友评论

      本文标题:学习原型中的各个难点

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