今天有人告诉我,没有括号也可以调用函数。我能想到的唯一方法是使用apply或call这样的函数。
f.apply(this);
f.call(this);
但是这些需要在apply和call上加上括号,让我们回到原点。我还考虑了将函数传递给某种事件处理程序,如setTimeout:
setTimeout(f, 500);
但问题就变成了“如何在没有括号的情况下调用setTimeout ?”
那么这个谜语的答案是什么呢?如何在Javascript中调用函数而不使用括号?
今天有人告诉我,没有括号也可以调用函数。我能想到的唯一方法是使用apply或call这样的函数。
f.apply(this);
f.call(this);
但是这些需要在apply和call上加上括号,让我们回到原点。我还考虑了将函数传递给某种事件处理程序,如setTimeout:
setTimeout(f, 500);
但问题就变成了“如何在没有括号的情况下调用setTimeout ?”
那么这个谜语的答案是什么呢?如何在Javascript中调用函数而不使用括号?
当前回答
有几种不同的方法可以调用不带括号的函数。
让我们假设你已经定义了这个函数:
function greet() {
console.log('hello');
}
下面是一些不带括号调用greet的方法:
1. 作为构造函数
使用new可以调用不带括号的函数:
new greet; // parentheses are optional in this construct.
MDN对新运营商的评价:
语法 新构造函数(((参数)))
2. 如toString或valueOf实现
toString和valueOf是特殊的方法:当需要进行转换时,会隐式调用它们:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
你可以(ab)使用这个模式调用不带括号的greet:
'' + { toString: greet };
或者使用valueOf:
+{ valueOf: greet };
valueOf和toString实际上是从@@toPrimitive方法调用的(从ES6开始),所以你也可以实现这个方法:
+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }
2.b重写函数原型中的valueOf
你可以采用前面的想法来覆盖Function原型上的valueOf方法:
Function.prototype.valueOf = function() {
this.call(this);
// Optional improvement: avoid `NaN` issues when used in expressions.
return 0;
};
一旦你这样做了,你可以这样写:
+greet;
尽管后面有括号,但实际触发调用没有括号。更多相关内容请参见博客“在JavaScript中调用方法,而不是真正调用它们”。
3.作为发电机
您可以定义一个生成器函数(使用*),该函数返回一个迭代器。你可以使用扩展语法或者for…的语法。
首先,我们需要一个原始greet函数的生成器变体:
function* greet_gen() {
console.log('hello');
}
然后通过定义@@iterator方法调用它,不带括号:
[...{ [Symbol.iterator]: greet_gen }];
通常,生成器在某处会有一个yield关键字,但调用函数并不需要它。
最后一个语句调用函数,但也可以通过解构来完成:
[,] = { [Symbol.iterator]: greet_gen };
或者a for…的,但它有自己的括号:
for ({} of { [Symbol.iterator]: greet_gen });
注意,你也可以用原始的greet函数来执行上面的操作,但它会在greet执行后触发一个异常(在FF和Chrome上测试)。您可以使用try…catch块。
4. 作为Getter
@jehna1对此有完整的答案,所以给他信任吧。下面是一种在全局作用域中调用圆括号less函数的方法,避免使用已弃用的__defineGetter__方法。它使用Object.defineProperty代替。
我们需要创建一个原始greet函数的变体:
Object.defineProperty(window, 'greet_get', { get: greet });
然后:
greet_get;
将window替换为全局对象。
你可以调用原始的greet函数,而不会在全局对象上留下任何痕迹,就像这样:
Object.defineProperty({}, 'greet', { get: greet }).greet;
但是有人可能会说这里确实有括号(尽管在实际调用中没有涉及到它们)。
5. As标签功能
从ES6开始,你可以用下面的语法调用一个传递模板文字的函数:
greet``;
参见“带标签的模板字面量”。
6. 作为代理处理器
从ES6开始,你可以定义一个代理:
var proxy = new Proxy({}, { get: greet } );
然后读取任何属性值将调用greet:
proxy._; // even if property not defined, it still triggers greet
这种说法有很多变体。再举一个例子:
var proxy = new Proxy({}, { has: greet } );
1 in proxy; // triggers greet
7. 作为实例检查器
instanceof操作符在第二个操作数上执行@@hasInstance方法,定义如下:
1 instanceof { [Symbol.hasInstance]: greet } // triggers greet
其他回答
Array.constructor`alert\x28"invoke with whatever u want"\x29```;
因为数组。构造函数是一个函数对象。当Function对象被调用时,它们返回一个函数,它的主体是它得到的参数。
这是另一个例子,我传入函数1然后传入无参数的函数,它被称为。
function one() {
console.log("one called");
}
function two() {
return new Promise((resolve, reject) => {
resolve();
});
}
two().then(one);
最简单的方法是使用new操作符:
函数f() { alert('你好'); } 新的f;
虽然这是不正统和不自然的,但它是有效的,是完全合法的。
如果不使用参数,new操作符不需要括号。
下面是一个特定情况的例子:
window.onload = funcRef;
尽管该语句实际上没有调用,但将导致未来的调用。
但是,我认为灰色区域对于这样的谜语来说是可以的:)
有几种不同的方法可以调用不带括号的函数。
让我们假设你已经定义了这个函数:
function greet() {
console.log('hello');
}
下面是一些不带括号调用greet的方法:
1. 作为构造函数
使用new可以调用不带括号的函数:
new greet; // parentheses are optional in this construct.
MDN对新运营商的评价:
语法 新构造函数(((参数)))
2. 如toString或valueOf实现
toString和valueOf是特殊的方法:当需要进行转换时,会隐式调用它们:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
你可以(ab)使用这个模式调用不带括号的greet:
'' + { toString: greet };
或者使用valueOf:
+{ valueOf: greet };
valueOf和toString实际上是从@@toPrimitive方法调用的(从ES6开始),所以你也可以实现这个方法:
+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }
2.b重写函数原型中的valueOf
你可以采用前面的想法来覆盖Function原型上的valueOf方法:
Function.prototype.valueOf = function() {
this.call(this);
// Optional improvement: avoid `NaN` issues when used in expressions.
return 0;
};
一旦你这样做了,你可以这样写:
+greet;
尽管后面有括号,但实际触发调用没有括号。更多相关内容请参见博客“在JavaScript中调用方法,而不是真正调用它们”。
3.作为发电机
您可以定义一个生成器函数(使用*),该函数返回一个迭代器。你可以使用扩展语法或者for…的语法。
首先,我们需要一个原始greet函数的生成器变体:
function* greet_gen() {
console.log('hello');
}
然后通过定义@@iterator方法调用它,不带括号:
[...{ [Symbol.iterator]: greet_gen }];
通常,生成器在某处会有一个yield关键字,但调用函数并不需要它。
最后一个语句调用函数,但也可以通过解构来完成:
[,] = { [Symbol.iterator]: greet_gen };
或者a for…的,但它有自己的括号:
for ({} of { [Symbol.iterator]: greet_gen });
注意,你也可以用原始的greet函数来执行上面的操作,但它会在greet执行后触发一个异常(在FF和Chrome上测试)。您可以使用try…catch块。
4. 作为Getter
@jehna1对此有完整的答案,所以给他信任吧。下面是一种在全局作用域中调用圆括号less函数的方法,避免使用已弃用的__defineGetter__方法。它使用Object.defineProperty代替。
我们需要创建一个原始greet函数的变体:
Object.defineProperty(window, 'greet_get', { get: greet });
然后:
greet_get;
将window替换为全局对象。
你可以调用原始的greet函数,而不会在全局对象上留下任何痕迹,就像这样:
Object.defineProperty({}, 'greet', { get: greet }).greet;
但是有人可能会说这里确实有括号(尽管在实际调用中没有涉及到它们)。
5. As标签功能
从ES6开始,你可以用下面的语法调用一个传递模板文字的函数:
greet``;
参见“带标签的模板字面量”。
6. 作为代理处理器
从ES6开始,你可以定义一个代理:
var proxy = new Proxy({}, { get: greet } );
然后读取任何属性值将调用greet:
proxy._; // even if property not defined, it still triggers greet
这种说法有很多变体。再举一个例子:
var proxy = new Proxy({}, { has: greet } );
1 in proxy; // triggers greet
7. 作为实例检查器
instanceof操作符在第二个操作数上执行@@hasInstance方法,定义如下:
1 instanceof { [Symbol.hasInstance]: greet } // triggers greet