confusion of javascript closure - javascript

I am studying JavaScript closure.
I want to modularize with closure.
So I wrote the code and I did not get the results I wanted
I want different results for result box1 and box2. But for some reason getting same results.
what should I do?
var spinBox = function() {
var spinBoxConfig;
return {
create: function(config) {
spinBoxConfig = {
value: typeof config.value === 'number' ? config.value : 200
}
return this;
},
getValue: function() {
return spinBoxConfig.value;
}
}
}()
var box1 = spinBox.create({
value: 30
});
var box2 = spinBox.create({
value: 310
});
console.log(box1.getValue()); // same
console.log(box2.getValue()); // same
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

You're creating a closure once, when you define the spinbox object. Everything that calls create or getValue will be interacting with that single instance of spinBoxConfig. If you want to create brand new closures every time you call create, you'll need to do so in your create function.
var spinBox = {
create: function (config) {
var spinBoxConfig = {
value: typeof config.value === 'number' ? config.value : 200
}
return {
getValue: function () {
return spinBoxConfig.value;
}
}
}
}
var box1 = spinBox.create({
value: 30
});
var box2 = spinBox.create({
value: 310
});
console.log(box1.getValue());
console.log(box2.getValue())
Though really, that spinBoxconfig is kind of overkill, since you already have the config param in your closure and it has all the relevant data. So you could do this:
var spinBox = {
create: function (config) {
if (typeof config !== 'number') {
config = 200;
}
return {
getValue: function () {
return config;
}
}
}
}
var box1 = spinBox.create(30);
var box2 = spinBox.create(310);
console.log(box1.getValue());
console.log(box2.getValue())

Related

Is there an analogue to Object.defineProperty to define variables?

It's easy to make private variables accessed by public methods of a module you're exporting:
var makeAModule = function() {
var _secret = 'Ssh!';
var module = {
tellMeYourSecret: function() {
console.log(_secret);
}
};
return module;
}
// > var m = makeAModule();
// > m.tellMeYourSecret();
// Ssh!
Sometimes I need to define properties with Object.defineProperty that are computed by getters using the value of other private variables. Those have to go on an object, though, so I end up making a private object just to hold them. If I don't store all my private members on that object, it gets confusing to remember which props are on it and which aren't, so I put everything there:
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(priv, 'secretLength', {
get: function() {
return priv._secret.length;
}
});
var module = {
tellMeYourSecret: function() {
console.log(priv._secret);
},
howLongIsYourSecret: function() {
console.log(priv._secretLength);
}
}
return module;
}
// > var m = makeAModule();
// > m.howLongIsYourSecret();
// 4
Is there any way to define a variable (not attached to an object) whose value is computed through a getter? Something like this:
var makeAModule = function() {
var _secret = 'Ssh!';
Object.defineVariable('_secretLength', {
get: function() {
return _secret.length;
}
})
var module = {
tellMeYourSecret: function() {
console.log(_secret);
},
howLongIsYourSecret: function() {
console.log(_secretLength);
}
}
return module;
}
Not directly.
However, you can set it as a property of window, thus making it a global variable. But using global variables is not recommendable, specially if they are secret.
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(window, '_secretLength', {
get: function() {
return priv._secret.length;
}
});
return {
tellMeYourSecret: function() {
return _secret;
},
howLongIsYourSecret: function() {
return _secretLength;
}
};
};
document.body.innerHTML =
"Secret length: " + makeAModule().howLongIsYourSecret();
Alternatively, you can define your getters as properties of an object, and use a with statement. Note that the with statement can't be used in strict mode.
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(priv, '_secretLength', {
get: function() {
return priv._secret.length;
}
});
with(priv) {
return {
tellMeYourSecret: function() {
return _secret;
},
howLongIsYourSecret: function() {
return _secretLength;
}
};
}
};
document.body.innerHTML =
"Secret length: " + makeAModule().howLongIsYourSecret();

Mutually exclusive booleans in javascript object?

