1

哪些对象有原型?
所有的对象在默认情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型(只有一种例外,默认的对象原型在原型链的顶端)

prototype属性
prototype是每个函数对象都具有的属性,被称为原型对象,而__proto__属性才是每个对象才有的属性。一旦原型对象被赋予属性和方法,那么由相应的构造函数创建的实例会继承prototype上的属性和方法

为什么只有函数才有prototype属性?ES规范就这么定的。
当你创建函数时,JS会为这个函数自动添加prototype属性, 值是一个有 constructor 属性的对象,不是空对象。而一旦你把这个函数当作构造函数(constructor)调用(即通过new关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype的所有属性和方法(实例通过设置自己的__proto__指向承构造函数的prototype来实现这种继承)

constructor属性和prototype属性
每个函数都有prototype属性,而这个prototype的constructor属性会指向这个函数。

proto
对象__proto__属性的值就是它所对应的原型对象

var one = {x: 1};
var two = new Object();
one.__proto__ === Object.prototype // true
two.__proto__ === Object.prototype // true
one.toString === one.__proto__.toString // true

下面我们来看个例子来帮助理解这三个属性

function Person(name){
this.name = name;
}
var p1 = new Person('louis');
console.log(Person.prototype);//Person原型 {constructor: Person(name),__proto__: Object}
console.log(p1.prototype);//undefined
console.log(Person.__proto__);//空函数, function(){}
console.log(p1.__proto__ == Person.prototype);//true

我们发现, Person.prototype(原型) 默认拥有两个属性:
constructor 属性, 指向构造器, 即Person本身
proto 属性, 指向一个空的Object 对象
而p1作为非函数对象, 自然就没有 prototype 属性

下面来看看__proto__属性:

p1.__proto__ 属性 指向的是 构造器(Person) 的原型, 即 Person.prototype.
这里我们发现: 原型链查询时, 正是通过这个属性(__proto__) 链接到构造器的原型, 从而实现查询的层层深入.
Person.__proto__ 属性 指向的是一个空函数( function(){} ),

console.log(Person.__proto__ === Function.prototype);//true

Person 是构造器也是函数(function), Person的__proto__ 属性自然就指向 函数(function)的原型, 即 Function.prototype.

这说明 所有的构造器都继承于Function.prototype

既然所有的构造器都来自于Function.prototype, 那么Function.prototype 到底是什么呢?
我们借用 typeof 运算符来看看它的类型.

console.log(typeof Function.prototype) // "function"

实际上, Function.prototype也是唯一一个typeof XXX.prototype为 “function”的prototype。其它的构造器的prototype都是一个对象。如下:

console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Object.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

既然Function.prototype 的类型是函数, 那么它会拥有 proto 属性吗, Function.prototype.__proto__ 会指向哪里呢? 会指向对象的原型吗? 请看下方:

console.log(Function.prototype.__proto__ === Object.prototype) // true

透过上方代码, 且我们了解到: Function.prototype 的类型是函数, 也就意味着一个函数拥有 proto 属性, 并且该属性指向了对象(Object)构造器的原型. 这意味着啥?

根据我们在前面了解到的: proto 是对象的内部属性, 它指向构造器的原型.

这意味着 Function.prototype 函数 拥有了一个对象的内部属性, 并且该属性还恰好指向对象构造器的原型. 它是一个对象吗? 是的, 它一定是对象. 它必须是.实际上, JavaScript的世界观里, 函数也是对象, 函数是一等公民.

这说明所有的构造器既是函数也是一个普通JS对象,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。

Object.prototype
函数的 proto 属性指向 Function.prototype, 如: Person.__proto__ —> Function.prototype

Function.prototype 函数的 proto 属性指向 Object.prototype, 如: Function.prototype.__proto__ —> Object.prototype.

那么Object.prototype.__proto__ 指向什么呢?

console.log(Object.prototype.__proto__ === null);//true

yali
47 声望1 粉丝