构造函数笔记

构造函数

  • 构造函数主要作用是用于实例化类,类实例是由构造函数构造的,构造函数的主要任务是初始化实例需要的信息。(通常构造函数的首字母一般大写)。
  • 构造函数使用new关键字调用
    1
    2
    3
    4
    5
    6
    7
    function Animal () {
    this.type = 'animal'
    }
    let dog = new Animal()
    let cat = new Animal()
    dog.type // animal
    cat.type // animal
    实现实例化类主要是new的作用,new的主要作用如下:
    1. 自动创建一个空对象
    2. 为新创建的对象添加proto,将该属性链接至构造函数的原型对象
    3. 把空对象和函数里的this 衔接起来(this指向实例化对象)
    4. 隐式返还this(即该函数没有返回对象,则返回this);
      在例子中 ,一个继承自Animal.prototyper的新对象被创建,this会指向dog。所以在调用时Animal里的this会指向dog,因此调用dog.type,会打印’animal’
      • 基于new的作用,可以仿写一个new运算符
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        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,并将该属性链接至构造函数的原型对象,所以原型链如下所示:

构造函数原型.png

其中Animal.prototype会有一个默认的constructor属性,引用对象关联的函数(在本例中是Animal)。

1
2
Animal.prototype.constructor === Animal // true
dog.constructor === Animal // true

需要注意的是dog.constructor之所以会“指向创建dog的函数Animal”是因为dog本身并没有constructor属性,访问它时会委托到Animal.prototype,而Animal.prototype.constructor默认指向Foo。

也正因为构造函数有这样的原型链,所以可以用来实现工厂模式。 一个简单的实现如下:

1
2
3
4
5
6
7
8
9
10
11
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)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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不需要修复

1
2
Objcet.setPrototypeOf(Son.prototype, Dad.prototype)
Son.prototype.constructor === Son // true

小结

这是最近在重新学习JS相关知识时,所整理的有关构造函数的部分,觉得有所帮助就点个赞和收藏^_^。