I have a javascript object with 3 booleans:
var obj = {};
obj.isPrimary = true;
obj.isPromotion = false;
obj.isSocial = false;
Only one of these can be true, there can never be a case where more than 1 is true. How can I achieve this?
Using a getter / setter should do the trick:
var obj = {
set isPrimary(bool){
this.Primary = bool;
if(bool){
this.Promotion = this.Social = false;
}
},
set isSocial(bool){
this.Social = bool;
if(bool){
this.Promotion = this.Primary = false;
}
},
set isPromotion(bool){
this.Promotion = bool;
if(bool){
this.Primary = this.Social = false;
}
},
get isPrimary(){ return this.Primary; },
get isSocial(){ return this.Social; },
get isPromotion(){ return this.Promotion; }
}
obj.isPrimary = true;
obj.isSocial = true;
obj.isPromotion = true;
alert(obj.isPrimary + ' ' + obj.isSocial + ' ' + obj.isPromotion);
// false false true (So only `obj.isPromotion` is true)
You can use Object.defineProperty something like:
Object.defineProperty(obj, 'isPrimary', {
get: function(){
return !this.isPromotion && !this.isSocial; //<-- Your logic goes here.
}
});
Of course the logic behind toggling this option on and off it is up to you.
You can simulate this with a function like this
function createToggleValues() {
var options = {
"primary": 1,
"promotion": 2,
"social": 4
},
value = 0;
return {
"set": function(name) {
value = options[name];
},
"is": function(name) {
return (value & options[name]) === options[name];
}
}
};
var togglable = createToggleValues();
togglable.set("primary");
console.log(togglable.is("primary"));
// true
If you require more options to be added, then you might want to simply extend the options object with new values and the next multiple of 2.
Closures are your friend. They prevent that somebody can fiddle with the internal state.
function createPropObj() {
var props = 0;
return {
get isPrimary() { return props === 1; },
set isPrimary(val) { if (val) { props = 1; }; },
get isPromotion() { return props === 2; },
set isPromotion(val) { if (val) { props = 2; }; },
get isSocial() { return props === 4; },
set isSocial(val) { if (val) { props = 4; }; }
}
}
You can use it like that:
> var test = createPropObj();
undefined
> test.isPrimary = true;
true
> test.isPromotion = true;
true
> test.isPrimary
false
You could create an object responsible for allowing a single flag to be true at a time. That would relieve your obj from implementing that logic. In the example below, SingleTrueFlagGroup holds onto a collection of flags, allowing a single one to be true at a time. Your obj can then double-dispatch on an instance of this object to get the job done.
The advantage of a similar implementation is that adding and removing flags becomes trivial.
var flags = ['isPrimary', 'isPromotion', 'isSocial'],
obj = {
_flags: new SingleTrueFlagGroup(flags)
};
flags.forEach(function (flag) {
Object.defineProperty(obj, flag, {
get: function () { return this._flags.get(flag); },
set: function (value) { this._flags.set(flag, value); }
});
});
obj.isPrimary = true;
obj.isPromotion = true;
console.log(obj.isPrimary); //false
console.log(obj.isPromotion); //true
function SingleTrueFlagGroup(flags) {
this._flags = {};
(flags || []).forEach(this.add.bind(this));
}
SingleTrueFlagGroup.prototype = {
constructor: SingleTrueFlagGroup,
set: function (flagToSet, value) {
var flags = this._flags;
(flags[flagToSet] = !!value) && Object.keys(flags).forEach(function (flag) {
if (flag !== flagToSet) flags[flag] = false;
});
},
get: function (flag) { return this._flags[flag]; },
add: function (flag) { this._flags[flag] = false; }
};
The other answers may work, but they seem over-engineered*.
If the values are exclusive, you should represent them in a single property, not three separate booleans:
obj.type = 'primary' // or 'promotion' or 'social'
Assignment among different values is inherently exclusive, since the variable can only hold one value at a time.
Or if you don't like magic strings, you can use an enumeration of defined values:
const TYPE_PRIMARY = 0
const TYPE_PROMOTION = 1
const TYPE_SOCIAL = 2
...
obj.type = TYPE_PRIMARY

Knockout Nested Object Scoping Undefined Reference

