原型
看下图,构造函数per,通过new实例化per1对象。
此时per1处在一个链上,per1的 __ proto __ 指向构造函数per的prototype上,通过下面的判断即可得出。
任何对象都有一个关联的原型对象,这个原型对象由对象的内置属性 __ proto __ 指向它的构造函数的prototype指向的对象。
也就是说任何对象都是由一个构造函数创建,被创建的对象都可以获得构造函数的prototype属性。
对象没有prototype属性,只有函数才有prototype属性。
任何对象都有一个constructor属性,指向创建此对象的构造函数,比如说{}对象,它的构造函数是function Object(){}。
在JavaScript中,每个函数都有一个prototype属性。
我们任意声明一个函数fn,它的prototype如下图所示:
当一个函数被用作构造函数来创建实例时,这个函数的prototype属性值会被作为原型赋给所有对象实例( __ proto __ ),也就是说,所有的实例的原型引用的是构造函数的prototype。
在构造函数new实例化过程中,new的过程:
var p = {};初始化一个对象p;
p.__ proto __ = Person.prototype;将对象p的 __ proto __ 属性设置为Person.prototype
Person.call(p,“张三”,20);调用构造函数Person来初始化p。
在这里对“prototype”和“proto”进行简单的介绍:
对于所有的对象,都有 __ proto __ 属性,这个属性对应该对象的原型.
对于函数对象,除了__ proto __ 属性之外,还有prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__ proto __ 属性)
属性查找
当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是 Object.prototype),如果仍然没有找到指定的属性,就会返回 undefined。
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.MaxNumber = 9999;
Person.__proto__.MinNumber = -9999;
var will = new Person("Will", 28);
console.log(will.MaxNumber); // 9999
console.log(will.MinNumber); // undefined
在这个例子中分别给”Person.prototype “和” Person.proto”这两个原型对象添加了”MaxNumber “和”MinNumber”属性,这里就需要弄清”prototype”和”proto”的区别了。
“Person.prototype “对应的就是Person构造出来所有实例的原型,也就是说”Person.prototype “属于这些实例原型链的一部分,所以当这些实例进行属性查找时候,就会引用到”Person.prototype “中的属性。
☆实例可以共享原型上面的属性和方法;
☆实例自身的属性会优先被使用,实例自身没有的属性回去原型上面找。
重写原型
原型本身也是对象,并且也是可以被重写的。
function Person(){}
Person.prototype = {
name:'ss',
age:20,
say(){
console.log('Hi');
}
}
重写时需要注意的问题
☆重写原型时,在已经创建了实例的情况下重写原型会切断现有实例与新原型之间的联系
☆重写原型对象,会导致原型对象的constructor属性指向Object,导致原型链关系混乱,所以我们应该在重写原型对象的时候执行constructor(instanceof仍然会返回正确的值)
Person.prototype = {
constructor:Person
}
对象创建方式影响原型链
var July = {
name: "张三",
age: 28,
getInfo: function(){
console.log(this.name + " is " + this.age + " years old");
}
}
console.log(July.getInfo());
当使用这种方式创建一个对象的时候,原型链就变成下图了。July对象的原型是”Object.prototype”也就是说对象的构建方式会影响原型链的形式。
综图所述
- 所有的对象都有__ proto __属性,该属性对应该对象的原型.
- 所有的函数对象都有prototype属性,该属性的值会被赋值给该函数创建的对象的__ proto __属性.
- 所有的原型对象都有constructor属性,该属性对应创建所有指向该原型的实例的构造函数.
- 函数对象和原型对象通过prototype和constructor属性进行相互关联.
原型链
因为每个对象和原型都有原型,对象的原型指向原型对象,
而父的原型又指向父的父,这种原型层层连接起来的关系结构就构成了原型链。
☆所有原型链的终点都是Object函数的prototype属性
☆Object.prototype指向的原型对象同样拥有原型,不过它的原型时null,而null则没有原型
关系判断
instanceof
用于确定原型指向关系的方法,检测的是原型,但是只能用来判断两个对象是否属于实例关系,而不能判断一个对象实例具体属于哪种类型。
hasOwnProperty
通过使用hasOwnProperty可以确定访问的属性是来自于实例还是原型对象