Why aren't options being overridden? - javascript

In my module pattern, options are 'undefined' for some reason.. does anyone see why they aren't being passed in properly?
Framework.MyModule = (function(options) {
var defaults = {
someOption : 1,
stuff : 2
};
if (!options) {
var options = defaults;
} else {
for (var index in defaults) {
if (typeof options[index] == 'undefined')
options[index] = defaults[index];
}
}
var module = {};
// Initialize
_something();
// Private Methods
function _something() {}
// Public Methods
module.click = function() {};
return module;
})();
... docready function ...
var options = {
someOption : 9,
stuff : 10
};
Framework.MyModule(options);
... end doc ready ...
Please see the fiddle: http://jsfiddle.net/kWHEZ/1/

var options = { /* ... */};
Framework.MyModule = (function(options) {
/* .. options are undefined ... */
})();
Framework.MyModule = (function(options) {
/* .. options are defined... */
})(options);
Now if you want the ability to add private/public variables AND still pass options you will need to make it so the a constructor method is returned with your public object - thus not passing options in the function that is run immediately. Because lets be honest .. this doesn't really make sense.
You could do something like this:
var Module = {};
Module.Foo = (function($){ // jQuery is accessible as $
var _private = {
defaults: {
url: '/default-url', container: '#dummy'
},
foos: []
};
return function(o){ // returns constructor
// other _private variables are accessible here
var opts = $.extend({}, _private.defaults, o);
var self = { // public return object
load: function(){
$(opts.container).load(opts.url);
}
};
_private.foos.push(self);
return self;
};
})(jQuery); // scope global variables
var foo1 = Module.Foo({
url: '/test.php',
container: '#success'
});
var foo2 = Module.Foo({
url: '/test2.php',
container: '#success2'
});
foo1.load();
foo2.load();

You're not passing in any options to the anonymous function call.
your call would have to end with })(options); if you want it to use custom options.

You're executing the function immediately. That function returns module, which is an object, not a function. Did you mean instead to return a function?
Then call it using:
Framework.MyModule(options);

Related

Using call to pass context

