An in depth understanding of the JavaScript series (48) : object creation patterns (part 2)

  • 2020-05-10 17:45:01
  • OfStack

introduce

This is the next installment of a series of patterns for creating objects, using techniques that can significantly avoid errors or allow you to write very lean code.

Pattern 6: functional grammar sugar

Function grammar sugar is an extension to quickly add methods (functions) for 1 object. This is mainly to take advantage of the features of prototype. The code is relatively simple.


if (typeof Function.prototype.method !== "function") {
    Function.prototype.method = function (name, implementation) {
        this.prototype[name] = implementation;
        return this;
    };
}

When extending objects, you can use:

var Person = function (name) {
    this.name = name;
}
.method('getName',
            function () {
                return this.name;
            })
.method('setName', function (name) {
    this.name = name;
    return this;
});

In this way, getName and setName are added to the Person function. Next, let's verify the result of 1:

var a = new Person('Adam');
console.log(a.getName()); // 'Adam'
console.log(a.setName('Eve').getName()); // 'Eve'

Pattern 7: object constants

Object constants are the embodiment of various methods of set,get and ifDefined in an object. Moreover, for the method of set, only the first set object will be retained, and the later set is invalid, which has reached the purpose that others cannot overload. The implementation code is as follows:


var constant = (function () {
    var constants = {},
        ownProp = Object.prototype.hasOwnProperty,
    // Only this is allowed 3 Values of various types
        allowed = {
            string: 1,
            number: 1,
            boolean: 1
        },
        prefix = (Math.random() + "_").slice(2);     return {
        // Set the name to name The properties of the
        set: function (name, value) {
            if (this.isDefined(name)) {
                return false;
            }
            if (!ownProp.call(allowed, typeof value)) {
                return false;
            }
            constants[prefix + name] = value;
            return true;
        },
        // To determine if the name exists name The properties of the
        isDefined: function (name) {
            return ownProp.call(constants, prefix + name);
        },
        // Get the name as name The properties of the
        get: function (name) {
            if (this.isDefined(name)) {
                return constants[prefix + name];
            }
            return null;
        }
    };
} ());

The verification code is as follows:


// Check for presence
console.log(constant.isDefined("maxwidth")); // false // define
console.log(constant.set("maxwidth", 480)); // true // To detect
console.log(constant.isDefined("maxwidth")); // true // Trying to redefine
console.log(constant.set("maxwidth", 320)); // false // Determine if the original definition still exists
console.log(constant.get("maxwidth")); // 480

Pattern 8: sandbox pattern

The sandbox (Sandbox) mode instantly provides a separate context for one or more modules without affecting the context of other modules. For example, if there are three methods in Sandbox, event,dom,ajax, there is no interference between two of them to make up one environment and three of them to make up one environment. The implementation code of Sandbox is as follows:


function Sandbox() {
    // Converts the argument to an array
    var args = Array.prototype.slice.call(arguments),
    // The last 1 The parameters for callback
        callback = args.pop(),
        // In addition to the last 1 The other parameters are the modules to be selected
        modules = (args[0] && typeof args[0] === "string") ? args : args[0],
        i;     // Forced to use new The operator
    if (!(this instanceof Sandbox)) {
        return new Sandbox(modules, callback);
    }     // Add attributes
    this.a = 1;
    this.b = 2;     // to this You want to add a module to an object
    // If there is no module or the parameter passed in is "*" , means passing in all modules
    if (!modules || modules == '*') {
        modules = [];
        for (i in Sandbox.modules) {
            if (Sandbox.modules.hasOwnProperty(i)) {
                modules.push(i);
            }
        }
    }     // Initialize the required modules
    for (i = 0; i < modules.length; i += 1) {
        Sandbox.modules[modules[i]](this);
    }     // call callback
    callback(this);
} // Add the prototype object by default
Sandbox.prototype = {
    name: "My Application",
    version: "1.0",
    getName: function () {
        return this.name;
    }
};

Then we define the default initial module:


Sandbox.modules = {}; Sandbox.modules.dom = function (box) {
    box.getElement = function () {
    };
    box.getStyle = function () {
    };
    box.foo = "bar";
}; Sandbox.modules.event = function (box) {
    // access to the Sandbox prototype if needed:
    // box.constructor.prototype.m = "mmm";
    box.attachEvent = function () {
    };
    box.detachEvent = function () {
    };
}; Sandbox.modules.ajax = function (box) {
    box.makeRequest = function () {
    };
    box.getResponse = function () {
    };
};

The method of invocation is as follows:


// Call way
Sandbox(['ajax', 'event'], function (box) {
    console.log(typeof (box.foo));
    // Have no choice dom , so box.foo There is no
}); Sandbox('ajax', 'dom', function (box) {
    console.log(typeof (box.attachEvent));
    // Have no choice event, so event The definition of attachEvent There is no
}); Sandbox('*', function (box) {
    console.log(box); // All the methods defined above are accessible
});

Through three different ways of calling, we can see that the context of the three ways is different, the first way does not have foo; The second does not have attachEvent, because only ajax and dom are loaded, not event; The third one loads them all.

Pattern 9: static members

A static member (Static Members) is just a static property provided by a function or object, which can be private or public, as in C# or Java public static and private static1.

Let's look at 1 public member first. Public member is very simple. The methods we usually declare are all public functions, such as:


// The constructor
var Gadget = function () {
}; // Public static method
Gadget.isShiny = function () {
    return "you bet";
}; // Normal methods added to the stereotype
Gadget.prototype.setPrice = function (price) {
    this.price = price;
}; // Calling static methods
console.log(Gadget.isShiny()); // "you bet" // Create the instance, and then call the method
var iphone = new Gadget();
iphone.setPrice(500); console.log(typeof Gadget.setPrice); // "undefined"
console.log(typeof iphone.isShiny); // "undefined"
Gadget.prototype.isShiny = Gadget.isShiny;
console.log(iphone.isShiny()); // "you bet"

While private static members can be implemented using their closure properties, there are two ways to do this.

The first implementation method:


var Gadget = (function () {
    // A static variable / attribute
    var counter = 0;     // Closure returns a new implementation of the constructor
    return function () {
        console.log(counter += 1);
    };
} ()); // Executed immediately var g1 = new Gadget(); // logs 1
var g2 = new Gadget(); // logs 2
var g3 = new Gadget(); // logs 3

It can be seen that although it is the object of new every time, the number is still increasing, achieving the purpose of static membership.

The second way:


var Person = function (name) {
    this.name = name;
}
.method('getName',
            function () {
                return this.name;
            })
.method('setName', function (name) {
    this.name = name;
    return this;
});
0
The number is also incremented, which is achieved using the closure feature of its internal authorization method.

conclusion

This is the next part of the object creation pattern. There are 9 patterns in total, which are commonly used in daily JavaScript programming. Different scenarios play different roles.


Related articles: