用一个实例记录了一下这三者的大致关系,方便复习。
对象构造函数,简称构造函数,用于创建类似的对象。
下面先定义一个构造函数:
function Dog(name, weight) {
this.name = name;
this.weight = weight;
}
注意:
形参名不必与属性名一致,不过为了清晰,常常保持一致;
构造函数名通常首字母大写,便于与其他函数区分开;
然后指定关键字new,再以合适的参数调用构造函数就可以实例化一个对象。
var adog = new Dog("puppy", 28);
调用构造函数新建对象必须使用关键字new,否则可能导致代码出现难以找出的bug
变量adog包含一个指向新建对象的引用。
构造函数的执行过程:new关键字首先创建一个新的空对象,接下来,new设置this,将其指向这个新对象,然后调用构造函数,用实参给新建对象的属性赋值,最后,构造函数返回一个指向新建对象的引用。
如果不使用new关键字,那么构造函数中的this将指向储存全局变量的顶级对象,在浏览器中为window对象。
原型
可以通过构造函数的prototype属性来访问它的原型。
var pro = Dog.prototype;
pro包含了指向构造函数原型的引用
每个原型链的终点都是Object对象,所以我们初始创建的所有构造函数的prototype属性都指向Object,它包含一些方法,常用的如toString()等。
大部分情况下,用户新建的对象都继承了Object对象的方法。
那么原型有什么用呢?
如果我们需要创建大量类似的对象,并且需要包含同样的方法,那么可以将方法写入原型,这样继承该原型的对象都会包含这些方法。之所以不用构造函数定义方法,是因为每个对象都是一个实例,每个对象都会重新创建一组新的方法,创建大量相同的方法,会影响程序性能,占用计算机资源。
重写原型:
Dog.prototype.bark = function(){
//函数体
};
这样,所有通过Dog创建的对象都包含了bark方法。
var adog = new Dog("aa", 20);
var bdog = new Dog("bb", 40);
adog和bdog都是以Dog为原型的实例,都继承了bark方法。
可以根据需要添加更多方法。如果需要为每个实例创建一个默认的属性,也可以写入原型。
Dog.prototype.health = true;
这为每个实例的狗添加了初始健康状态,最初都是健康的。
接下来,定义一个以Dog为原型的构造函数。
function Police_dog(name, weight, breed,intellect){
this.name = name;
this.weight = weight;
this.breed = breed;
this.intellect = intellect;
}
Police_dog.prototype = new Dog();
要将新的构造函数的原型属性设置为一个新建的Dog实例,这里不需要为Dog提供参数。
下面就可以以上述同样的方法改写原型了。
Police_dog.prototype.bait = function(){
//函数体
};
Police_dog.prototype.league = "awesome";
然后实例化一个对象。
var handsome_dog = new Police_dog("hdog", 50, "German shepherd", 88);
这个对象不仅有自己专属的方法和属性,还包含了Dog原型和Object对象中的方法和属性。
最后需要注意的是,实例对象有一个属性constructor,它指示了对象的构造函数。handsome_dog是用构造函数Police_dog创建的实例,但是如果没有显式地设置Police_dog的constructor属性,那么这个属性会继承自Dog实例,所以handsome_dog的constructor属性为Dog。
最好在修改完原型之后就把这个属性修改过来。
function Police_dog(name, weight, breed,intellect){
this.name = name;
this.weight = weight;
this.breed = breed;
this.intellect = intellect;
}
Police_dog.prototype = new Dog();
Police_dog.prototype.construtor = Police_dog;