本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金
构造函数
- 构造函数主要作用是用于实例化类,类实例是由构造函数构造的,构造函数的主要任务是初始化实例需要的信息。(通常构造函数的首字母一般大写)。
- 构造函数使用
new关键字调用实现实例化类主要是function Animal () { this.type = 'animal' } let dog = new Animal() let cat = new Animal() dog.type // animal cat.type // animalnew的作用,new的主要作用如下:- 自动创建一个空对象
- 为新创建的对象添加__proto__,将该属性链接至构造函数的原型对象
- 把空对象和函数里的this 衔接起来(this指向实例化对象)
- 隐式返还
this(即该函数没有返回对象,则返回this); 在例子中 ,一个继承自Animal.prototyper的新对象被创建,this会指向dog。所以在调用时Animal里的this会指向dog,因此调用dog.type,会打印'animal'
- 基于
new的作用,可以仿写一个new运算符function mynew(constructor, ...arg) { //创建 一个空对象 let obj = {} // this指向obj对象 constructor.call(obj, ...arg) // 添加属性__proto__,指向构造函数的原型 obj.__proto__ = constructor.prototype; // 返回 对象 return obj } // 使用 let dog = mynew(Animal) dog.type // animal
构造函数的原型链
因为 new会为新的对象添加__proto__,并将该属性链接至构造函数的原型对象,所以原型链如下所示:
其中Animal.prototype会有一个默认的constructor属性,引用对象关联的函数(在本例中是Animal)。
Animal.prototype.constructor === Animal // true
dog.constructor === Animal // true
需要注意的是dog.constructor之所以会“指向创建dog的函数Animal”是因为dog本身并没有constructor属性,访问它时会委托到Animal.prototype,而Animal.prototype.constructor默认指向Foo。
也正因为构造函数有这样的原型链,所以可以用来实现工厂模式。 一个简单的实现如下:
function Animal (name) {
this.name = name
this.type = 'animal'
}
Animal.prototype.myName = function () {
console.log(`my name is ${this.name}`)
}
let dog = new Animal('dog')
let cat = new Animal('cat')
dog.myName() // dog
cat.myName() // cat
访问dog的myName方法,因为本身没有这个方法,会通过原型链访问到Animal.prototype上。因此我们可以在Animal.prototype上定义共有的方法来封装。
继承
构造函数其实也是一种继承,是类和实例之间的继承,dog可以"继承"Animal.prototype并访问到Animal.prototype的MyName函数。而我们更多使用的是类和类之间的继承。
类和类之间的继承主要使用的是Object.create()函数,它会创建一个新对象并把新对象的__proto__关联到你指定的对象。在下面的例子中就是创建一个新的Son.prototype对象并关联到Dad.prototype。(会抛弃默认的Son.prototype)
function Dad (name) {
this.fatherName = name
}
Dad.prototype.fatherName = function () {
console.log(`I'm father ,my name is ${this.fatherName}`)
}
function Son (name, father) {
Dad.call(this, father) //在调用时将Dad的this指向Son,从而在Son中能访问到fatherName
this.sonName = name
}
// 创建一个新的Son.prototype对象并关联到Dad.prototype
Son.prototype = Object.create(Dad.prototype)
// 注意此时Son.prototype.constructor属性会指向Dad,因为它关联到了Dad.prototype,需要手动修复
Son.prototype.constructor = Son
ES6 可以使用Object.setPrototypeOf直接修改现有的Bar.prototype, 此时Son.prototype.constructor不需要修复
Objcet.setPrototypeOf(Son.prototype, Dad.prototype)
Son.prototype.constructor === Son // true
小结
这是最近在重新学习JS相关知识时,所整理的有关构造函数的部分,觉得有所帮助就点个赞和收藏^_^。