0

I started to read the source code for stampit js yesterday, and found an interesting way of enclose function variables in an object by calling apply()

instance = fn.apply(instance, arguments) || instance;

How does this really work? And why does the following code line not work?

instance = fn.apply(instance, arguments);

A longer example:

var createFoo = function() {
    var foo = {},
        fn = function() {
            var i = 0;

            this.increment = function() {
                i++;
            };

            this.get = function() {
                return i;
            };
        };
    foo = fn.apply(foo, arguments) || foo;
    return foo;
}, foo = createFoo();

test('foo test', function () {
    foo.increment();
    equal(foo.get(), 1, 'pass');
});

var createBar = function() {
    var bar = {},
        fn = function() {
            var i = 0;

            this.increment = function() {
                i++;
            };

            this.get = function() {
                return i;
            };
        };
    bar = fn.apply(bar, arguments);
    return bar;
}, bar = createBar();

test('bar tests', function () {
    bar.increment(); /* undefined */
});

http://jsfiddle.net/RMh78/59/

radiovisual
  • 6,298
  • 1
  • 26
  • 41

2 Answers2

2

What's going here has to do with how objects are passed as references and what values functions return.

In your code block, you have:

var createFoo = function() {
    var foo = {},
        fn = function() {
            var i = 0;

            this.increment = function() {
                i++;
            };

            this.get = function() {
                return i;
            };
        };
    foo = fn.apply(foo, arguments) || foo;
    return foo;
},
foo = createFoo();

Let's break down the foo = fn.apply(foo, arguments) || foo; line.

foo was declared and initialized as an empty object ({}). It was then set as the this context in the foo function (that's what .apply does). The arguments would pass any args (none) sent to createFoo to fn.

So, so when fn.apply is ran, the foo objects has increment and get properties applied to it. fn doesn't have a return statement, so it returns undefined.

So, now we have foo = undefined || foo;, and we have foo updated with some properties. This sets foo to itself, then the next line returns it.

In the second (bar) block:

var createBar = function() {
    var bar = {},
        fn = function() {
            var i = 0;

            this.increment = function() {
                i++;
            };

            this.get = function() {
                return i;
            };
        };
    bar = fn.apply(bar, arguments);
    return bar;
},
bar = createBar();

You don't have || bar after fn.apply(bar, arguments). So, what happens is that fn runs, it returns undefined, bar's set to that then bar (undefined) is returned.

nachocab
  • 13,328
  • 21
  • 91
  • 149
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
0

So how does the following code work, and does it have any disadvantages compared to the first createFoo function?

var createFoo2 = function() {
    var foo = {},
    fn = function() {
        var i = 0;

        this.increment = function() {
            i++;
        };

        this.get = function() {
            return i;
        };
    };
    fn.apply(foo, arguments);
    return foo;
},
foo2 = createFoo2();