继承和原型链
大家好,这篇文章我将会和大家分享JS关于继承和原型链的有关知识。
首先,让我们了解一下什么是原型对象。
JS在加载构造函数时,会在内存中生成一个对象,这个对象称为函数的原型对象(prototype)。
每个实例对象(object)都有一个私有属性(称之为__proto__),指向它的构造函数的原型对象。这个原型对象也有一个自己的原型属性,指向它的构造函数的原型对象,层层向上直到一个对象的原型对象为null,根据定义,null没有原型,并作为这个原型链中的最后一个环节。
请看下面的例子
代码语言:javascript复制遵循ECMAScript标准,[[Prototype]]用于表示实例对象的原型属性,这和非JavaScript标准但很多浏览器实现的proto属性一样,但不应与prototype混淆。
var object = new Object();
//object是Object的一个实例对象
//object.[[Prototype]]指向Object.prototype
null位于原型链的顶端,根据定义,null就是没有原型。
继承属性
JavaScript对象是动态的属性“包”,它有一个指向它的原型的链。当试图访问一个对象的属性时,它不仅仅会在该对象上搜寻,还会在该对象的原型上搜寻,直到找到名字相同的属性或到达原型链的末尾。
代码语言:javascript复制function Car(){
this.showColor = function(){
console.log(this.color);
}
}
Car.prototype.color = "red";
var car = new Car();
car.showColor();//log "red"
car.color = "blue";
car.showColor();//log "blue";
//Car.prototype上有属性color,但car已经有color属性,所以不会再向上搜寻,这种现象叫做属性屏蔽
继承方法
JavaScript没有像其他基于类的语言所定义的“方法”,任何函数都可以添加到对象上作为对象的属性。函数的继承和其他属性的继承没有差别,包括上面的属性屏蔽。
需要注意的是,当继承的函数被调用时,this
指向的是当前继承的对象,而不是继承的函数所在的原型对象。
function Car(){
this.showColor = funciton(){
console.log(this.color);
}
}
Car.color = "red";
var car = new Car();
car.showColor();//log "red"
使用不同的方法来创建对象和生成原型链
使用语法结构创建对象
代码语言:javascript复制var car = {a:1};
//这个对象car/继承了Object.prototype上的所有属性
//Object.prototype的原型为null
//原型链为car --> Object.prototype --> null
var a = [a:1];
//数组都继承于Array.prototype
//Arrat.prototype继承于Object.prototype
//原型链为a --> Array.prototypr --> Object.prototype --> null
function f(){
}
//函数都继承于Function.prototype
//原型链为f --> Funciton.prototype --> Object.prototype --> null
使用构造器创建对象
在JavaScript中,构造器其实就是一个普通的函数。当使用new
操作符来作用这个函数时,它就可以被称为构造方法(构造函数)。
function Car(){
this.color = "red";
}
var car = new Car();
//car是生成的对象,它自身拥有属性color
//在car/被实例化时,car.[[prototype]]指向了Car.prototype
使用Object.create()创建对象
ECMAScript 5中引入了一个新方法: Object.create()。可以调用这个方法来创建一个新的对象。新的对象的原型就是这个方法中传入的第一个参数。
代码语言:javascript复制var Car = {
color : "red"
}
var car = Object.create(Car);
//car.[[Prorotype]]为Car
//原型链为car --> Car --> Function.prototype --> Object.prototype --> null
使用class
关键字创建对象
ECMAScript6引入了一套新的关键字来实现class
。使用基于类语言的开发人员会对这些结构感到熟悉。但它们是不同的,JavaScript仍然基于原型。
class Hang{
constructor (color){
this.color = color;
}
}
var hang = new Hang("red");
性能
在原型上查找属性比较耗时,会对性能产生一些副作用。这在对性能要求苛刻的场景很重要。另外,试图访问不存咋的属性时会遍历整个原型链。
遍历对象的属性时,原型链上的每个可枚举属性都会被枚举出来出来。要检查对象是否具有自己的每个属性,而不是其原型链上是否具有每个属性,则必须使用对象从Object.prototype上继承的hasOwnProperty
方法。