Skip to content

JS原型、原型链深入理解 #25

Description

@junhey

前几天被阿里问到了一个原型和原型链的相关问题,其实大体上都懂,细节方面没有认识到,这里可以好好总结下了。

  1. ALL IN OBJECT

首先第一点需要知道的是All In Object,也就是说‘一切都是对象’,在javascript中我们认为任何值或变量都是对象,从对象划分等级来说,Object是第一级,Function是第二级,其他String,Array,Date,Number,Boolean,Math等内建对象是第三级,剩下的第四级。
当然你可以会看到如下代码:

function show(x) {
            console.log(typeof x);    // undefined
            console.log(typeof 10);   // number
            console.log(typeof 'abc'); // string
            console.log(typeof true);  // boolean

            console.log(typeof function () {});  //function

            console.log(typeof [1, 'a', true]);  //object
            console.log(typeof { a: 10, b: 20 });  //object
            console.log(typeof null);  //object
            console.log(typeof new Number(10));  //object
        }
        show();
        var fn = function () { };
        console.log(fn instanceof Object);  // true

从上面可以看出typeof来判断可以判断简单值类型:undefined, number, string, boolean,而要判断引用值类型:函数、数组、对象、null、new Number(10) 只能用instanceof来判断。
由于javascript是解析性的弱语言,所以最好的解析All In Object是一切(引用类型)都是对象,对象是属性的集合

  1. prototype

然后再来讲原型prototype,javascript中所有的函数都有prototype这个属性,Object对象本身是一个函数对象。既然是Object函数,就肯定会有prototype属性,所以可以看到Object.prototype的值就是Object {}这个原型对象。反过来,当访问Object.prototype对象的constructor这个属性的时候,就得到了Obejct函数。另外,当通过Object.prototype._proto_获取Object原型的原型的时候,将会得到null,也就是说Object {}原型对象就是原型链的终点了,所以Object就是第一级。

原型链是因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。来一张图可能更直观一点
object-prototype

从图中可以看出一个属性查找的过程,当查找一个对象的属性时,javaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是 Object.prototype),如果仍然没有找到指定的属性,就会返回 undefined。

而对于还问到了对象创建方式影响原型链,其中比较典型的就是new的过程,new 的过程分为三步,如下代码:

var p = new Person('张三',20);//new创建对象方式

var p={}; //第一步:初始化一个对象p。
p._proto_=Person.prototype;//第二步:将对象p的 __proto__ 属性设置为 Person.prototype
Person.call(p,”张三”,20);//第三步:调用构造函数Person来初始化p。关于call/apply使用又可以讲一大堆了...

对于__proto__的解释:__proto__是一个指针,它指的是构造它的对象的对象的prototype

  1. constructor

忘了说构造函数了,constructor官方解析是这样的:在 Javascript 语言中,constructor 属性是专门为 function 而设计的,它存在于每一个 function 的prototype 属性中。这个 constructor 保存了指向 function 的一个引用。
也就是在我们定义一个function的时候会为该function添加一个原形(即 prototype)属性,然后为 prototype 对象额外添加一个 constructor 属性,并且该属性保存指向function的一个引用,这样当我们把function作为自定义构造函数来创建对象的时候,对象实例内部会自动保存一个指向其构造函数。

// 比如一个构造函数:
function Foo() {  }
// 声明一个函数后,默认就生成下面这条语句。
Foo.prototype.constructor === Foo    // true
//修正后,new Foo.prototype.constructor()相当于new Foo()

综上:
所有的对象都有__proto__属性,该属性对应该对象的原型.
所有的函数对象都有prototype属性,该属性的值会被赋值给该函数创建的对象的_proto_属性.
所有的原型对象都有constructor属性,该属性对应创建所有指向该原型的实例的构造函数.
函数对象和原型对象通过prototype和constructor属性进行相互关联.

参考文档:
深入理解javascript原型和闭包(完结)
原型与原型链的详细理解
ES5和ES6中的继承

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions