原型链
原型链
背景
大部分面向对象的编程语言,都是通过“类”(class)来实现对象的继承。JavaScript 语言的继承则是通过“原型对象”(prototype)。
概述
构造函数
定义:
需要用 new 关键字来调用的函数(new 执行的过程)
为什么用:
在使用对象字面量创建一系列同一类型的对象时,这些对象可能具有一些相似的特征(属性)和行为(方法),此时会产生很多重复的代码,而使用构造函数就可以实现代码的复用。
e.g.
function Animal(color) {
this.color = color;
}缺点
构造函数类似于一个模板,固定输入会得到固定输出,但是同一个构造函数的多个实例之间,是无法共享属性的。
function Cat(name, color) {
this.name = name;
this.color = color;
this.meow = function() {
console.log('喵喵');
};
}
var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色');
cat1.meow === cat2.meow;
// falseprotortype / __proto__
protortype / __proto__每个函数都有一个 prototype 属性,指向一个对象,对于构造函数实例化的时候,该对象就成为了实例对象的原型。
实现思路:所有实例都能共享原型对象(prototype)的属性和方法。
好处:
节省内存空间;
共享数据,建立实例间的联系。
function Student() {}
Student.prototype.class = 'class A';
var student1 = new Student();
var student2 = new Student();
student1.class; // class A
student2.class; // class A
Student.prototype.class = 'class B';
student1.class; // class B
student2.class; // class B特殊:当实例自身拥有某个属性或方法的时候,就不会从原型上去寻找该属性或方法了。
每个对象拥有一个
__proto__属性,指向的就是构造函数的原型对象(prototype)。
原型链
每个对象有拥有一个自己的原型,而每个原型也都是一个对象,也拥有自己的原型,因此会行程一条链路——原型链。
所有对象网上追溯都会追溯到
Object.protptype,即为 Object 构造函数的 prototype 属性。Object.prototype的原型是null。Object.getPrototypeOf(Object.prototype) // nullObject.getPrototypeOf方法返回参数对象的原型
过程:
读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的 Object.prototype 还是找不到,则返回 undefined。如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)
注意:如果寻找层级过深,有可能会影响性能。
constructor
prototype 对象内有一个 constructor 属性,默认指向的是 prototype 所在的构造函数。它是从原型对象到构造函数关联的一个桥梁。
存在的意义:
可以得知某个实例对象是由哪个构造函数所创建的
可以通过一个实例去创建另一个实例
function Fun() {} var f = new Fun(); var f2 = new f.constructor(); f2 instanceof Fun; // true
修改原型对象的时候切记要修改对应的 constructor,防止引用错误(e.g.直接修改**.prototype = {})
good:(保证
instanceof不会失真)function Fun(){} Fun.prototype.** = function(){} // better Fun.prototype = { // good constructor: Fun, **: **, }bad:
function Fun(){} Fun.prototype = { **: ** }
可以通过*.contructor.name 获取对应构造函数的名称
instanceof
用于判断某个实例是否由某个构造函数所创建的。
判断值的类型(用于判断最上层构造函数)
例如
var arr = []; arr instanceof Array; // true arr instanceof Object; // true
只能用于对象的判断,不适用于原始值类型。
对于 undefined 和 null,instanceOf 运算符总是返回 false。
检查的是整个原型链上的构造函数。
function A() {} var a = new A(); a instanceof A; // true a instanceof Object; // true A instanceof Function; // true A instanceof Object; // truea instanceof A等价于A.prototype.isPrototypeOf(a)
Object.create
接收一个对象参数并返回一个对象结果,传入的参数为返回值的原型
特殊:当传入 null 时,返回的对象是没有原型的,此时 instanceof 会失真
继承
原型链继承
构造函数继承(经典继承)
实例继承(原型式继承)
组合继承
寄生组合继承
ES6 继承
和原型相关的一些主要方法
Object 自身的方法:
Object.getPrototypeOf(获取指定对象原型)Object.getPrototypeOf(instance) === instance.__proto__Object.getPrototypeOf(Object)不是Object.prototype,而是Function.prototypeObject.getPrototypeOf(Object.prototype) // null
Object.prototype 上的方法:
Object.prototype.isPrototypeOf(测试一个对象是否存在于另一个对象的原型链上)Object.prototype.isPrototypeOf(instance); // trueinstance instanceof Object; // trueisPrototypeOf() 与 instanceof 运算符不同。在表达式 "object instanceof AFunction"中,object 的原型链是针对 AFunction.prototype 进行检查的,而不是针对 AFunction 本身。
Object.prototype.hasOwnProperty(判断自身是否有某属性,不包含原型)Object.prototype.propertyIsEnumerable(表示指定的属性是否可枚举,即属性是否可以被 for...in 循环枚举,注意:在原型链上 propertyIsEnumerable 不被考虑)
Last updated
Was this helpful?
