最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript named function definition executed when it shouldn't - Stack Overflow

programmeradmin0浏览0评论

I have no idea what is happening here. The code is:

  if( true ) { 

      console.log('In first function definition');

      function test(){
        console.log('Hello world');
      }

    } else {

      console.log('In the second function definition');

      function test(){
        console.log('Goodbye world');
      }

    }

  test();

I would expect this to log in the console:

'In the first function definition'
'Hello world'

But instead it logs:

'In the first function definition'
'Goodbye world'

How is the second named function being created when the code doesn't enter that branch?

I have no idea what is happening here. The code is:

  if( true ) { 

      console.log('In first function definition');

      function test(){
        console.log('Hello world');
      }

    } else {

      console.log('In the second function definition');

      function test(){
        console.log('Goodbye world');
      }

    }

  test();

I would expect this to log in the console:

'In the first function definition'
'Hello world'

But instead it logs:

'In the first function definition'
'Goodbye world'

How is the second named function being created when the code doesn't enter that branch?

Share Improve this question asked Jun 5, 2013 at 2:54 BIOSBIOS 1,6955 gold badges21 silver badges37 bronze badges 1
  • why do you want to re-define same function name? – Raptor Commented Jun 5, 2013 at 2:56
Add a ment  | 

5 Answers 5

Reset to default 10

Remember, everything in JavaScript is function-scoped; there is no block scope.

To that effect, you have two function declarations defined in the same scope (whatever the scope that if-else sits in), with the same name, in different blocks. This produces inconsistent results between browsers.

You need to either give those functions different names, or use function expressions, with something like this:

var f;
if(true) { 
   console.log('In first function definition');

   f = function(){
     console.log('Hello world');
   };

} else {
  console.log('In the second function definition');

  f = function(){
    console.log('Goodbye world');
  };
}
f();

To your excellent question of

But how is the function defined, if we don't enter that branch of the code? If that block is not executed, why is scope a consideration?

The simple answer is that function declarations are "hoisted", and immediately available anywhere in the scope, even before the declaration itself.

ie:

function foo(){
    f(); //perfectly valid

    function f(){
    }
}

The longer answer is that, prior to entering the scope, all variable declarations, and function declarations are stripped out, and placed onto the "activation object." The activation object is then placed at the head of the "scope chain." When you execute the function, any references to these variables and functions are simply resolved from there.

Function definitions in javascript are independent of control structures, meaning that when you redefine the function the second time even though it's in a branch of a control structure that will never bit hit it still redefines the function. What are you trying to do anyway?

Some JavaScript engines treat the definition as always occurring regardless of the condition, and the second definition overwrites the first.

Note: Some JavaScript engines, not including SpiderMonkey, incorrectly treat any function expression with a name as a function definition.

To add to Adam's answer, you can get a way around it if you assign your function.

if( true ) { 
  console.log('In first function definition');
  test = function() { console.log('Hello world'); }
} else {
  console.log('In the second function definition');
  test = function(){ console.log('Goodbye world'); }
}
test();

This will print

In the first function definition
Hello world

According to ECMA-262, function declarations are processed before any code is executed. So declaring functions anywhere effectively moves ("hoists") them to the top of the execution context.

However, not everything that looks like a declaration is a declaration. In the following:

if (false) {
  function fred() {return true;}
}

Some browsers see a function declaration so:

alert(fred());

shows "true". Other browsers use an extension to ECMA-262 that allows it to be treated as a named function expression function statement (I'll try to find a reference to an excellent posting by Richard Cornford on p.lang.javascript about that see below), so that:

alert(fred());

throws as an error that fred is undefined. Try it in Firefox and IE.

So the bottom line is if you want to conditionally create a function, use an unambiguous function expression. They're often used in conjunction with feature testing, e.g. to create a function to get the textContent or innerText of an element:

var getText = (function() {
  var el = document.createElement('div');

  if (typeof div.textContent == 'string') { 
    div = null;
    return function(el) {return el.textContent;};

  } else if (typeof div.innerText == 'string') { 
    div = null;
    return function(el) {return el.innerText;};
  }
}());

Edit

Here's Richard Cornford's post in FunctionExpression's and memory consumptions. The important part:

In fact it is a function statement; a syntax extension that is capable of allowing the conditional creation of a function because being a Statement it can be evaluative inside a block.

But the whole post is worth reading.

Also note that function statements are warned against in ES5 strict mode and may be introduced in some future version of ECMAScript.

发布评论

评论列表(0)

  1. 暂无评论