一.什么是构造函数?
构造函数和普通函数主要区别于它首字母大写,如下所示:
function Fun1(name,Class){
this.name=name;
this.age=age
}
一个构造函数可以有多个实例化对象
function Fun1(name,Class){
this.name=name;
this.class=Class;
this.fun=function(){
console.log(this.name+'是'+this.class+'班的学生')
}
}
var stud1=new Fun1('小明',5)
var stud2=new Fun1('小王',5)
console.log(stud1,stud2,1111)
stud1.fun()
stud2.fun()
如上所示一个构造函数Fun1它可以有多个实列对象,比如stud1和stud2
但是我们从结果上可以看出来虽然两个实列化对象都是源于一个构造函数,但是他们的数据却不可以互通,最通俗的理解就是只有一个班级,但是每实列出一个同学的信息就会重复创造出class班级这个属性,然而每一个同学的班级都是一样的且只有一个。这样就造成了内存的浪费。所以为了避免内存资源的浪费,就可以用到原型对象prototype。
二、prototype属性(原型对象)
JavaScript中每一个对象都继承另一个对象,父类对象称之为“原型”(prototype)对象。只有null除外,其他都有自己的原型对象。原型对象上的所有属性和方法,都能被派生(子类)对象共享‘
由构造函数的得到的实例化对象,它的原型对象就是构造函数上的prototype,每一个函数(构造函数)都会有arguments和prototype 属性(但是箭头函数没有)详细区别链接
所以我们可以把共用的属性以及方法都放在原型对象上,避免重复创造
function Fun1(name,Class){
this.name=name;
this.fun=function(){
console.log(this.name+'是'+this.class+'班的学生')
}
}
Fun1.prototype.class='5'//在原型对象上添加class属性
var stud1=new Fun1('小明')
var stud2=new Fun1('小王')
stud1.fun()
stud2.fun()
得出结果如下
上述中我们在两个实例化对象的构造函数原型对象上添加了一个class属性,结果两个实例化对象都可以读取属性,实现了属性共享。虽然原型对象属性不是实例化对象本身的属性,但是只要原型对象上属性修改,就会同步更新到所有由同一个构造函数创造出的实例化化对象上。
三、原型链
对象的属性和方法,有可能是定义在自身内,也有可能是定义在它的原型对象上。由于原型对象本身也是对象,又有自己的原型,所有生成了一条原型链(prototype chain)。例如,a对象是b对象的原型,b对象是c对象的原型,依次类推。如果那么一层层地上溯,所有对象的原型最终都可以上溯到Object对象上。Object对象也有原型就是一个没有任何属性和方法的null对象,而null对象没有自己的原型。
function Student(Name){
this.name=Name;
}
var stu1=new Student('aklman');
console.log(Student.prototype);
console.log(Student.prototype.constructor.prototype);
//由于对象自身直接获取原型对象,最终的大对象就是object,也就是说,在JavaScript中所有对象(不管从何而来)都基于object大对象,而最大对象Object的原型指向null,也就是没有
console.log(stu1.__pro__.__proto__.__proto__);
原型链的作用是读取对象某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到就找它的原型(父类对象),如果还是找不到就找原型的原型。如果直到最顶层的Object。prototype还是找不到,则返回undefined。
注意:一级级向上,在原型链寻找某个属性,对性能是有影响的。如果寻找某个不存在的属性将会遍历整个原型链。
实际开发上注意事项:通常使用第三方框架(一个类),但是我们发现这个类中并不存在我们想要的属性或方法时,不能直接修改源代码,但是可以通过原型对象来添加我们想要的属性和方法。