JavaScript中的“创建对象”是一个复杂的话题。这种语言提供了多种创建对象的方法,新手或老手可能会不知所措。然而,尽管创建对象的方法有很多种并且语法上存在明显差异,但它们实际上可能比您想象的更相似。本文将带你踏上对象创建方法的梳理之旅,为你揭示不同方法之间的依赖关系和递进关系。对象文字我们的第一个站点毫无疑问是创建对象、对象文字的最简单方法。JavaScript总是宣传它可以“无中生有”地创建对象——没有类、没有模板、没有原型——只需单击一下,一个带有方法和数据的对象就会出现。varo={x:42,y:3.14,f:function(){},g:function(){}};但是这种方法有一个缺点:如果我们要在别处创建一个相同类型的对象,我们就不得不复制粘贴这个对象的方法、数据和初始化。我们需要一种方法来批量创建相同类型的对象,而不是只创建一个对象。工厂函数我们的下一站是工厂函数。显然,使用这种方法创建一个具有相同结构、接口和实现的对象类是最简单的。我们不直接创建对象字面量,而是将对象字面量作为函数的返回值。当我们需要多次或在多个地方创建相同类型的对象时,只需要调用该函数即可。functionthing(){return{x:42,y:3.14,f:function(){},g:function(){}};}瓦罗=东西();但是这种方法也有一个缺点:会造成内存膨胀,因为每个对象都包含一个单独的工厂函数副本。理想情况下,我们希望所有对象共享工厂函数的一个副本。原型链JavaScript提供了一种内置机制,用于在称为原型链的对象之间共享数据。当我们访问一个对象的属性时,它会委托给其他一些对象来完成请求。我们可以利用这一点修改工厂函数,使其创建的每个对象只包含自己唯一的数据,而对其他属性的请求都委托给原型链上的一个公共对象。varthingPrototype={f:function(){},g:function(){}};functionthing(){varo=Object.create(thingPrototype);o.x=42;o.y=3.14;返回;}瓦罗=东西();事实上,JavaScript本身就有支持这种通用模式的内置机制。我们不需要自己去创建这个公共对象(原型对象),JavaScript会自动为每个函数创建一个原型对象,我们可以直接把共享的数据放在这个对象中。thing.prototype.f=function(){};thing.prototype.g=function(){};functionthing(){varo=Object.create(thing.prototype);o.x=42;o.y=3.14;返回;}瓦罗=东西();但是这种方法也有一个缺点:会造成重复。上述thing函数的第一行和最后一行在每个“委托原型工厂函数”中都重复出现,差别不大。使用ES5类,我们可以提取那些重复的代码并将它们放入自定义函数中。这个函数创建一个对象,并与其他某个任意函数(参数函数)的原型建立委托(继承)关系,然后我们将新创建的对象作为参数,调用这个函数(参数函数),并返回这个新对象.functioncreate(fn){v??aro=Object.create(fn.prototype);fn.call(o);返回;}//...Thing.prototype.f=function(){};Thing.prototype.g=function(){};functionThing(){this.x=42;这个.y=3.14;}varo=创建(事物);事实上,JavaScript也内置了对这种方法的支持。我们定义的create函数其实就是new关键字的基本实现,所以我们可以很方便的把create换成new。Thing.prototype.f=function(){};Thing.prototype.g=function(){};functionThing(){this.x=42;这个.y=3.14;}varo=newThing();我们到达这一站通常被称为ES5类。它使用函数创建对象,将需要共享的数据委托给原型对象,使用new关键字处理重复逻辑。但是这种方式也有一个缺点:冗长丑陋,在实现继承的时候会更加冗长丑陋。ES6类JavaScript***一项相关的改进是ES6类,使用新语法可以更清晰地实现这些类。classThing{构造函数(){this.x=42;这个.y=3.14;}f(){}g(){}}varo=newThing();对比一下多年来JavaScript开发者与原型链的关系,形影不离,纠缠不清。今天我们最有可能遇到两种创建对象的方式,一种是强依赖原型链的类语法,另一种是完全不依赖原型链的工厂函数语法。这两种方法在性能和特性上有所不同——尽管差别不是太大。性能今天的JavaScript引擎已经过高度优化,很难从JavaScript代码中推断出什么会更快。关键在于测量方法。然而,测量方法有时会失败。通常,较新的JavaScript引擎每六周发布一次,在此之前进行的测量以及基于此类测量的决策可能会失去意义。所以我的经验法则是选择最官方和最广泛使用的语法,因为大多数时候它具有最久经考验的性能,因此性能最好。到目前为止,类语法是最好的,在我写这篇文章时,类语法比返回文字的工厂函数快大约3倍。特性随着ES6的发布,过去存在于类和工厂函数之间的一些差异消失了。现在,工厂函数和类都可以强制执行真正的私有数据——工厂函数通过闭包,类通过WeakMaps。两者都可以实现多重继承——工厂函数可以将其他属性混合到它们的对象中,类可以通过类工厂或代理将其他属性混合到它们的原型中。工厂函数和类都可以在需要的时候返回任意对象,语法也很简单。结论综合考虑,我更倾向于类语法。它是标准的、简单的、干净的、快速的,并且提供了曾经只在函数工厂中可用的所有特性。
