是否可以从自己的体内重新定义JavaScript函数。例如,我可以执行以下操作吗?
function never_called_again(args) {
// Do some stuff
never_called_again = function (new_args) {
// Do some new stuff
}
}
以上是否有效,是否具有正确的语义?我不想用旧的函数名创建一个新的全局变量,因为我试图在全局范围内做这种事情,但是从各种对象范围开始,我不希望当我发生名字冲突时在这些本地范围内重新定义函数。
答案 0 :(得分:42)
从其正文中重新定义一个函数确实可能。该技术用于所谓的 Lazy Function Definition Pattern 。
看起来像这样:
// Lazy Function Definition Pattern
var foo = function() {
var t = new Date();
foo = function() {
return t;
};
return foo();
}
此函数存储第一个调用的日期,然后返回此日期。
如果将与模块模式进行比较,则不同之处在于初始化仅在首次调用时发生,而不是在定义时进行。对于代价高昂的初始化,这可能是一个巨大的好处。
// Conditional Module Pattern
var foo = (function() {
var t;
return function() {
if (t) {
return t;
}
t = new Date();
return t;
}
})();
答案 1 :(得分:14)
是的,您可以通过这种方式重新定义功能。
运行此:
function never_called_again(args) {
console.log('Func 1', args);
never_called_again = function (new_args, x) {
console.log('Func 2', new_args, x);
}
}
never_called_again('arg A', 'arg B');
never_called_again('arg A', 'arg B');
产生这个:
Func 1 arg A
Func 2 arg A arg B
答案 2 :(得分:3)
完全有可能在第一次调用时将函数对象重新定义为您想要的任何内容。
这是可能的原因是因为分配评估是从右到左处理的。这意味着在执行函数时捕获函数的范围(在这种情况下,当您调用函数时)。
这实际上意味着在执行时,正在执行的函数对象和原始函数定义实际上是两个不同的东西,它允许重新定义原始函数,好吧......真的。
使用它的最好(也是最酷)方法之一是创建一个本质上是自己工厂的功能。通过这种方式,您不必携带许多不会被使用的对象定义。
示例:
d = function(type){
switch(type.toUpperCase()){
case 'A' :
d = (
function(){
return {
name : 'A',
getName : function(){return this.name;}
};
}
)();
break;
case 'B' :
d = (
function(){
return {
name : 'B',
getName : function(){return this.name;}
};
}
)();
break;
default:
d = (
function(){
return {
name : 'DEFAULT',
getName : function(){return this.name;}
};
}
)();
break;
}
};
console.dir(d);
d('A');
console.dir(d);
console.log(d.getName());
答案 3 :(得分:2)
您的示例基本上与:
相同var never_called_again = function(args) {
//do some stuff
never_called_again = function (new_args) {
//do some new stuff
}
}
因为您可能知道这有效:
var a = 1;
function myFunction() {
//do some stuff
a = 2;
}
myFunction();
alert(a) //==> 2
很明显,第一个例子也有效。
你是否实际想要这样做是一个更开放的问题。它会让代码更难理解吗?
答案 4 :(得分:1)
是的,它是可能的,它不会创建全局功能。我在Internet Explorer 6,Firefox,Chrome和Opera中验证了这一点。 请考虑以下代码:
<head>
<title>Never called again</title>
<style type="text/css">
</style>
<script type="text/javascript">
function hello() {
function never_called_again(args) {
alert("Hello world " + never_called_again);
//do some stuff
never_called_again = function (new_args) {
//do some new stuff
alert("hello " + never_called_again);
}
}
never_called_again();
never_called_again();
}
</script>
</head>
<body onload="">
<button onclick="hello(); never_called_again();">Call</button>
</body>
这将在never_called_again第一次打印“Hello World {function code}”,第二次打印“hello {changed function code}”第二次。
但是当按钮的onclick被调用时,它会抛出一个错误,说明函数没有被定义,清楚地表明函数是重新定义的(而不是全局创建的)。
答案 5 :(得分:1)
严格地说,不,根本不可能重新定义JavaScript函数。虽然这是一个语义问题。
一个函数可能会使用另一个函数覆盖某个范围内的引用,这个函数可以作为另一个函数出现在第一个函数的位置。 e.g。
greet_once = function() {
console.log('Hello.');
greet_once = function() { console.log('Can I help you?') };
};
类似地,函数可以使用闭包范围的状态在第二次调用时表现不同(显然不是“重新定义”)。
以下示例说明了上述模式不重新定义的原因,因为它取决于可能无法与调用范围共享的父作用域。
greet_always = function() {
greet_once = function() {
console.log('Hello.')
greet_once = function() { console.log('Can I help you?') }
};
return greet_once()
}()
greet_always()
greet_always()
被称为greet_always
的函数(始终打印'Hello。')是同一个函数,最初分配给greet_once
。
我认为你可以重新定义一个函数的最接近的方法是重新分配它的apply和call方法,这会产生myFunction.call()
与myFunction()
不同的场景,这很奇怪,但可以想象有用。< / p>