我在过去的几个月里一直在学习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)容易出现任何不良副作用
答案 0 :(得分:1)
你的模式
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,并且函数的参数会自动传递,而不必提前知道有多少。此方法适用于任何arity的构造函数,包括可变构造函数。
答案 1 :(得分:0)
从技术角度来看,它有效。但是你应该小心改变预期的语义,除非你有令人信服的理由,在这种情况下(没有双关语意),我认为你没有。特别是如果你的代码被其他开发人员使用 - 最好坚持使用约定,比如使构造函数大写,而不是常规函数。
如果未使用throw
调用此功能,您是否只会new
出现错误?