js原型对象和原型链,拖更新待完善

123 阅读4分钟

前言

在很长很长的时间, 我对js的原型以及原型链很懵懂, 为什么 Object.__proto__ === Function.prototype Function.prototype.__proto__ === Object.prototype 这一现象让我觉得非常困惑,深深的觉得它在套娃,我不断的在这个循环里打转,无法自拔,看一会感觉自己理解了,但是后面换一种问法,我又开始绕进去了,我想我并没有真正理解,知其一不知其二,所以我决定用文档的形式,或者是说以述说,“为什么” 的角度分享出来,知其因,知其果。

什么是原型对象

通常我们把函数的 prototype 称作为原型对象,每个函数都会有prototype。

    function x() {}
    console.log(x.prototype) // 原型对象

什么是原型链

原型与原型层层连接的过程称为原型链。

     // 这里我们先把复杂的Function,与object抛开,只讨论以下代码的链路连接
    function Y(name,age) { 
      this.name = name;
      this.age = age;
    }
    // 给Y的原型对象添加 color属性为 red
    Y.prototype.color = 'red'

     // 改变Y1原型对象的指向,指向这个生成的实例
    function Y1(name) {
      this.name = name;
    }
    Y1.prototype = new Y('小明', 29);
   
    // 基于Y2.prototype,构造出实例,这个实例对象的 __proto__ 引用了Y2.prototype
    const child = new Y1('小红');
    const childCopy = {};
    
     // !!!对象没有prototype!! 思考: 为什么对象没有__proto__呢?
    // 更改 childCopy .__proto__ 的指向 为child.__proto__ 
    childCopy.__proto__ = child.__proto__;
    
    console.log(child.color, childCopy.color)  // red red
    console.log(child.name, childCopy.name) // 小红 小明
    

待补图

为什么我们能直接调用 数组/字符串 的“方法” ?

你有没有思考过一个问题,为什么我们能直接调用 [].map, 'x'.toString()...等,我们创建一个变量,有两种方式,一种是声明,一种是构造形式, 他们生成的对象都是一样的,但是他们的表现却会不同。

  var myStr = 'I am a stringI am a string'; // 声明式
  typeof myStr; // string
  var myStrObj = new String('I am a string'); // 构造式
  typeof myStrObj; // object;
  myStr + myStrObj // I am a stringI am a string

可以看见使用声明式 “I am a string” 并不是一个对象,它只是一个普通的字符串,字符串就是数据,在必要时,注意是必要时,比如:访问字符串的方法(长度,或者splice...等等),js引擎会把它转换成String对象

上面的描述不够直观,我一直在想,用一种什么样的方式表达我想说的,直到我再次回顾了《你不知道的js》这本书,作者在书中写着这段话让我突然豁然开朗想要表达些什么。

面向对象编程强调的是数据和操作数据的行为本质上是互相关联的(当然,不同的数据有不同的行为)。 因此好的设计就是把数据以及和它 相关的行为打包(或者说封装)起来。 这在正式的计算机科学中有时被称做数据结构

通常我们不关心数据是什么,而是可以对数据做什么,所以可以应用在这种数据上的行为(计算长度,添加数据,搜索,等等..),都被设计成string方法, 所有的字符串都是一个 String。

通俗点来说,你可以把访问方法的过程,想象成装箱拆箱

new String 看作是一个箱子,箱子里装着字面量 ('I am a string') , 比如:当你使用两个字符串相加时,js引擎会拆箱,把箱子里的字面量取出使用(这里涉及到js的运算机制,我们不展开), 而使用的是声明式,这个时候访字符串的方法js引擎会把字面量装箱(方法都在对象上面,字面量只是数据)。

注意:这些状况都是在需要使用的时候,才会进行的操作,如果你不使用它,那它不会发生任何的改变。

重要:我们定义所有的声明都是继承对应数据类型的方法


tip: 通常我们并不会使用构造式这么去创建一个对象,我们一般都会使用声明式创建对象,
绝大多数的内置对象也是这么做的。


引流标题:工作了五年我竟然还不懂js原型对象和原型链!!这一次彻底搞懂什么是原型对象/