首先放一个在stackoverflow上的图片,该问题的地址:
http://stackoverflow.com/questions/650764/how-does-proto-differ-from-constructor-prototype
记住两条基本规则:
1. 所有的构造函数(也就是类,虽然JS中没有类的概念)和函数的__ptoto__都指向Function.prototype,它是一个空函数。
2. 所有对象的__proto__都指向它的构造函数的prototype。
下面以例子来说明规则:
Number.__proto__ === Function.prototype // true
Boolean.__proto__ === Function.prototype // true
String.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true
Array.__proto__ === Function.prototype // true
RegExp.__proto__ === Function.prototype // true
Error.__proto__ === Function.prototype // true
Date.__proto__ === Function.prototype // true
上面都是JS内置的构造函数。另外对于普通的函数:
function f(){};
f.__proto__ === Function.prototype // true
其实在JS中构造函数和一般函数没有本质的区别,只不过构造函数一般是通过new新的对象来使用,作为类存在,而普通函数都是直接调用。
Math.__proto__ === Object.prototype // true
JSON.__proto__ === Object.prototype // true
Math和JSON是JS内置的对象,使用时无需通过new新的对象来使用,所以它们的构造函数也就是Object。
"abc".__proto__ === String.prototype // true
String对象的构造函数是String
var x = {a: 123};
x.__proto__ == Object.prototype // true
一般的对象的构造函数同样是Object。
function Person(){};
Person.prototype.x = 123;
var p = new Person();
p.__proto__ === Person.prototype // true
对于自定义的构造函数也是一样的,而且:
p.__proto__ === p.constructor.prototype // true
因为p.constructor就是Person。(条件是修改原型)
但是如果是重写原型:
function Person(name) {
this.name = name
}
// 重写原型
Person.prototype = {
getName: function() {}
}
var p = new Person('jack')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // false
那么p.constructor就是Object了,因为p本身没有constructor那么就去寻找p.__proto__的constructor,即Person.prototype的constructor,由于上面Person.prototype是重写的新的对象,它的constructor是Object。
Function.prototype是唯一一个typeof XXX.prototype为 “function”的prototype。其它的构造器的prototype都是一个对象。
总结:
1. __proto__在编程中尽量避免使用,研究它只是用于理解原型和原型链的关系。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
2. 在查找对象的属性时,首先查找自身属性,如果没有,查找对象的__proto__中的属性,以此类推。
3. prototype可以理解为为子对象共享属性的一个接口。
4. __proto__中的属性可以直接 对象名. 取得,而prototype中的属性必须 对象名.prototype.name 取得。
5. 基础是上面提到的那两个基本规则!