原型对象prototype
ES6引入了class语法,这里暂不涉及。
原型对象概述
1.构造函数的缺点
JavaScript通过构造函数生成新对象,因此构造函数可以视为一个模版,用于生成实例对象以及该实例对象的属性与方法。
function Animal(type,name){
this.type=type;
this.name=name;
}
var pp=new Animal("pig","pp");
pp.type;// pig
pp.name;// pp
上面代码中,构造函数Animal
定义了type
和name
属性,所有由函数Animal
构造的实例对象,都具有这两个属性。
缺点
通过构造函数为定义实例对象的属性,虽然很方便,但是,同一个构造函数构建的实例对象之间,无法共享属性,会造成资源的浪费
function Animal(type,name){
this.type=type;
this.name=name;
this.voice=function(){
console.log("hanghang");
};
}
var pp=new Animal("pig","pp");
var uu=new Animal("pig","uu");
pp.voice===uu.voice ;//false
上面代码表示,pp
和uu
是构造函数Animal
的两个实例,他们有着相同的voice
方法,但是该方法是生成在每个实例对象上,有几个实例对象就要生成几次,这样就导致了资源的浪费。
因为该方法在不同实例对象间,执行结果都是一样的
在此背景下,JavaScript
引出了一个解决方法,那就是原型对象(prototype
)
2. prototype属性的作用
简单来说,当属性和方法定义在原型(prototype
)上时,那么所有的实例对象都能共享,不仅节省了内存,还体现了实例对象之间的联系。
如何为对象指定原型?
JavaScript
规定,每个函数都有一个prototype
属性,指向一个对象。
function f(){}
type of f.prototype; //object
上述代码中,函数f默认有prototype属性,指向一个对象。
对于普通函数来说,这个属性可有可无,但是当这个属性定义在构造函数上时,该属性会自动成为实例对象的原型。
function Animal(type,name){
this.type=type;
this.name=name;
};
}
Animal.prototype.voice=function(){
console.log("hanghang");
}
var pp=new Animal("pig","pp");
var uu=new Animal("pig","uu");
pp.voice(); //hanghang
uu.voice(); //hanghang
上面代码中,voice
是定义在构造函数Animal
原型上的方法,可以被uu
和pp
两个实例对象共享。
原型对象上的方法不是实例对象自身的方法,如果对其进行修改,变动会体现在所有的实例对象上。
Animal.prototype.voice=4;
pp.voice; //4
uu.voice; //4
上述代码表示,改变对构造函数原型上的方法,变动会体现在所有的实例对象上
只有当该实例对象没有某个属性或方法时,它才会去原型上找,否则将直接使用实例对象自带的
pp.voice="hanghang";
上面代码中,实例对象pp
的voice
属性改为了"hanghang",使得它不再去原型对象读取voice
属性。
总结一下,原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象。
Animal.prototype.walk = function () {
console.log(this.name + ' is walking');
};
上面代码中,Animal.prototype
对象上面定义了一个walk
方法,这个方法将可以在所有Animal
实例对象上面调用。
3.原型链
产生原因
JavaScript
规定,所有对象都有自己的原型对象(prototype
)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain
):对象到原型,再到原型的原型……
按照这个思路,所有对象的原型最终都可以追溯到Object.prototype
。也就是说,所有的对象都可以继承定义在Object.prototype
下的方法如valueOf
和toString
等。
Object.prototype
对象的原型是null
,本文不详细介绍
读取对象的某个属性时,JavaScript
引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype
还是找不到,则返回undefined
。
如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding
)。
注意,一级级向上,在整个原型链上寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
举例来说,如果让构造函数的prototype
属性指向一个数组,就意味着实例对象可以调用数组方法。
var MyArray = function () {};
MyArray.prototype = new Array();
MyArray.prototype.constructor = MyArray;
var mine = new MyArray();
mine.push(1, 2, 3);
mine.length // 3
mine instanceof Array // true
上面代码中,mine
是构造函数MyArray
的实例对象,由于MyArray.prototype
指向一个数组实例,使得mine
可以调用数组方法(这些方法定义在数组实例的prototype
对象上面)。
最后那行instanceof
表达式,用来比较一个对象是否为某个构造函数的实例,结果就是证明mine
为Array
的实例。
上面代码还出现了原型对象的constructor
属性,这个属性默认指向prototype对象所在的构造函数。
参考链接
JavaScript Modules: A Beginner’s Guide-----Preethi Kasireddy
最后,希望能和大家一起进步! |
---|
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!