乐趣区

图解javascript原型原型链

我们在学习 javascript 时,经常会听到“万物皆对象”,但是呢,其实万物皆对象的对象也有区别。分为普通对象和函数对象。
1. 对象分为函数对象和普通对象
    通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。

2. 构造函数
而提到 new 关键字,我们不得不提到构造函数。构造函数又分为自定义构造函数及 native 构造函数(即构造器)
2.1 自定义构造函数

 function Person(name,age,job){
        this.name = name;
        this.age = age;
        this.job = job;
    }
    var miya = new Person('miya',18,'engineer'); //miya 是构造函数 Person 的实例;

而实例的构造函数属性 (constructor) 都指向构造函数
    即:miya.constuctor = Person 
    
2.2 构造器 
    js 内置的构造器包括 Number,Boolean,String,Object,Function,Array,RegExp,Error,Date 等
同样的,我们的构造器的实例也有一个 constuctor 指向它的构造器
   

    let miya= new Array()
    miya.constuctor ==Array;

通过以上的分析,我们可以得到以下这张图    

这里扩展一下,其实我们在做类型判断的时候习惯用 typeof,typeof 判断简单数据类型的时候其实是 ok 的。但是 typeof 有判断复杂数据类型不是很清晰,得到的基本是 String 或者 Function
比如一下图示判断

但是,通过上述我们知道构造器的实例都有一个 constructor 的属性指向构造器。那其实我们直接用 constructor 便可以清晰地知道这个实例从哪里来。

3. 原型对象
    每个函数对象都有一个 prototype 属性,这个属性指向函数的原型对象即 prototype。
    所有的 prototype 会有一个默认的 constuctor 属性,指向函数对象本身。

function Person(name,age,job){
this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype.sayName = function () {console.log(this.name);
};

let miya = new Person('miya',18,'engineer');
let tiffany = new Person('tiffany',18,'engineer');
miya.sayName();  //miya
tiffany.sayName();  //tiffany
console.log(miya.sayName == tiffany.sayName);  //true
console.log(Person.prototype.constructor == Person);  //true

通过:Person.prototype.constuctor = Person,因为构造函数的实例是有一个 constructor 的属性指向构造函数的,我们可以得到结论其实 Person.prototype 也是 Person 的实例
    即:原型对象是构造函数的一个实例【原型对象(Function.prototype 除外) 是一个普通对象,而不是函数对象】

4.__proto__属性
    4.1 JS 在创建对象的时候都会有一个__proto__指向它的构造函数的原型对象

其实,每个对象都有一个__proto__属性,但只有函数对象有 prototype 属性。
因此,可以得到以下这样图。

    4.2 构造函数扩展
  而我们的构造函数本质上都是从 Function new 出来的。他们本质上都是 Function 的一个实例。都有一个__proto 属性指向 Function 的原型,也有一个 constructor 属性指向 Function。

    提示:Math,JSON 是以对象形式存在的,无需 new。他们的__proto__是 Object.prototype 

因此可以得到以下的图示,所有的函数对象的__proto__都指向 Function.prototype(是一个空函数)


5. 函数对象
    1. 所有的构造器都是通过 Function new 出来的,他们都是 Function 的实例,他们的__pro__都指向 Function.prototype,甚至包括根构造器 Object 及 Function 本身。

Number.__proto__ === Function.prototype  // true
Number.constructor == Function //true

String.__proto__ === Function.prototype  // true
String.constructor == Function //true

Object.__proto__ === Function.prototype  // true
Object.constructor == Function // true

Function.__proto__ === Function.prototype // true
Function.constructor == Function //true

    2. 除 Object.prototype 外,所有的构造器的 prototype 的__proto__属性都指向 Object.prototype

Function.prototype.__proto__ === Object.prototype; // true
Number.prototype.__proto__ === Object.prototype; // true
String.prototype.__proto__ === Object.prototype; // true
Array.prototype.__proto__ === Object.prototype; // true
Boolean.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === Object.prototype; // true


    3. 那 Object.prototype 的__proto__属性是指向 null 的。

Object.prototype.__proto__ === null; // true

    Function.prototype 也是唯一一个 typeof XXX.prototype 为 function 的 prototype    
    推导 Function.prototype.__proto__是什么呢?Object.prototype
    所有的构造器都继承 Function.prototype 的属性及方法 => 所有的构造器函数都是普通的 js 函数可以用 Object 的方法
    Object.prototype.__proto__ == null
 
 

console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype)   // object
console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Array.prototype)    // object
console.log(typeof RegExp.prototype)   // object
console.log(typeof Error.prototype)    // object
console.log(typeof Date.prototype)     // object
console.log(typeof Object.prototype)   // object

 
补充:
    null 是一个独立数据类型,而不是一个空引用,只是期望此处引用一个对象 https://developer.mozilla.org…
    typeof null == Object 是一个遗留 bug

退出移动版