写点什么

工厂函数和构造函数

作者:大熊G
  • 2022 年 6 月 06 日
  • 本文字数:1635 字

    阅读完需:约 5 分钟

工厂函数和构造函数

工厂函数

工厂模式是一种设计模式,说白了就是一种简单的函数,这个函数可以创建对象,为它添加属性和方法,然后返回这个对象。就像一个工厂一样,可以批量制作某种类型的对象。这种设计模式是就是为了降低代码冗余。

简单写一个小例子

  function createPerson(name, age) {        let o = new Object();        o.name = name;        o.age = age;        o.sayName = function () {            console.log(this.name);        };        return o;    }    let person1 = createPerson("jackson", 20);    let person2 = createPerson("bear", 22);    person1.sayName(); //jackson    person2.sayName(); //bear
复制代码

这里函数 createPerson()接收俩个参数,根据这几个参数构建了一个包含 person 信息的对象。这样写主要是为了解决需要创建大量有属性重叠的对象,如果每个都 new 一下,然后逐一添加属性。这也是个累人的活。通过上面的代码中,我们声明了一个 createPerson 方法,此方法可批量制造。但是还有缺点,它没有解决对象标识问题(就是创建的对象是什么类型)。

构造函数

构造函数模式可以自定义引用类型,可以使用 new 关键字创建内置类型实例应用创建自定义类型实例,我们常用的 new Vue(),其本质上就是传递 options 参数,实例化一个 Vue 对象。

上面的工厂函数我们可以用构造函数来改进一下

    function Person(name, age) {        this.name = name;        this.age = age;        this.sayName = function () {            console.log(this.name);        };    }    let person1 = new Person("jackson", 20);    let person2 = new Person("bear", 22);    person1.sayName(); // jackson    person2.sayName(); // bear
复制代码

在这个例子中,我们可以发现构造函数可以替代工厂函数,在实际开发中,我们用构造函数的频率一般会大于用工厂函数的频率。

注意:按照惯例,构造函数名称的首字母要大写

要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数,实际上会有以下 5 个步骤。

(1) 在内存中创建一个新对象。

(2) 这个新对象内部的 Prototype 特性被赋值为构造函数的 prototype 属性。

(3) 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。

(4) 执行构造函数内部的代码(给新对象添加属性)。

(5) 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。

构造函数虽然好用,但是也有一些问题,我们分析一下逻辑

上面的例子,person1 和 person2 都有一个 sayName()方法,但这俩个方法却不是同一个 function 实例,相当于这里定义的方法 sayName()会在每个实例上都创建一遍,虽然我们自己省事了,但机器可不省事。

        this.sayName = function () {console.log(this.name);};        //逻辑等价与下面的        this.sayName = new Function("console.log(this.name)"); 
复制代码

优化一下

因为做的事情是一样的,所以没必要定义俩个不同的 Function 实例,我们可以把函数定义转移到构造函数外部。

    function Person(name, age) {        this.name = name;        this.age = age;        this.sayName = sayName;    }
function sayName() { console.log(this.name); } let person1 = new Person("jackson", 20); let person2 = new Person("bear", 22); person1.sayName(); // jackson person2.sayName(); // bear
复制代码

在这里,sayName()被定义在了构造函数外部。在构造函数内部,sayName 属性等于全局 sayName() 函数。因为这一次 sayName 属性中包含的只是一个指向外部函数的指针,所以 person1 和 person2 共享了定义在全局作用域上的 sayName()函数。这样虽然解决了相同逻辑的函数重复定义的问题,但全局作用域也因此被搞乱了,因为那个函数实际上只能在一个对象上调用。如果这个对象需要多个方法,那么就要在全局作用域中定义多个函数。这会导致自定义类型引用的代码不能很好地聚集一起。这个新问题可以通过原型模式来解决。

发布于: 刚刚阅读数: 3
用户头像

大熊G

关注

每天都在写bug的硬核男人 2022.06.02 加入

前端

评论

发布
暂无评论
工厂函数和构造函数_JavaScript_大熊G_InfoQ写作社区