原型和原型链
文章目录
1.原型
1.1 定义
原型是function对象的一个属性(prototype),它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
Person.prototype.LastName = 'Deng';
Person.prototype.say = function () {
console.log('hehe');
}
function Person (name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var person = new Person('xuming', 35, 'male');
1.2 利用原型的特点和概念,可以提取共有属性
原型的共有属性可以减少一定的代码冗余。
function MyCar (color) {
this.color = color;
this.name = 'BMW';
this.height = '1400';
this.lang = '4900';
this.weight = 1000;
this.health = 100;
this.run = function () {
this.health --;
}
}
var car = new MyCar('red');
var car1 = new MyCar('blue');
例如上面代码,Mycar构造函数中,除了color,其他属性都是固定的,每次构造一个新对象都要执行this.xxx = xxx
,这些属性可以看作是共有的,因此写到原型里就可以避免每次构造新对象时重复定义属性。
1.3 对象如何查看原型(隐式属性 __proto__)
在构造函数的内部原理中,第一步var this = {}
,其中{}其实不是空对象,里面含有__proto__ = xxx.prototype
。
对象.__proto__
和构造函数.prototype
都可以访问原型对象。
function Person () {
// var this = {
// __proto__ = Person.prototype;
// }
}
var person = new Person();
修改实例.__proto__
指向别的对象,会改变该实例的原型对象。
1.4 对象如何查看对象的构造函数(constructor)
由构造函数创建出来的对象存在一个constructor属性指向其构造函数。
对象.constructor
会返回该对象的构造函数。
2.理解原型
无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个prototype属性,函数的prototype属性会指向原型对象;
默认情况下,所有原型对象自动获得一个名为constructor
的属性,指回与之关联的构造函数。
每次调用构造函数创建一个新对象,对象内部的[[Prototype]]
指针就会被赋值为构造函数的原型对象。
firefox、safari、chrome浏览器会在每个对象上暴露__proto__
属性,通过这个属性可以访问对象的原型。
构造函数、原型对象和实例(调用构造函数创建的对象)是三个完全不同的对象。实例和原型对象之间有直接的联系,但实例和构造函数之间没有。
实例通过__proto__
链接到原型对象(它实际上指向隐藏特性[[Prototype]]
);构造函数通过prototype属性链接到原型对象,原型对象的constructor
属性指回构造函数。
3.原型链
3.1 原型链的构成
每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。
原型本身作为一个对象,内部也存在一个内部指针指向另一个原型,另一个原型也有一个指针指向另一个构造函数。
以此类推,就在实例和原型之间构造了一条原型链。
3.2 原型搜索机制
原型链扩展了原型搜索机制。
在读取实例上的属性时,首先会在实例上搜索这个属性。如果没有找到,则会继承搜索实例的原型。
在通过原型链实现继承之后,搜索就可以继承向上,搜索原型的原型。
3.3 原型链的终端(默认原型)
绝大多数对象的最终都会继承自Object.prototype
。
默认情况下,所有引用类型都继承自Object,这也是通过原型链实现的。任何函数的默认原型都是一个Object的实例。
3.4 Object.create()
Object.create()方法也可以创建一个新对象,使用现有的对象来提供新创建对象的__proto__
。
特殊地,Object.create()括号中不仅可以放现有对象,还可以放null。
Object.create(null);
创建出的新对象没有任何属性,这意味着这个新对象也没有__proto__
,所以它不会继承自Object。
此时人为给对象添加__proto__
属性是没有效果的。
document.write()
实质上是打印括号中内容的.String。
var obj = Object.create(null);
document.write(obj); //报错
4.函数重写
原型链中的函数重写:
用重名不同功能的函数覆盖继承来的函数。
例如,在Object的原型中,有一个toString函数,而在包装类Number、String、Boolean、Array中各自定义了各自的toString函数,在使用包装类时,调用toString则使用的是重写后的功能。
tips: javascript可正常计算的范围,小数点前16位,后16位。
0.1 + 0.2 == 0.3
为false