I'm trying to write a basic form using KnockoutJS using the following code:
var Form = function() {
var self = this;
self.name = {
value: ko.observable(""),
isValid: ko.computed(function () {
return self.name.value().length > 0;
}),
},
self.email = {
value: ko.observable(""),
isValid: ko.computed(function () {
return false;
})
},
self.message = {
value: ko.observable(""),
isValid: ko.computed(function () {
return false;
})
},
self.isValid = ko.computed(function () {
return self.name.isValid && self.email.isValid && self.message.isValid;
})
};
However, when I try to run this code I get the following error: Unable to get property 'value' of undefined or null reference. To me, this looks like a scope issue, but I'm not familiar enough with Knockout to understand why this is happening. Without Knockout I seem to be able to get this code working (replacing all observables with true for value and functions for isValid), but I'm looking to get these values updated in real-time. I could always separate out the validation functions to top-level functions but it seems like the improper way to do this. Each form field has a value and it's own unique validation, so it makes sense to make each form field it's own object with both properties.
Any help or guidance is appreciated.
This
self.name = {
value: ko.observable(""),
isValid: ko.computed(function () {
return self.name.value().length > 0;
}),
},
doesn't work because the inner function (the computed callback) refers to self.name, which is not even completely defined yet. Since computeds are called immediately, you see an error.
You could use the deferEvaluation option to delay evaluating the isValid computed until something actually requests its value:
self.name = {
value: ko.observable(""),
isValid: ko.computed({
read: function () { return self.name.value().length > 0; },
deferEvaluation: true
}),
},
That would work, but it would also quickly start to become repetitive and unwieldy.
As an alternative you can use Knockout extenders to make an observable validatatable in an abstract/decoupled fashion.
ko.extenders.validator = function (target, validationCallback) {
// create an isValid property on the target observable,
// immediately calculate validity of its current value
target.isValid = ko.observable(validationCallback(target()));
// subscribe to future changes
target.subscribe(function (newValue) {
target.isValid(validationCallback(newValue));
});
// return target observable for chaining
return target;
};
Now with this extender defined, all you need to do is create callback functions that validate a value and return true or false.
var Form = function () {
var self = this;
self.name = ko.observable("").extend({
validator: function (value) { return value.length > 0; }
});
self.email = ko.observable("").extend({
validator: function (value) { return true; }
});
self.message = ko.observable("").extend({
validator: function (value) { return true; }
});
self.isValid = ko.computed(function () {
var overallValid = true;
ko.utils.objectForEach(self, function (key, value) {
if (value.hasOwnProperty("isValid")) {
overallValid = overallValid && value.isValid();
}
});
return overallValid;
});
};
Further separating your validation functions now becomes very simple:
var validators = {
email: function (value) { return /* email check here */; },
minLen: function (minLen) {
return function (value) { return value.length >= minLen; }
},
maxLen: function (maxLen) {
return function (value) { return value.length <= maxLen; }
},
minmaxLen: function (minLen, maxLen) {
return function (value) { return value.length >= minLen && value.length <= maxLen; }
},
matches: function (regex) {
return function (value) { return regex.test(value); }
}
}
and
self.name = ko.observable("").extend({ validator: validators.minLen(1) });
self.age = ko.observable("").extend({ validator: validators.matches(/^\d+$/) });
You will find that of course somebody already did all of this (and much more).
It's best to create separate functions for each of your objects:
var Form = function() {
var self = this;
self.name = new NameFormField();
}
var NameFormField = function() {
var self = this;
self.value = ko.observable("");
self.isValid = ko.computed(function () {
//not sure why you are checking length here
return self.value().length > 0;
});
}
The other way that you could get it to work is by doing this:
var Form = function() {
var self = this;
self.name = {
value: ko.observable("")
};
self.name.isValid = ko.computed(function () {
//not sure why you are checking length here
return self.name.value().length > 0;
});

JavaScript Constants

we know we can protect the value of variables , so user can't change the value of variables the existing!! Does implementation this have nothing wrong with object..??
for example..
const x = 5;
x = 10;
alert(x)
// will be returned 5
using an object..
const obj = {
init: function() {
obj.show()
},
show: function() {
//..
},
hide: function() {
//..
}
}
obj.init();
If you can get away with using JS5, you have this option:
var CONST = {
NAME: "The Cool Gizmo",
VERSION: 2
};
Object.freeze(CONST);
alert(CONST.NAME);
var myObj = (function () {
var privVar1 = 111,
privVar2 = 222;
var getConstants = function () {
return { priv1: privVar1, priv2: privVar2 }
};
return { getConstants: getConstants };
})();
myObj.getConstants().priv1
The const keyword is not currently supported by all browsers, nor is it a part of the official Javascript specification in use today. (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/const)
To accomplish a constant, consider encapsulating the behavior you need in a function:
var getConstant = function(key) {
var constants = { x: 5 };
return constants[key];
};
alert(getConstant("x"));
Or, simply use a variable with the appropriate scope to protect 3rd parties from setting its value:
function myModule() {
var x = 5;
doSomethingWith(x);
}

Super in Backbone

When I override the clone() method of a Backbone.Model, is there a way to call this overriden method from my implantation? Something like this:
var MyModel = Backbone.Model.extend({
clone: function(){
super.clone();//calling the original clone method
}
})
You'll want to use:
Backbone.Model.prototype.clone.call(this);
This will call the original clone() method from Backbone.Model with the context of this(The current model).
From Backbone docs:
Brief aside on super: JavaScript does not provide a simple way to call
super — the function of the same name defined higher on the prototype
chain. If you override a core function like set, or save, and you want
to invoke the parent object's implementation, you'll have to
explicitly call it.
var Note = Backbone.Model.extend({
set: function(attributes, options) {
Backbone.Model.prototype.set.apply(this, arguments);
...
}
});
You can also use the __super__ property which is a reference to the parent class prototype:
var MyModel = Backbone.Model.extend({
clone: function(){
MyModel.__super__.clone.call(this);
}
});
Josh Nielsen found an elegant solution for this, which hides a lot of the ugliness.
Just add this snippet to your app to extend Backbone's model:
Backbone.Model.prototype._super = function(funcName){
return this.constructor.prototype[funcName].apply(this, _.rest(arguments));
}
Then use it like this:
Model = Backbone.model.extend({
set: function(arg){
// your code here
// call the super class function
this._super('set', arg);
}
});
Working from the answers given by geek_dave and charlysisto, I wrote this to add this._super(funcName, ...) support in classes that have multiple levels of inheritance. It's worked well in my code.
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
// Find the scope of the caller.
var scope = null;
var scan = this.__proto__;
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === arguments.callee.caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
return scan.constructor.__super__[funcName].apply(this, _.rest(arguments));
};
A year later I've fixed some bugs and made things faster. Below is the code that I use now.
var superCache = {};
// Hack "super" functionality into backbone.
Backbone.View.prototype._superFn = Backbone.Model.prototype._superFn = function(funcName, _caller) {
var caller = _caller == null ? arguments.callee.caller : _caller;
// Find the scope of the caller.
var scope = null;
var scan = this.__proto__;
var className = scan.constructor.className;
if (className != null) {
var result = superCache[className + ":" + funcName];
if (result != null) {
for (var i = 0; i < result.length; i++) {
if (result[i].caller === caller) {
return result[i].fn;
}
}
}
}
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
var result = scan.constructor.__super__[funcName];
if (className != null) {
var entry = superCache[className + ":" + funcName];
if (entry == null) {
entry = [];
superCache[className + ":" + funcName] = entry;
}
entry.push({
caller: caller,
fn: result
});
}
return result;
};
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
var args = new Array(arguments.length - 1);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i + 1];
}
return this._superFn(funcName, arguments.callee.caller).apply(this, args);
};
Then given this code:
var A = Backbone.Model.extend({
// className: "A",
go1: function() { console.log("A1"); },
go2: function() { console.log("A2"); },
});
var B = A.extend({
// className: "B",
go2: function() { this._super("go2"); console.log("B2"); },
});
var C = B.extend({
// className: "C",
go1: function() { this._super("go1"); console.log("C1"); },
go2: function() { this._super("go2"); console.log("C2"); }
});
var c = new C();
c.go1();
c.go2();
The output in the console is this:
A1
C1
A2
B2
C2
What's interesting is that class C's call to this._super("go1") scans the class hierarchy until it gets a hit in class A. Other solutions do not do this.
P.S. Uncomment the className entries of the class definitions to enable caching of the _super lookup. (The assumption is that these class names will be unique in the application.)
If you want just to call this._super(); without passing the function name as an argument
Backbone.Controller.prototype._super = function(){
var fn = Backbone.Controller.prototype._super.caller, funcName;
$.each(this, function (propName, prop) {
if (prop == fn) {
funcName = propName;
}
});
return this.constructor.__super__[funcName].apply(this, _.rest(arguments));
}
Better use this plugin:
https://github.com/lukasolson/Backbone-Super
I believe you can cache the original method (although not tested):
var MyModel = Backbone.Model.extend({
origclone: Backbone.Model.clone,
clone: function(){
origclone();//calling the original clone method
}
});
backbone._super.js, from my gists: https://gist.github.com/sarink/a3cf3f08c17691395edf
// Forked/modified from: https://gist.github.com/maxbrunsfeld/1542120
// This method gives you an easier way of calling super when you're using Backbone in plain javascript.
// It lets you avoid writing the constructor's name multiple times.
// You still have to specify the name of the method.
//
// So, instead of having to write:
//
// var Animal = Backbone.Model.extend({
// word: "",
// say: function() {
// return "I say " + this.word;
// }
// });
// var Cow = Animal.extend({
// word: "moo",
// say: function() {
// return Animal.prototype.say.apply(this, arguments) + "!!!"
// }
// });
//
//
// You get to write:
//
// var Animal = Backbone.Model.extend({
// word: "",
// say: function() {
// return "I say " + this.word;
// }
// });
// var Cow = Animal.extend({
// word: "moo",
// say: function() {
// return this._super("say", arguments) + "!!!"
// }
// });
(function(root, factory) {
if (typeof define === "function" && define.amd) {
define(["underscore", "backbone"], function(_, Backbone) {
return factory(_, Backbone);
});
}
else if (typeof exports !== "undefined") {
var _ = require("underscore");
var Backbone = require("backbone");
module.exports = factory(_, Backbone);
}
else {
factory(root._, root.Backbone);
}
}(this, function(_, Backbone) {
"use strict";
// Finds the next object up the prototype chain that has a different implementation of the method.
var findSuper = function(methodName, childObject) {
var object = childObject;
while (object[methodName] === childObject[methodName]) {
object = object.constructor.__super__;
}
return object;
};
var _super = function(methodName) {
// Keep track of how far up the prototype chain we have traversed, in order to handle nested calls to `_super`.
this.__superCallObjects__ || (this.__superCallObjects__ = {});
var currentObject = this.__superCallObjects__[methodName] || this;
var parentObject = findSuper(methodName, currentObject);
this.__superCallObjects__[methodName] = parentObject;
// If `methodName` is a function, call it with `this` as the context and `args` as the arguments, if it's an object, simply return it.
var args = _.tail(arguments);
var result = (_.isFunction(parentObject[methodName])) ? parentObject[methodName].apply(this, args) : parentObject[methodName];
delete this.__superCallObjects__[methodName];
return result;
};
// Mix in to Backbone classes
_.each(["Model", "Collection", "View", "Router"], function(klass) {
Backbone[klass].prototype._super = _super;
});
return Backbone;
}));
In the case that you don't know what the parent class is exactly (multiple inheritance or you want a helper function) then you can use the following:
var ChildModel = ParentModel.extend({
initialize: function() {
this.__proto__.constructor.__super__.initialize.apply(this, arguments);
// Do child model initialization.
}
});
With helper function:
function parent(instance) {
return instance.__proto__.constructor.__super__;
};
var ChildModel = ParentModel.extend({
initialize: function() {
parent(this).initialize.apply(this, arguments);
// Do child model initialization.
}
});
Pass the parent class as an option during instantiation:
BaseModel = Backbone.Model.extend({
initialize: function(attributes, options) {
var self = this;
this.myModel = new MyModel({parent: self});
}
});
Then in your MyModel you can call parent methods like this
this.options.parent.method();
Keep in mind this creates a retain cycle on the two objects. So to let the garbage collector do it's job you would need to manually destroy the retain on one of the objects when finished with it. If you're application is pretty large. I would encourage you to look more into hierarchal setups so events can travel up to the correct object.
2 functions below, one requires you pass in the function name, the other can "discover" which function we want the super version of
Discover.Model = Backbone.Model.extend({
_super:function(func) {
var proto = this.constructor.__super__;
if (_.isUndefined(proto[func])) {
throw "Invalid super method: " + func + " does not exist in prototype chain.";
}
return proto[func].apply(this, _.rest(arguments));
},
_superElegant:function() {
t = arguments;
var proto = this.constructor.__super__;
var name;
for (name in this) {
if (this[name] === arguments.callee.caller) {
console.log("FOUND IT " + name);
break;
} else {
console.log("NOT IT " + name);
}
}
if (_.isUndefined(proto[name])) {
throw "Super method for: " + name + " does not exist.";
} else {
console.log("Super method for: " + name + " does exist!");
}
return proto[name].apply(this, arguments);
},
});
Here is how I would do this:
ParentClassName.prototype.MethodToInvokeName.apply(this);
so for your example this is:
Model.prototype.clone.apply(this)

Categories