JavaScript 原型和原型链

307 阅读3分钟

最近面试了好多小伙伴,发现现在有一个奇怪的现象。好多小伙伴都是只会用vue进行业务开发,对于js的基础知识都停留在知道有这个东西的层面上。我觉得大家还是需要将基础夯实,这样才能在后面走的更远。

今天准备就我对原型和原型链的理解给大家分享一波,如果有不对的地方,欢迎大家指出。

本文核心知识点

  • prototype
  • [[proto]] 备注:部分浏览器实现为__proto__

JavaScript 设计规则

1. Object(对象)有__proto__属性
2. Function(函数)有prototype属性
3. 对象都是由函数生成的,而函数又是一种对象
4. 所有对象生成时,对象的__proto__都会指向Function(函数)的prototype属性

所有原型链的前提都是根据上面几个规则来的

对于上面基础原则,代码展示

    var a = {}
    a.prototype           // undefined
    
    var b = function(){}
    b.__proto__          // ƒ () { [native code] }
    b.prototype          // {constructor: ƒ}

一、 最简单的情况

    // 构造函数 Foo
    var Foo = function(){}
    // 实例化构造函数
    var foo = new Foo()

    foo.__proto__ === Foo.prototype
    
    Foo.__proto__ === Function.prototype
    
    Foo.prototype.constructor === Foo
    
    Foo.prototype.__proto__ === Object.prototype
    // typeof Foo.prototype     Object 原型对象

这里我们定义了构造函数 Foo,并且实例化了一个 foo,对于foo的__proto__属性,指向了构造函数的prototype属性,即指向Foo的prototype。

对于构造函数Foo,他也是一个函数,Foo的__proto__属性则指向了Function的prototype属性。

对于Foo的prototype,和所有function一样,函数的prototype的constructor指向函数本身。

函数的原型都是对象,所以称为原型对象,所以Foo.prototype的__proto__属性指向了Object的原型

二、核心部分 Function 和 Object 的关系

    Function.__proto === Function.prototype               // true
    Object.__proto__ === Function.prototype               // true
    Function.prototype.__proto__ === Object.prototype     // true
    Object.prototype.__proto__ === null                   // true
    
    因为上面部分都是 true ,就会有一个神奇的 现象
    
    Function instanceof Function                        // true
    Object instanceof Object                            // true
    Function instanceof Object                          // true
    Object instanceof Function                          // true

Function的__proto__指向Function的prototype属性,是因为Function也是通过Function生成的,即函数也是通过函数实例化出来的,所以Function的原型链指向他的原型对象

Object的__proto__指向Function的prototype属性,也是因为Object是通过函数生成的,所以Object的__proto__指向了Function的prototype

Function的prototype属性的__proto__,指向Object的prototype,是因为所有原型都是对象,对象的__proto__属性,则都指向了Object的prototype属性

Object的原型对象的__proto__,往上找已经到顶了,即为null

根据上面的等式部分,推出了这个神奇的instance等式。Function和Object互相以及和自己都在自己原型链上

三、理解上面部分,做几个题目试试吧

  • 题目1
    var Foo = function() {};
    Foo.prototype.n = 1;
    var foo1 = new Foo();
    Foo.prototype = {
      n: 2,
      m: 3
    }
    var foo2 = new Foo();
    
    console.log(foo1.n);
    console.log(foo1.m);
    
    console.log(foo2.n);
    console.log(foo2.m);
    
    

解析:这一题目还涉及了一个引用类型的问题(注意这里修改Foo的prototype后,原来的prototype,还是在内存中的,这里实例化的对象存的是一个指向这里的地址,所以foo1的内容不会受打影响)

答案:

1
undefined

2
3
  • 题目2
var obj = {},
    Fun = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';

console.log(obj.a);
console.log(obj.b);

console.log(Fun.a);
console.log(Fun.b);

解析

obj.__proto__ === Object.prototype
Object,prototype.__proto__ === null

Fun.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype

// 答案
value a
undefined

value a
value b

四、总结

第一部分我们就分析了原型和原型链最基础的相关知识,大家对于这部分最基础的掌握,才能对后面基于这块实现的js设计模式中的继承以及new的过程中做了哪些事情等等一系列知识进行学习。希望大家一起努力一起进步。