I am attempting to use a function declaration within an object but am so far unable to. I know I can use function expressions within an object but is it possible to use function declarations instead?
This works:
var objContainer = {};
objContainer.callback = function(data) {
objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
};
This doesn't:
var objContainer = {};
function objContainer.callback(data) {
objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
}
I also tried using a function declaration using object literal notation but it also fails:
var objContainer = {
function callback(data) {
var objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
}
};
I know I can use function expressions within an object but is it possible to use function declarations instead?
No. Only expressions.
The closest you could get would be to have a function declaration in scope, and then assign the function to an object property by name.
function foo () { }
var bar = { func: foo };
If I'm understanding you correctly, you just want to use the "function funcname() { .. }" syntax instead of "obj.prop = function() { .. }" correct? The only way you'll be able to do that is using something like this:
function objContainer() {
this.callback = callback;
function callback(data) {
alert(data);
}
};
var myObjectContainer = new objContainer();
myObjectContainer.callback('hello world');
When you call a function using "varName = new funcName()" it creates an object.
For the last one example I think this is what you want:
var objContainer = {
callback : function(data) {
var objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
}
};
// then you could use the object like this:
objContainer.callback();
Related
I am trying to monkeypatch a 3rd party javascript library but the original function definition I am overloading keeps getting called.
var ns = {};
ns.topFxn = function(){
var _me = "me";
function _toOverride(){
console.log("This is the original: " + _me);
}
function pubFxn(){
_toOverride();
}
console.log("Original");
ns.pubFxn = pubFxn;
};
//attempt to monkey patch
var oldTopFxn = ns.topFxn;
ns.topFxn = function(){
oldTopFxn();
function _toOverride(){
console.log("This is the overriden: " + _me);
}
console.log("MonkeyPatch");
};
ns.topFxn();
ns.pubFxn();
OUTPUT:
scratch.js:15> Original
scratch.js:26> MonkeyPatch
scratch.js:10> This is the original: me
I think this is because this function is indirectly called by another function, and that function might hold a closure on the function it is pointing to - so maybe this isn't possible? Any suggestions on how to override?
jsfiddle
You can't override a local function in another function, because of variable scope. The name _toOverride is local to each function, and assigning it in your function has no effect on the function with the same name in a different function.
You would have to override ns.pubFxn.
var oldTopFxn = ns.topFxn;
ns.topFxn = function(){
oldTopFxn();
var oldPubFxn = ns.pubFxn;
function _toOverride(){
console.log("This is the overriden: " + _me);
}
ns.pubFxn = function() {
oldPubFxn();
_toOverride();
}
console.log("MonkeyPatch");
};
I'm trying to avoid using global variable when using functions within objects.
I want to invoke a function inside other function and use a variable from the first function's scope.
For example:
var showForecast = {
'init': function () {
this.getData();
},
'buildView': function(){
var code = "Hey, you're from " + this.data.city;
$('body').append(code);
},
'getData': function () {
$.getJSON('http://ipinfo.io/', function (data) {
console.log(data);
showForecast.buildView();
})
}
}
Clearly it's not working. I want to use data inside buildView without making data a global variable.
I thought using this would be the right course of action because I'm calling buildView from a function where data is defined.
How can this be achieved? Thanks.
You can pass the information along:
var showForecast = {
'init': function () {
this.getData();
},
'buildView': function(data){
var code = 'Hey, you\'re from ' + data.city;
$('body').append(code);
},
'getData': function () {
$.getJSON('http://ipinfo.io/', function (data) {
console.log(data);
showForecast.buildView(data);
})
}
}
There is no way to access the data variable itself. That is locally scoped to the anonymous function you pass to getJSON (and getJSON passes it as an argument, which is beyond your control).
You have to copy the value somewhere.
In your particular example, there are no scopes shared between getData and buildView other than the global scope. So if you want to pass the value through scopes, then a global is your own (terrible) option.
You can simply pass it as an argument:
showForecast.buildView(data);
Or you can store it as a property:
showForecast.myData = data;
I like Vinny's answer.
One round-bout way is to make a module out of it:
var showForecast = function(){
var data;
var init = function () {
this.getData();
};
var buildView = function(){
var code = 'Hey, you\'re from ' + this.data.city;
$('body').append(code);
};
var getData = function () {
$.getJSON('http://ipinfo.io/', function (data) {
console.log(data);
this.data = data;
showForecast.buildView();
})
};
return {
'init': init,
'buildView': buildView,
'getData': getData
};
}();
This way the scope of var data is limited to the function. It's like a private variable.
As you are trying to avoid global, you should consider using namespaces. There is no such thing called namespace in Javascript. But you can define yourself using small utility method mentioned here.
http://www.zachleat.com/web/namespacing-outside-of-the-yahoo-namespace/
A utility method which helps creating custom namespaces.
jQuery.namespace = function() {
var a=arguments, o=null, i, j, d;
for (i=0; i<a.length; i=i+1) {
d=a[i].split(".");
o=window;
for (j=0; j<d.length; j=j+1) {
o[d[j]]=o[d[j]] || {};
o=o[d[j]];
}
}
return o;
};
Define name space
jQuery.namespace( 'jQuery.showForecast' );
Define methods using revealing module pattern
https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript
jQuery.showForecast = (function() {
var data;
var init = function() {
getData();
}
var buildView = function() {
var code = "Hey, you're from " + data.city;
$('body').append(code);
}
var getData = function() {
$.getJSON('http://ipinfo.io/', function(_data) {
console.log(data);
data = _data;
buildView();
})
}
return {
init: init
};
})(); // Execute it immediately
Usage:
You can access only init method as it is exposed to outside.
jQuery.showForecast.init()
Define another namespace
jQuery.namespace( 'jQuery.showForecast.extended' );
jQuery.showForecast.extended = {
// Define some more
};
i run into this code and i'm not familiar with the syntax - What is the "get: " stands for? and why is it written this way?
var newVar = {
get: function fn() {
return this.val;
},
val: 43
};
var child = Object.create(newVar);
child.val = 333;
var child2 = Object.create(child);
console.log(child.get() + child2.get());
There is nothing special about get. In your example, it is simply a property of an object called get. It could just as easily by called getMeOutOfHere:
var newVar = {
getMeOutOfHere: function () { console.log('we\'re leaving'); }
}
I have a function name in a string:
var func = "doTest";
I need this function to be applied to the current instance ("this");
So I need it to call:
this.doTest();
How can I do this? I cannot go via window.
Thanks,
Wesley
Just use the construct of object[functionName]();, like so:
function Person() {};
Person.prototype.speak = function() { alert('ohai'); };
var john = new Person, action = 'speak';
john[action]();
Alternative style:
var Person = {
speak: function() { alert('ohai'); },
speakDelegate: function() { var action = 'speak'; this[action](); }
};
Person.speakDelegate();
this[func]();
No need to .call or .apply since context is held in the reference.
For example:
var obj = {
doTest: function(){ console.log(this); },
fn: function(){ var name='doTest'; this[name](); }
};
obj.fn(); // logs the object, proving this has the correct context.
Try the following
var funcObj = this["doTest"];
funcObj.apply(this);
What this does is grab the member named doTest from this. It then executes the function via apply and tells javascript to bind this as this within the function. I think the example is a bit less confusing if you consider the same code on a non-this value
var obj = {
doTest: function() {
console.log("doTest called");
}
};
var doTestFunc = obj["doTest"];
doTestFunc.apply(obj);
In this case the method doTest will be executed with the value obj as this
If you are using jquery you can just do:
$(this)[func]()
I've been playing around and searching a bit, but I can't figure this out. I have a pseudo private function within a JavaScript object that needs to get called via eval (because the name of the function is built dynamically). However, the function is hidden from the global scope by a closure and I cannot figure out how to reference it using eval().
Ex:
var myObject = function(){
var privateFunctionNeedsToBeCalled = function() {
alert('gets here');
};
return {
publicFunction: function(firstPart, SecondPart) {
var functionCallString = firstPart + secondPart + '()';
eval(functionCallString);
}
}
}();
myObject.publicFunction('privateFunctionNeeds', 'ToBeCalled');
I know the example looks silly but I wanted to keep it simple. Any ideas?
The string passed to eval() is evaluated in that eval()'s scope, so you could do
return {
publicFunction: function(firstPart, SecondPart) {
var captured_privateFunctionNeedsToBeCalled = privateFunctionNeedsToBeCalled;
var functionCallString = 'captured_' + firstPart + secondPart + '()';
eval(functionCallString);
}
}
However, a better solution would be to avoid the use of eval() entirely:
var myObject = function(){
var functions = {};
functions['privateFunctionNeedsToBeCalled'] = function() {
alert('gets here');
};
return {
publicFunction: function(firstPart, secondPart) {
functions[firstPart+secondPart]();
}
}
}();
myObject.publicFunction('privateFunctionNeeds', 'ToBeCalled');