日期:2014-05-16  浏览次数:20458 次

JavaScript Patterns 读书笔记(二)

二.Object

  • Object Constructor Catch
    ? ?You have no reason to use the new Object() constructor when you can use an object literal, but you might be inheriting legacy code written by others, so you should be aware of one “feature” of this constructor (or yet another reason not to use it). The feature in question is that the Object() constructor accepts a parameter and, depending on the value passed, it may decide to delegate the object creation to another built-in constructor and return a different object than you expect. Following are a few examples of passing a number, a string, and a boolean value to new Object(); the result is that you get objects created with a different constructor:
    // Warning: antipatterns ahead
    // an empty object
    var o = new Object();
    console.log(o.constructor === Object); // true
    // a number object
    var o = new Object(1);
    console.log(o.constructor === Number); // true
    console.log(o.toFixed(2)); // "1.00"
    // a string object
    var o = new Object("I am a string");
    console.log(o.constructor === String); // true
    // normal objects don't have a substring()
    // method but string objects do
    console.log(typeof o.substring); // "function"
    // a boolean object
    var o = new Object(true);
    console.log(o.constructor === Boolean); // true
    
    ?
  • Constructor’s Return Values
    ? When invoked with new, a constructor function always returns an object; by default it’s the object referred to by this. If you don’t add any properties to this inside of your constructor, an “empty” object is returned (“empty” aside from inheriting from the constructor’s prototype).
    ?Constructors implicitly return this, even when you don’t have a return statement in the function. But you can return any other object of your choosing. In the next example, a new object referenced by that is created and returned.
    var Objectmaker = function () {
    	// this `name` property will be ignored
    	// because the constructor
    	// decides to return another object instead
    	this.name = "This is it";
    	// creating and returning a new object
    	var that = {};
    	that.name = "And that's that";
    	return that;
    };
    // test
    var o = new Objectmaker();
    console.log(o.name); // "And that's that"
    
    ?? ?As can you see, you have the freedom to return any object in your constructors, as long as it’s an object. Attempting to return something that’s not an object (like a string or a boolean false, for example) will not cause an error but will simply be ignored, and the object referenced by this will be returned instead(!).
  • Self-Invoking Constructor
    ??To address the drawback of forgeting "new" when construct a new instance and have prototype properties available to the instance objects, consider the following approach. In the constructor you?check whether this is an instance of your constructor, and if not, the constructor invokes itself again,this time properly with new:
    function Waffle() {
    	if (!(this instanceof Waffle)) {
    		return new Waffle();
    	}
    	this.tastes = "yummy";
    }
    
    Waffle.prototype.wantAnother = true;
    // testing invocations
    var first = new Waffle(),
    second = Waffle();
    console.log(first.tastes); // "yummy"
    console.log(second.tastes); // "yummy"
    console.log(first.wantAnother); // true
    console.log(second.wantAnother); // true
    
    ?
  • Array Constructor Curiousness
    ???? One more reason to stay away from new Array() is to avoid a possible trap that this constructor has in store for you.
    ???? When you pass a single number to the Array() constructor, it doesn’t become the value of the first array element. It sets the length of the array instead. This means that new Array(3) creates an array with length of 3, but no actual elements. If you try to access any of the elements, you get the value undefined because the elements don’t exist. The following code example shows the different behavior when you