过去几个月我一直在学习 Javascript,有时感觉我写代码的速度比我实际掌握语言细微差别的速度还快,所以请多多包涵。
无论如何,我的问题与我一直使用的某种方法的行为有关。基本要点是能够设计无需使用“new”关键字即可构造和使用的对象。
举个例子:
<!DOCTYPE html>
<html>
<head>
<script>
function example()
{
if(!(this instanceof example))
return new example();
}
example.prototype.test = function()
{
var
result = example();
if(result instanceof example)
{
console.log("Type: example");
if(result === this)
console.log("Unexpected: (result === this)");
else
console.log("Expected: (result !== this)");
}
else
console.log("Type: ?");
return result;
}
function run()
{
var
one = new example(),
two = example(),
three = one.test(),
four = two.test();
three.test();
four.test();
}
</script>
</head>
<body onload = "run()">
</body>
</html>
我得到的输出是:
Type: example
Expected: (result !== this)
Type: example
Expected: (result !== this)
Type: example
Expected: (result !== this)
Type: example
Expected: (result !== this)
...这正是我想看到的。具体来说,我的问题是:
(1) 标准行为
(2) 所有浏览器都支持
(3) 容易产生任何不良副作用
最佳答案
你的模式
function Foo() {
if (!(this instanceof Foo)) {
return new Foo();
}
}
非常普遍且广为人知(是的,它符合犹太洁食标准)。但它也有一些缺点,主要是围绕着处理传递参数。这也是不必要的,JavaScript 具有高阶函数,因此无需为您编写的每个函数添加样板文件:
let wrapConstructor = fn => (...args) => {
return new (fn.bind.apply(fn, [fn, ...args]));
};
let Foo = function Foo() {
if (!(this instanceof Foo)) {
throw new TypeError('Not a Foo...');
}
};
let wrappedFoo = wrapConstructor(Foo);
let foo = wrappedFoo(); // doesn't throw
这具有使用内置构造函数(如 Date
)的额外好处:
let wrappedDate = wrapConstructor(Date);
let myDate = wrappedDate(2016, 11, 8); // today's date
就浏览器兼容性而言,正如所写的那样,它显然不是很好,但是任何具有 Function.prototype.bind
和 Function.prototype.apply
的环境(IE 9+)都可以在一点 babel 魔法之后运行它。
至于它是否符合标准行为,好吧,如果你的意思是符合规范,那么这肯定符合。如果你的意思是“这是常见的做法”,那么,这取决于你运行的 JavaScript 人群。如果您倾向于使用大量高阶函数(例如我的小 wrapConstructor
实用程序),那么 new
会很痛苦,并且需要避免。
对于包含此类功能的库,请查看 ramda .
更新
另请注意,只需对助手稍作修改,您就可以很容易地将这两种模式结合起来:
let construct = (fn, args) => {
return new (fn.bind.apply(fn, [fn, ...args]));
};
function Foo() {
if (!(this instanceof Foo)) {
return construct(Foo, Array.from(arguments));
}
}
现在可以使用或不使用 new
调用 Foo,并且函数的参数会自动传递,而无需提前知道有多少。此方法适用于任何数量的构造函数,包括可变参数构造函数。
关于javascript - 在没有 "new"关键字 kosher 的情况下声明 Javascript 对象的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41045916/