JS面向对象中的原型
每一个构造函数都有一个属性 即原型对象(prototype)同时每一个原型对象(prototype)都有一个属性(constructor)指向构造函数,同时每一个对象又有一个__proto__的非标准属性,这个属性指向构造函数的原型对象。
理解上面概念,引入“原型链”
如下新建一个构造函数
function Student(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
}
打印这个构造函数,发现其具有prototype属性,这个属性就是构造函数的原型对象,同时这个原型对象有具有一个属性constructor
属性,这个属性指向构造函数
实例化构造函数
var stu1 = new Student('te','m',12);
console.dir(stu1);
打印结果,印证上面所说的每一个对象又有一个__proto__
属性,这个属性是指向构造函数的原型对象的所以proto ==构造函数的prototype
console.log(stu1.__proto__ === Student.prototype)
//返回true
综上我们可以得出 构造函数 原型对象 以及对象之间的关系
如图
对象通过构造函数创建,而每一个对象有一个__proto__
属性,这个属性是指向原型对象的,而每一个原型对象又有一个constructor
属性,这个属性指向构造函数,上面说到每一个构造函数具有一个prototype
属性,这个属性就是原型对象
由此可以得到一个简单得三角关系。
如果你仔细观察可以发现原型对象也有一个__proto__
属性,这并不奇怪,因为每一个对象都有一个__proto__
属性这个属性是指向他构造函数的原型对象。
查看原型对象的指向
可以看到原型对象的__proto__
属性(这个属性指向Object的原型对象)里面的constructor
属性指向其构造函数Object
那么原型对象也是由构造函数创建,这个构造函数就是Object
。上面说到只要是对象就会有一个__proto__
属性,这个属性指向构造函数的的原型对象,那么Object
的原型对象的原型对象又是什么呢?
var stu1 = new Student('te','m',12);
var o = stu1.__proto__;
console.log(o);//构造函数的原型对象
console.log(o.__proto__.__proto__);//Object的原型对象的原型对象
可以看到Object
的原型对象的原型对象为空null
那么null
有原型对象吗,会不会一直循环下去?
console.log(o.__proto__.__proto__.__proto__);//null的原型对象
抛出异常,说明最顶层的原型对象就是null
,因此我们可以得出一个简单的原型链图
我们通过构造函数创建一个对象,因为每一个对象有一个__proto__
属性,这个属性就指向该对象构造函数的原型对象,由于原型对象也有一个__proto__属性
,这个属性指向原型对象的原型对象,我们可以看到原型对象的原型对象的构造函数为Object
而原型对象是具有__proto__
属性的,而Object
的原型对象的原型对象指向null
所以我们说最顶层的原型对象为null
说了那么多根据原型链我们可以得出对象查找/设置属性和方法的规则
结论
查找:对象在调用属性或方法时,会先在当前对象查找是否有相关属性或方法
如果没有就在当前对象的构造函数的原型对象上查找,如果还是没有则继续在原型对象的原型对象上查找直到指向null
这就是我们所说的原型链。
如下
function Student(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
this.method = function(){
console.log(123)
}
}//构造函数
Student.prototype.method=function(){
console.log(321)
}
var stu1 = new Student('te','m',12);
stu1.method()
我们分别在原型对象和构造函数中写入了相同的方法,结果输出123
如果我们将构造函数中的method
方法去掉则会调用原型对象上的方法输出321
同时我们可以原型链的查找规则使用Object
中的属性或方法,以toString
为例
console.log(stu1.toString());
//返回[object Object]字符串
设置:对象在设置属性/方法时,如果当前对象没有该属性或方法,则重新在当前对象创建一个同名属性/方法,并不会影响原型链上具有的属性或方法
function Student(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
}//构造函数
Student.prototype.method=function(){
console.log(123);
}
var stu1 = new Student('te','m',12);
stu1.method=function(){
console.log(321)
}
var stu2 = new Student('w','w',13);
stu1.method();
stu2.method()
// console.dir(
可以看到stu1并没有修改原型链上的方法