”谈一谈“之ES5创建对象的7种方式

327 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

”谈一谈“之ES5创建对象的7种方式

在javascript这门语言中,对象是一个说简单就简单,说难就难的一个点。 今天就聊一聊创建的几种方式。

1.工厂模式

function Factory (a,b,c){
    let obj = {}
    obj.a = a;
    obj.b = b;
    obj.c = c;
    obj.callA = function(){
        alert(this.a+ ':a')
    }
    return obj
}
let fa = Factory('a','b','c');
console.log(fa)

打印结果:

image.png

缺点:这里确实创造出了一个对象,但是不清楚他的原型是谁,可以看到construct指向了Object。

联想:简单的理解就是有一个工厂,工厂生产汽车,汽车是生产出来了,但是我不清楚生产汽车发动机的厂商是哪个,这样客户肯定不会买单的,所以这样的方式创建是不推崇的。

2.构造函数

function Constru (a,b,c){
    this.a = a;
    this.b = b;
    this.c = c;
    this.callA = function(){
        alert('a')
    }
}
let con = new Constru('a','b','c');
console.log(con)

打印结果:

image.png

这边结果和工厂模式类似,可以看出这个对象创建出来的构造函数指向了Constr。在new出的过程中发生了以下的4个步骤:

  • 创建一个新对象
  • 将构造函数的作用域给了新对象(改变this的指向)
  • 执行构造函数中的代码
  • 返回一个新的对象

相比工厂模式,这边明显的能清楚的知道属于那个类型,可以使用instanceof来验证

 fa in stantceof Object //true
 fa in stantceof Factory  //true

这就是构造函数方式优于工厂模式的一个地方。

缺点:构造函数的方式设计还是存在了一定的问题,比如我创建了两个对象

let co1 = new Constru('a','b','c');
let co2 = new Constru('a','b','c');

这两个对象的callA这个方法其实是一样的,我们重复的去在这个对象上面创建了这两个方法,这样设计明显是多余的,也不符合变成的封装性和继承性。因此有了原型模式。

联想:我有个工厂,打开机器后,这个工厂就会以机械的方式返回你需要的产品,这样看起来很快捷。但是比如我需要生产一个柜子,柜子里面会用到螺丝,这个螺丝每次我都要去造一次,这样效率会大大的减少。

3.原型模式

function Proto(){}
Proto.prototype.a = 'a'
Proto.prototype.b = 'b'
Proto.prototype.c = 'c'
Proto.prototype.callName = function(){
    alert('a')
}
let po = new Proto()

打印结果:

image.png

可以看出,这样返回的对象是一个空的,但是原型中出现了callName和一些属性,而且每实例化出一个属性或者方法他们都指向了同一个方法或属性。这个其实就是实现了一个简单的继承,具体的继承后面会提到。这边知识点挺多,具体及不多提了,后续可能会陆续补充。

缺点:原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒 也说得过去,毕竟(如前面的例子所示),通过在实例上添加一个同名属性,可以隐藏原型中的对应属 性。然而,对于包含引用类型值的属性来说,问题就比较突出了。

联想:以上面的例子继续说,现在我发现效率有点低,那我就把所有的零件都分配给不通的部门去做,这个部门是做螺丝的,那个部门是处理板子的,这个部门是拼装的。这样问题确实解决了,效率也挺快,但是出现个问题。我做产品A的时候用的螺丝是长的,做好后,又来了产品B,现在产品B螺丝用的是短的,这不完了吗.....,那如何解决上面两个问题呢?精髓就是:I have pen,I have apple ,emm~, applePen

组合使用构造函数模式和原型模式

function Contac(a){
    this.a = a
}
Contac.prototype.callName = function(){
    alert('a')
}
let po = new Contac()

person1.constructor == Person

这个就是我们开发中常用到的一些方法。在需要独立创建的时候,可以在构造函数中创建,遇到一些公用的没有必要重复申请的就放挂在原型上。分工有序,互不干扰。

寄生构造函数模式。

function Factory (a,b,c){
    let obj = {}
    obj.a = a;
    obj.b = b;
    obj.c = c;
    obj.callA = function(){
        alert(this.a+':a')
    }
    return obj
}
let fa = new Factory('a','b','c');
console.log(fa)

寄生构造函数类似工厂模式,就是多了一个new,没有什么特别之处。

极度不推荐,只是知道能够创建一个对象,创建出来的对象也不能知道原型指向哪里的,所以能不用就不用。

稳妥构造函数模式

function Factory (a,b,c){
    let obj = {}
    obj.a = a;
    obj.b = b;
    obj.c = c;
    obj.callA = function(){
        alert('a')
    }
    return obj
}
let fa = new Factory('a','b','c');
console.log(fa)

在这个模式中,指的是没有公共属性和函数,函数不能使用new 和this,在符合此情况下,可以使用,和上面的寄生构造函数类似,只要知道符合以上说的条件下,迫不得已可以使用。