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

javascript - self-defining function(also called lazy function definition) when using function declaration - Stack Overflow

programmeradmin5浏览0评论

In the "JavaScript Patterns" book by Stoyan Stefanov, there's a part about Self-Defining Function.

var scareMe = function(){
    console.log("Boo!");
    scareMe = function(){
        console.log("Double Boo!"); 
    }
}

scareMe();//==>Boo!
scareMe();//==>Double Boo!

It works as I expected. But I modify the scareMe function as following:

function scareMe(){
     console.log("Boo!");
     function scareMe(){
         console.log("Double Boo!");
     }
 }

 scareMe();//==>Boo!
 scareMe();//==>Boo!

Problem:

  1. what's the difference between them?
  2. In the second case, why the output is not "Double Boo!", but "Boo!"

In the "JavaScript Patterns" book by Stoyan Stefanov, there's a part about Self-Defining Function.

var scareMe = function(){
    console.log("Boo!");
    scareMe = function(){
        console.log("Double Boo!"); 
    }
}

scareMe();//==>Boo!
scareMe();//==>Double Boo!

It works as I expected. But I modify the scareMe function as following:

function scareMe(){
     console.log("Boo!");
     function scareMe(){
         console.log("Double Boo!");
     }
 }

 scareMe();//==>Boo!
 scareMe();//==>Boo!

Problem:

  1. what's the difference between them?
  2. In the second case, why the output is not "Double Boo!", but "Boo!"
Share Improve this question edited May 27, 2016 at 13:06 Sergei Basharov 53.9k78 gold badges207 silver badges352 bronze badges asked Sep 30, 2013 at 1:57 jasonjason 1,6316 gold badges21 silver badges40 bronze badges 5
  • This pattern is amazing. Besides obfuscation, is there any practical use ?? – GameAlchemist Commented Sep 30, 2013 at 2:03
  • 1 @GameAlchemist: Yes. Sometimes I have a function to do something that I only want to do once; initialization, say. I can define that function as so: function init() { init = function() {}; /* ... */ }; And now as long as I'm only using init by name and not actually capturing a reference to the original function, it will only initialize once. This could be done with a boolean variable, but this way you've got one less variable to keep track of. – icktoofay Commented Sep 30, 2013 at 2:11
  • interesting. So for instance the rAF replacement by setInterval could bee : requestAnimationFrame = function(cb) { requestAnimationFrame=function(){}; return setInterval(cb,16); }. A bit cryptic, but elegant. – GameAlchemist Commented Sep 30, 2013 at 2:20
  • for the record you mistyped the name : it is Stoyan Stefanov, my friend google said. – GameAlchemist Commented Sep 30, 2013 at 2:26
  • @GameAlchemist: in the book, the author also use this pattern to create Singleton pattern. function Singleton(){instance = this; Singleton = function(){return instance};}. Then When you create two instance, they are the same. var s1 = new Singleton(); var s2 = new Singleton(); console.log(s1 === s2); – jason Commented Sep 30, 2013 at 8:52
Add a ment  | 

3 Answers 3

Reset to default 11

The first scareMe function when invoked overwrite its own behavior by creating another function scareMe inside it, which overwrites the one in the upper scope, so the definition of original scareMe changes, i have see this approach been used if you want to do a first time set up in an application and want to change its behavior all over right after setting it up.

If you had defined:

var scareMe = function(){
    console.log("Boo!");
    var scareMe = function(){ //define it with var
        console.log("Double boo!"); 
    }
}

scareMe();//==>Boo!
scareMe();//==>Boo! //you will see the behavior as that of the second one.

Also one practical implementation of a one time setup:

var scareMe = function(){
    console.log("Boo!");

   //I have done my job now. I am no longer needed.
    scareMe = undefined;

}

scareMe();//==>Boo!
scareMe();//==> oops error

Second Case you are creating a new function with the name scareMe whose scope is only within the function, it doesn't overwrite itself.

Try this one for instance:

function scareMe(){
     console.log("Boo!");
     function scareMe(){
         console.log("Double bool!");
     }
    scareMe(); //Now this invokes the once defined inside the scope of this function itself.
 }

 scareMe();//==>Boo! and Double bool!

In your first approch, scareMe is a global variable (in your context). When in the "double boo", you change the value of that global variable, so it works. In the second approch, the inner scareMe is a local variable and it won't change value of the global one. So it's about the variable scope.

Except for hoisting and debuggability, you can consider:

function f(/* ... */) { /* ... */ }

To be equivalent to:

var f = function(/* ... */) { /* ... */ };

If we translate your second code sample to use this second form, we get:

var scareMe = function() {
    console.log("Boo!");
    var scareMe = function() {
        console.log("Double bool!");
    };
};

Note that this is not the same as your first snippet; the inner function definition has a var on it. With the inner var, it creates a new variable called scareMe that shadows the outer one.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论