I'm trying to use call to pass the context of the Utilities object so I can access its members (allData array, etc) within the myTest function.
I'm getting error:
ReferenceError: allData is not defined
This tells me the context is lost and I guess I'm not binding the context correctly. How do I do this?
var Utilities = {
allData : [],
storage : [],
apiRequest : function () {
this.allData = ["a","b","c"];
var myTest = this.allData.map.call(this, function (i, el) {
var url = 'testPHP.php/translate_tts?ie=utf-8&tl=zh-CN&q=' + i;
return $.get(url, function (returned_data) {
this.storage.push(returned_data);
});
});
$.when.apply($, myTest).done(function () {
log('done!');
log(this.storage[i]);
});
Reminder
There is only function level context in Javascript, and this is nothing more than a local variable. By default, this is set to the global window object:
function me () { return this; };
me() === window; // true
Or to the object from which the function was invoked:
var o = {};
o.me = me;
o.me() === o; // true
Knowing this, read the following carefully:
var me = o.me;
me === o.me; // true, not a copy
me() === o; // false
me() === window; // true
var p = {};
p.me = o.me;
p.me() === p; // true
o.me() === o; // true
As you can see, this is automatically set at function invocation. This is the default behaviour, but you can also do it yourself using either .call() or .apply() (one shot):
me.call(o) === o; // true
me.apply(o) === o; // true
p.me.call(o) === o; // true
me() === window; // true
And more recently, .bind() (permanent):
me = me.bind(o);
me() === o; // true
me() === window; // false
Your question
I would use .bind():
var Utilities = {
allData : [],
storage : [],
apiRequest : function () {
this.allData = ["a","b","c"];
var myTest = this.allData.map(function (i, el) {
var url = 'testPHP.php/translate_tts?ie=utf-8&tl=zh-CN&q=' + i;
return $.get(url, function (returned_data) {
this.storage.push(returned_data);
}.bind(this));
}.bind(this));
$.when.apply($, myTest).done(function () {
log('done!');
// I've added a loop here
var i, l = arguments.length;
for (i = 0; i < l; i++) {
log(this.storage[i]);
}
}.bind(this));
Great answer above. One thing to emphasize at this point: whenever you bind the object at initialization it will be bound and cannot be call/apply'd using another context anymore. IMO it's up to you whether to use call/apply (at runtime) OR .bind (permanently).
Going from here:
I'm trying to use call to pass the context of the Utilities object so I can access its members (allData array, etc) within the myTest function.
var OtherTest = function() {
this.dataStorage.push(["ok"]);
console.log(arguments);
}
var Utilities = {
dataStorage: [],
allData: [],
apiRequest: function() {
this.allData = ["a","b","c"];
OtherTest.apply(this,arguments);
}
}
Utilities.apiRequest('hu','hu');
console.log(Utilities.dataStorage[0]);
Since this is a reference to the object, it can be mutated at any time after initialization making it easy to use call/apply to pass the context which is the Utilities Object in this case.

JavaScript "Class" Structure to avoid using x = new widget();

I would like use the following syntax where the parameter is an ID of HTML element, very similar as to how you setup JWPlayer but I can't figure out how they did it. This is so I can make it as simple as possible for someone else to use.
myWidget("htmlTargetId");
I'm trying to avoid having to do:
myWidget = new MyWidget("htmlTargetId");
I know that I can create the first by doing:
var myWidget = function(target) {
// Do something here
}
myWidget("htmlTargetId");
I need to add methods and properties etc but I would like a "constructor" that will create elements in the "htmlTargetId". What would be the best way to do this?
I tried a few variations, this is the latest attempt:
var myWidget = (function () {
var _target = undefined;
// constructor
var widget = function (target) {
_target = target;
version = 12;
};
widget.prototype = {
constructor: widget,
doSomething: function () {
console.log("I will so something to", target);
}
};
return widget;
})();
// Try out the new code
myWidget("htmlTargetId");
console.log(myWidget.version);
myWidget.doSomething();
But this gives me "undefined" and "Uncaught TypeError: undefined is not a function" I assume this is because the return statement is returning a function rather than an object because I'm not using "new"?
// Trying to avoid having to do this
superWidget = new myWidget("htmlTargetId");
Many thanks!
If you want to have multiple Widget instances,
var myWidget = (function () {
// constructor
var Widget = function (target) {
this._target = target;
};
Widget.prototype = {
constructor: Widget,
version: 12,
doSomething: function () {
console.log("...", this._target);
}
};
return function init(target) {
return new Widget(target);
};
})();
var widget1 = myWidget("foo"),
widget2 = myWidget("bar");
console.log(widget1.version); // 12
widget1.doSomething(); // "..." "foo"
widget2.doSomething(); // "..." "bar"
However, if you only need one "instance", you don't need any constructor:
var myWidget = function (target) {
myWidget._target = target;
};
myWidget.version = 12;
myWidget.doSomething = function () {
console.log("...", myWidget._target);
}
myWidget("foo");
console.log(myWidget.version); // 12
myWidget.doSomething(); // "..." "foo"

Extend the properties returned by a function?

I'm a JS beginner. I have defined a function on my Backbone model as follows.
myFunction: function () {
return {
firstAttr: this.model.get('value-attribute')
};
}
It is available to me as this.myFunction.
From somewhere else in the code, I want to extend this.myFunction to return another attribute. In other words, I'd like it to return a dict with two attributes: { firstAttr: 'something', secondAttr: true }.
How can I do this?
I've tried:
this.myFunction().secondAttr = true;
but I know that's the wrong thing to do.
Assuming your model prototype looks like
var MyModel = Backbone.Model.extend({
myFunction: function () {
return {
// I assume you work directly on a model
// the principle would be the same with a wrapper object
firstAttr: this.get('value-attribute')
};
}
});
you can either mask your method on a model by model basis like this:
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
m.myFunction = function () {
var res = MyModel.prototype.myFunction.call(this);
res.secondAttr = true;
return res;
};
console.log(m.myFunction());
See http://jsfiddle.net/V8zt2/ for a demo
Or dynamically modify your prototype to alter all instances :
var f = MyModel.prototype.myFunction;
MyModel.prototype.myFunction = function () {
var res = f.call(this);
res.secondAttr = true;
return res;
};
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
http://jsfiddle.net/V8zt2/1/
How about modifying your myFunction to :
myFunction : function () {
var i,
obj = {};
for (i=0; i< arguments.length;i++){
obj['attribute'+(i+1)] = this.model.get(arguments[i]);
}
return obj;
}
This way you can send keys of model, that you want to be in the returned object as arguments to myFunction.

Private functions in JavaScript

In a jQuery-based web application I have various script where multiple files might be included and I'm only using one of them at a time (I know not including all of them would be better, but I'm just responsible for the JS so that's not my decision). So I'm wrapping each file in an initModule() function which registers various events and does some initialization etc.
Now I'm curious if there are any differences between the following two ways of defining functions not cluttering the global namespace:
function initStuff(someArg) {
var someVar = 123;
var anotherVar = 456;
var somePrivateFunc = function() {
/* ... */
}
var anotherPrivateFunc = function() {
/* ... */
}
/* do some stuff here */
}
and
function initStuff(someArg) {
var someVar = 123;
var anotherVar = 456;
function somePrivateFunc() {
/* ... */
}
function anotherPrivateFunc() {
/* ... */
}
/* do some stuff here */
}
The major difference between these two approaches resides in the fact WHEN the function becomes available. In the first case the function becomes available after the declaration but in the second case it's available throughout the scope (it's called hoisting).
function init(){
typeof privateFunc == "undefined";
var privateFunc = function(){}
typeof privateFunc == "function";
}
function init(){
typeof privateFunc == "function";
function privateFunc(){}
typeof privateFunc == "function";
}
other than that - they're basically the same.
this is a model that helped me to manage modules in javascript:
base.js:
var mod = {};
mod.functions = (function(){
var self = this;
self.helper1 = function() {
} ;
self.helper2 = function() {
} ;
return self;
}).call({});
module_one.js
mod.module_one = (function(){
var
//These variables keep the environment if you need to call another function
self = this, //public (return)
priv = {}; //private function
priv.funA = function(){
}
self.somePrivateFunc = function(){
priv.funA();
};
self.anotherPrivateFunc = function(){
};
// ini module
self.ini = function(){
self.somePrivateFunc();
self.anotherPrivateFunc();
};
// ini/end DOM
$(function() {
});
return self; // this is only if you need to call the module from the outside
// exmple: mod.module_one.somePrivateFunc(), or mod.module_one.ini()
}).call({});

Is it possible to append functions to a JS class that have access to the class's private variables?

I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());

Categories

Resources