目录
构造函数
构造函数是一种特殊的方法,主要作用是和new关键字搭配以创建对象,它的函数名首字母通常大写,以区分普通函数。构造函数在创建时会产生一个空对象,函数内部的this便指向这个空对象,当用户将空对象实例化后,便有了具体的值。
function People(name,age,gender){
this.uname=name;
this.uage=age;
this.ugender=gender;
}
// 【new】 函数创建一个对象
let p=new People("js",14,"男");//实例化对象
console.log(p);
原型和原型链
People下有一个属性Prototype,属性值是一个对象,其中存放公共方法,这是People函数的原型对象,原型对象中存在构造方法指向该原型对象的所在的构造方法,当构造函数访问原型对象时,使用 构造函数名.prototype 若原型对象需要访问构造函数,则使用 原型对象名.constructor
在原型对象下也存在原型对象Prototype,它的构造方法则指向Object类
通过构造方法产生的实例化对象也存在原型对象,它访问原型对象则是 实例化对象.__proto__ ,而实例化对象需要访问构造函数,则使用 原型对象名.constructor
需要注意的是,原型对象也是对象,因此原型对象也存在他自己的原型对象和构造函数
对于上图中,实例化对象访问原型对象的原型对象产生的路径,即为原型链
继承
当子构造函数的原型对象指向父构造函数时,子构造函数就可以继承父构造函数的方法和属性,而子构造函数依然可以保持自己的私有属性
function Father(age,name){
this.age=age;
this.name=name;
}
function Child(age,name,gender){
Father.call(this,age,name);
this.gender=gender;
}
Child.prototype=new Father();
Child.prototype.game=function(){
console.log("playing game");
}
let child=new Child(13,"xixi","男");
console.log(child);
在上述代码中,通过子构造函数Child创建的实例化对象,在子构造函数内部调用了父构造函数。
注:由于构造函数在调用的时候,this指向调用自己的实例化对象,但是child并不是Father构造函数的实例化对象,因此我们必须要修改this的指向,使其指向本构造函数中的属性
但上述代码中存在一个问题,子构造函数的原型对象指向父构造函数后,子构造函数确实可以继承父构造函数的方法,但同时,子构造函数的私有方法却也能够被父构造函数调用,失去私有性。
解决这个问题仅需要一个实例化对象,其中原理如下图所示
在上图中,我们新创建了一个Father构造函数的实例化对象,但是它和Child构造函数还没有联系,此时我们将child构造函数对原型对象的指向修改到Father构造函数的实例化对象上,则该实例化对象可以作为一个原型对象存在,这个实例化对象可以访问Father构造函数及其原型对象。如此便满足了Child构造函数的私有性,和对Father构造函数属性方法的继承。具体实现代码如下:
function Father(age,name){
this.age=age;
this.name=name;
}
let father =new Father(17,"haha");
function Child(age,name,gender){
Father(age,name);
this.gender=gender;
}
Child.prototype=new Father();
Child.prototype.constructor=Child;
Child.prototype.game=function(){
console.log("playing game");
}
let child=new Child(13,"xixi","男");
console.log(child);
Child.prototype=new Father();
将Child构造函数的原型对象改为Father构造函数的实例化对象
Child.prototype.constructor=Child;将Child的新的原型对象的构造函数改为Child构造函数