JS面向对象中的原型 每一个函数都有一个属性 即原型对象(显式原型:prototype)这个原型对象默认指向一个Object空对象,同时每一个原型对象(prototype)都有一个属性(constructor)又指向构造函数(构造函数和它的原型对象相互引用),同时每一个实例对象又有一个__proto__
属性(隐式原型),这个属性指向其构造函数的原型对象 (Fn.prototype===fn.__proto__
)。
需要注意的是每个函数也有一个隐式属性
__proto__
,因为函数是Function的实例
理解上面概念,引入“原型链” 如下新建一个构造函数
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
综上我们可以得出 构造函数 原型对象 以及对象之间的关系 如图
方便理解为每个步骤列图 1.当创建构造函数时 此时在栈区创建了一个函数名(Student)存储的是地址值(0x123)指向堆区的Function对象,这个对象会有一个prototype属性,指向默认的空Object对象
2.当实例化构造函数时 在栈取创建了一个stu1
存储的是地址值(0x345)执行堆区的Student实例对象,这个对象会生成一个隐式原型__proto__
属性,这个属性也执行prototype指向的对象(__proto__
=Student.prototype)
3.当为原型对象添加方法时
对象通过构造函数创建,而每一个对象有一个__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并没有修改原型链上的方法
表达式 A instanceof B 如果B函数的显示原型对象在A对象的原型链上,返回true,否在返回false
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有