Question

I was reading over how to 'Create a JavaScript Library' earlier and I came across these pieces of code that make me wanna rip my hair out.

Here is the code which got my brain in knots:

if (window === this) {
    return new _(id);
}

_(id) is just the function name in which this code is contained. Here's the rest of the code if you need to look over it yourself.

function _(id) {

// About object is returned if there is no 'id' parameter
var about = {
    Version: 0.5,
    Author: "Michael Jasper",
    Created: "Fall 2010",
    Updated: "23 November 2011"
};

if (id) {

    // Avoid clobbering the window scope:
    // return a new _ object if we're in the wrong scope
    if (window === this) {
        return new _(id);
    }

    // We're in the correct object scope:
    // Init our element object and return the object
    this.e = document.getElementById(id);
    return this;
  } else {
    // No 'id' parameter was given, return the 'about' object
    return about;
  }
};

I've never seen 'return new function' before but I would love to understand how it functions.

The other piece of code:

_.prototype = {
  hide: function () {
          this.e.style.display = 'none';
          return this;
  }

  show: function () {
           this.e.style.display = 'inherit';
           return this;
  }
};

I know that this code adds new methods to the _ object but why do they 'return this'? I tried that without and it worked just fine.

One last thing, the link to the article is http://www.mikedoesweb.com/2012/creating-your-own-javascript-library/

Was it helpful?

Solution

The first bit of code is essentially trying to detect how the "constructor" function has been called...

in javascript, you can use a function to create an object in two ways:

function _(id) {
    this.someProperty = "stuff";
    //Do more stuff to "this"
    return this;
}

//in this scenario, the "this" object will be the window object
var myObject = _(id);
console.log(window.someProperty); //outputs "stuff";
console.log(myObject.someProperty); //outputs "stuff";

//in this scenario, the "this" object is what get's actually returned...
var myObject = new _(id);
console.log(window.someProperty); //outputs "undefined"
console.log(myObject.someProperty); //outputs "stuff"

therefore, the checking for

if (window === this) {
    return new _(id);
}

is simply there to make sure you don't accidentally call the constructor without the new keyword. this would be bad, as any property that you would assign to the object, would immediately be assigned to the window namespace... which would be bad.


as for your second question, the author is using a return this; at the end of each method as a fluent interface design pattern

this allows for convenient and nice looking object manipulation. a common example of this is jQuery, where you can chain methods onto one single object...

$(".some-css-selector").click(function() { 
    ... do something to the selected objects during the "click" event
}).keyup(function() {
    ... do something to the same objects during the "keyup" event
});

EDIT: a little more additional information in response to W3Geek's comments below:

from Douglas Crockford's book "Javascript: The Good Parts" (totally a good read if you are getting into JS... only like 70 pages but every one of them is worth reading).


Javascript's new operator creates a new object that inherits from the operand's prototype member, and then calls the operand, binding the new object to this. This gives the operand (which had better be a constructor function) a chance to customize the new object before it is returned to the requestor.

If you forget to use the `new operator, you instead get an ordinary function call, and this is bound to the global object instead of to a new object. That means that your function will be clobbering global variables when it attempts to initialize the new members. That is a very bad thing.

...

Constructors are functions that are designed to be used with the new prefix. The new prefix creates a new object based on the function's prototype and binds that object to the functions implied this parameter. If you neglect to use the new prefix, no new object will be made, and this will be bound to the global object. This is a serious mistake.


OTHER TIPS

return this gives you the ability to chain method calls. You can do some really cool and useful things like, _.show().hide(). :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top