如何解决Javascript对象定义技术的优缺点
| 在Javascript中定义可重用对象的基本方法是什么?我说可重用以排除单例技术,例如直接用对象文字符号声明变量。我在某处看到克罗克福德在他的书中定义了四种这样的方式,但我宁愿不必购买本书以获取这些简短的信息。 这是我熟悉的方法: 使用this
并用new
构造(我认为这被称为经典吗?)
function Foo() {
var private = 3;
this.add = function(bar) { return private + bar; }
}
var myFoo = new Foo();
使用原型,这是相似的
function Foo() {
var private = 3;
}
Foo.prototype.add = function(bar) { /* can\'t access private,correct? */ }
不使用this
或new
返回文字
function Foo() {
var private = 3;
var add = function(bar) { return private + bar; }
return {
add: add
};
}
var myFoo = Foo();
我可以想到相对较小的变化,这些变化可能不会以任何重要的方式起作用。我想念什么风格?更重要的是,每种技术的优缺点是什么?有值得推荐的人吗?还是优先考虑和一场神圣的战争?
解决方法
使用原型。从构造函数返回特定的对象使它们成为非构造函数,而将方法分配给
this
则使继承变得不那么方便。
返回对象文字
优点:
如果一个人忘记了“ 1”,他们仍然会得到物体。
您可以创建真正的私有变量,因为构造函数内部定义的对象的所有方法都共享其作用域。
缺点:
它不是真正的构造函数。在原型中添加内容不会更改返回的对象,即new
或否new
。 new Foo() instanceof Foo
也会导致false
。
使用prototype
优点:
您可以使构造函数整洁。
这是用JavaScript进行处理的标准方法,所有内置的构造函数都将其方法放在其原型上。
继承变得更加容易和正确。您可以(并且应该)使用Object.create(ParentConstructor.prototype)
代替new ParentConstructor()
,然后从Constructor
中调用ParentConstructor
。如果您想覆盖某个方法,则可以在原型上进行。
您可以在对象创建后对其进行“修改”。
您可以扩展您无法访问的构造函数的原型。
缺点:
可能太冗长了,如果您想更改函数的名称,则还必须更改添加到原型中的所有函数。 (或者将原型定义为一个大对象文字,并带有兼容的ѭ18属性描述符。)
它们不共享特定于实例的范围,因此您实际上不能拥有私有变量。
在构造函数中分配给ѭ19
优点:
您可以使用闭包,因此可以使用私有成员变量。
缺点:
没有鸭子打字;您不能使用任何旧对象立即从原型中调用方法。例如,Array.prototype.slice.call(collectionLikeObject)
。
, 这主要是偏好问题。没有一种方法可以制作鸡肉面条汤,而且统一的对象也是如此。
我不使用这三个中的任何一个,尽管它们都是出于自己的目的而工作。我使用一个名为Object:deploy的自定义函数,并像这样使用它。
var a = { hey: \'hello\' },b = {}.deploy(a);
console.log(b.hey); // \'hello\'
由于自动点滴,最适合大多数人使用prototype
。
function A() {};
A.prototype.hello = \"Hey\";
var a = new A();
console.log(a.hello); // \'Hey\'
A.prototype.hello = \"Hello\";
console.log(a.hello); // \'Hello\'
与普遍看法相反,您可以在in13ѭ中使用私有变量。
function Hello() {};
(function () {
var greeting = \"Hello\";
Hello.prototype.greet = function () { return greeting };
}).apply(this);
但是,即使有可能,通常也更好。
function Hello() {};
Hello.prototype.greeting = \"Hello\";
Hello.prototype.greet = function () { return this.greeting };
, 好吧,第二种方法(原型)与其他语言(例如Python)中的标准类更相似,因为您有一个公共的“ prototype \”对象,所有实例都可以共享该对象。比较第一种和第二种方法:
在方法1中,每次调用“new Foo()
\”时,都将创建一个全新的对象并插入所有方法。这不是非常节省时间或空间,因为每个Foo实例将拥有自己的所有方法表。您可以通过创建两个Foo对象并询问foo1.add == foo2.add
(false)来进行测试。方法3与此非常相似;我不确定方法1和方法3之间的语义差异(如果有)。
在方法2中,您设置了包含所有方法的共享原型对象。如果你问foo1.add == foo2.add
,那你就成真了。这样更节省空间和时间。它还允许您在创建实例后向原型添加更多方法,并且它们将看到新方法。
如您所说,方法2的问题在于您无法访问私有成员。但是您仍然可以将非私有成员添加到对象本身,并使用原型方法访问那些成员:
function Foo() {
this.private = 3;
}
Foo.prototype.add = function(bar) { return this.private + bar }
需要注意的是,foo.private
在外部是可见的。
,原型没有add对象的每个对象实例的开销。仅这就是为什么我不喜欢其他两种方法的原因。
, 不要忘记继承。有一天你需要。对于组织继承,最好的方法是结合技术:
function Foo() {
this.array = [1,2,3];
this.add = function(bar) { return private + bar; }
}
Foo.prototype.add = function(bar) { }
var myFoo = new Foo();
在构造函数中设置字段对于避免由子对象修改字段很有用。
将方法设置为原型的速度比每次在构造函数中都要快。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。