原型的5个规则
- 所有的引用类型(数组,对象,函数),都具有对象特性,即可自由扩展属性(除了“null”)
var obj ={};obj.a=100
//100
var arr=[];arr.a=100
//100
function fn(){}
fn.a=100
//100
- 所有的应用类型,都有一个proto属性(隐式原型),属性值是一个普通的对象
console.log(obj.__proto__);
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(arr.__proto__);
//[constructor: ƒ, concat: ƒ, pop: ƒ, push: ƒ, shift: ƒ, …]
console.log(fn.__proto__);
//ƒ () { [native code] }
- 所有的函数都有一个prototype属性(显式原型),属性值也是一个普通对象
console.log(fn.prototype)
//{constructor: ƒ}
- 所有的引用类型的 proto属性值指向它的构造函数prototype属性值(即所有引用类型的隐形原型指向他的构造函数的显式原型)
console.log(obj.__proto__===Object.prototype); //true
//Object是一个构造函数
- 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去他的proto(即它的构造函数的prototype)中寻找
/*测试*/
function Foo(name,age){
this.name = name;
}
Foo.prototype.alertName = function(){//由于Foo.prototype本身也是一个对象,而对象是可以自由扩展属性的
alert(this.name);
}
var f = new Foo('zhan');
f.printName = function(){
console.log(this.name);
}
f.printName();//zhan 可以直接在这个对象中找到这个属性
f.alertName();//alert弹出zhan 这时候在这个对象本身找不到这个属性,去Foo.prototype找,得到值
/*******************************/
/*之前在牛可网碰到到一道面试题*/
var A = {n:4399};
var B = function(){
this.n = 9999;
}
var C = function(){
var n = 8888;
}
B.prototype = A;
C.prototype = A;
var b = new B();
var c = new C();
A.n++;
console.log(b.n);//9999
console.log(c.n);//4400
//先从他的实例中找,找不到去它的构造函数的prototype中找
this
对上面测试代码来说,永远指向对象本身,所以执行f.alertName
可以弹出zhan
循环自身的属性
还是对上面的测试代码来说,如果对进行循环的话,可以找到,name属性,alertName属性,printName属性,但是一般情况下,我们只希望得到这个对象自身定义的属性,比如:name属性与printName属性
var item
for(item in f){
if(f.hasOwnProperty(item)){
console.log(item);
// 高级浏览器已经在forin中屏蔽了来自原型的属性
//但在这里建议大家还是加上这个判断,保证程序的健壮性(程序对于规范要求以外的输入情况的处理能力)
}
}