theme: channing-cyan
这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
工厂函数
工厂模式是一种设计模式,说白了就是一种简单的函数,这个函数可以创建对象,为它添加属性和方法,然后返回这个对象。就像一个工厂一样,可以批量制作某种类型的对象。这种设计模式是就是为了降低代码冗余。
简单写一个小例子
代码语言:javascript复制 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对象。
上面的工厂函数我们可以用构造函数来改进一下
代码语言:javascript复制 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()会在每个实例上都创建一遍,虽然我们自己省事了,但机器可不省事。
代码语言:javascript复制 this.sayName = function () {console.log(this.name);};
//逻辑等价与下面的
this.sayName = new Function("console.log(this.name)");
优化一下
因为做的事情是一样的,所以没必要定义俩个不同的 Function 实例,我们可以把函数定义转移到构造函数外部。
代码语言:javascript复制 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()函数。这样虽然解决了相同逻辑的函数重复定义的问题,但全局作用域也因此被搞乱了,因为那个函数实际上只能在一个对象上调用。如果这个对象需要多个方法,那么就要在全局作用域中定义多个函数。这会导致自定义类型引用的代码不能很好地聚集一起。这个新问题可以通过原型模式来解决。 我们下一次讲解原型(可以mark一下我的文章,谢谢)