Javascript : can we reuse inner function to acces both global and local - javascript

var teamName ="studio";
var otherTeamName ={
teamName :'factory',
getTeamName : function(){
alert(this.teamName);
}
};
window.otherTeamName.getTeamName();// alerts factory
Is there any way to get the studio? by using the same getTeamName function.(i.e i know, removing this will fetch studio.) without removing the this?

Yes, it is possible. There are two ways:
use call: otherTeamName.getTeamName.call(window)
copy reference:
var getTeamName = otherTeamName.getTeamName;
getTeamName(); // alerts studio
call() is not supported by older browsers, the second solution works everywhere.
var teamName = "studio";
var otherTeamName = {
teamName: 'factory',
getTeamName: function() {
alert(this.teamName);
}
};
otherTeamName.getTeamName(); // alerts factory
var getTeamName = otherTeamName.getTeamName;
getTeamName(); // alerts studio

Yes, you can still use the same getTeamName method by changing context function is executed in:
var teamName = "studio";
var otherTeamName = {
teamName: 'factory',
getTeamName: function() {
alert(this.teamName);
}
};
otherTeamName.getTeamName.call(window);
By using Function.prototype.call you make this point to window instead of
otherTeamName object.
UPD. However, this will only work if teamName is global variable. If not, check Quentin's answer.

You can simply use
otherTeamName.getTeamName.call(this)
this here refers to the window

Short answer: No. It isn't a property of the object, so you can't access it as if it was.
Longer answer: You could replace the teamName property with a getter function that returned the value of the variable … but that would be an unintuitive approach to whatever the problem is.

// The good:
otherTeamName.getTeamName.call(this);
otherTeamName.getTeamName.apply(this);
// The okayish:
var f = otherTeamName.getTeamName; f();
otherTeamName.getTeamName.bind(this)();
// The bad:
((f) => f)(otherTeamName.getTeamName)();
(function(f) {f()})(otherTeamName.getTeamName)
// The ugly:
eval(otherTeamName.getTeamName)();
eval("(" + otherTeamName.getTeamName + ")()");
new Function("(" + otherTeamName.getTeamName + ")()")();

Related

make object sub-prototype have context of parent object

This may be a duplicate, and if so, I apologize. I've looked through a few questions and haven't found one that quite matches my situation (which maybe a bad sign to begin with).
I've got a class, say RandomClass, that is defined as follows
function RandomClass(id){
this._id = id;
}
RandomClass.prototype.getID = function(){
return this._id;
}
var rc = new RandomClass(1);
rc.getID(); //returns 1, as expected
Say I want to define a set of handlers, and keep them in a sub-object (while continuing to use prototype) of RandomClass. My knowledge of prototypes is somewhat limited, so apologies if this next bit is extremely bad form.
RandomClass.prototype.handlers = {};
RandomClass.prototype.handlers.HandlerOne = function(){
console.log("Handler one calling from ID: "+this._id);
//the context is not the context of RandomClass, but of RandomClass.prototype.handlers!
}
rc.handlers.HandlerOne(); //prints "Handler one calling from ID: unknown"
Again, maybe this is bad form, but I have several handlers which need to be called and doing things this way simplifies the code to:
var handler = "one of many many handlers returned from an ajax request";
rc.handlers[handler]();
So, my question is how do I make HandlerOne's context be the context of RandomClass rather than of handlers? I'd like to continue to use prototypes, because then they are not cloned multiple times (as in the following example):
function RandomClass(id){
this._id = id;
this._handlers = {};
}
function HandlerOne(){
console.log("Handler one calling from ID: "+this._id);
}
var rc = new RandomClass(1);
rc._handlers["HandlerOne"] = HandlerOne.bind(rc);
rc._handlers["HandlerOne"]() //prints as expected, but I believe performance is much worse here
Could satisfy to you do this, instead of bind the context try to pass it as a parameter.
function RandomClass(id){
this._id = id;
this._handlers = {};
}
function HandlerOne(instance){
var parentScope = instance;
console.log("Handler one calling from ID: "+parentScope._id);
}
//call it like this
var rc = new RandomClass(1);
rc._handlers["HandlerOne"] = HandlerOne;
rc._handlers["HandlerOne"](rc)
You could simply make Handlers it's own class. Note that you should not access private members from outside the class like I did in the exemple below. You must expose the correct public API to make objects work together without violating encapsulation.
function RandomClass(id){
this._id = id;
this.handlers = new Handlers(this);
}
function Handlers(randomClassInstance) {
this._randomClassInstance = randomClassInstance;
}
Handlers.prototype = {
constructor: Handlers,
handlerOne: function () {
console.log("Handler one calling from ID: "+ this._randomClassInstance._id);
}
};
Then you can do:
var rnd = new RandomClass('test');
rnd.handlers.handlerOne(); //Handler one calling from ID: test
Both answers submitted at this point are good alternatives (that I would say are acceptable), but I've decided to take another route (that lead to the least amount of modification to my code :)).
Similar to #BlaShadow's answer, rather than passing the context and setting a parentScope variable, I simply use Javascript's function.call() method to pass the correct context.
function RandomClass(id){
this._id = id;
}
function.prototype.handlers = {}
function.prototype.handlers.HandlerOne = function(data){
console.log("Handler one calling from ID: "+this._id+" with data: "+data);
}
var rc = new RandomClass(1);
rc.handlers.HandlerOne.call(rc, {"some": "data"});
//prints "Handler one calling from ID: 1 with data { "some" : "data" }

Call a function when a property gets set on an object

I don't really know how to explain this but I'll show you code and tell you what I'd like to achieve.
Let's say I make a quick object:
var test = {};
And then I set a property to it: (I insist on the syntax, it mustn't use any function as the setter)
test.hello = 'world';
Pretty simple, eh? Now I'd like to add a function to that object that would get called everytime a new property gets set. Like this:
var test = {
newPropertyHasBeenSet: function(name){
console.log(name + 'has been set.');
}
};
test.hello = 'world';
// Now newPropertyHasBeenSet gets called with 'hello' as an argument.
// hello has been set.
I don't know if it's possible, but that would be quite amazing. Anyone has an idea of how to achieve so?
EDIT: I'd like also to be able to do the same for property get (so test.hello would call get('hello') for example).
EDIT2: This is for server-side javascript using node.js.
Thanks a lot and have a nice day!
try this example in chrome (as mentioned in previous comments it uses ES6 Proxy):
var p = new Proxy(
{},
{
get: function(obj, name) {
console.log('read request to ' + name + ' property');
if (name == 'test_test') return 1234;
else return 'Meh';
},
set: function(obj, name, value) {
console.log('write request to ' + name + ' property with ' + value + ' value');
},
}
);
console.log(p.test_test);
console.log(p.test);
p.qqq = 'test';
result:
read request to test_test property
1234
read request to test property
Meh
write request to qqq property with test value
var test = {};
Object.defineProperty(test, "hello", {
get : function () {
return this._hello;
},
set : function (val) {
alert(val);
this._hello = val;
}
});
test.hello = "world";
Something like that. But it will not work on old browsers.
You can find more options here: http://robertnyman.com/javascript/javascript-getters-setters.html
If you really insist on keeping the test.hello = "world" syntax to detect changes for existing properties, then you'll have to wait a few years for Object.watch to become part of the next EcmaScript standard.
Luckily, you can do the same in EcmaScript 5 using Object.defineProperty. Eli Grey made a nice Object.watch polyfill which you can call like this:
var test = {};
test.watch("hello", function(propertyName, oldValue, newValue) {
console.log(propertyName + " has been set to " + newValue);
});
test.hello = "world"; // triggers the watch handler
You could modify his code to trigger a different handler inside the getter as well, so you can detect property accesses.
Unfortunately, browser support is limited to modern browsers including Internet Explorer 9, Firefox 4, Chrome, Opera 12 and Safari 5.
If you want to trigger a handler when a new property is set, you'll have even more trouble. The best you could do is wrapping your object inside a proxy and placing a set trap. You can then detect whether the property already existed by testing if this.getOwnPropertyDescriptor(name) returns a 'truthy' value. The Proxy API is very experimental though and only a few browsers provide a prototype implementation to play with. You'll probably have to wait quite a while to get a completed API with decent browser support.
you need a library that provides key-value observing and bindings.
ember-metal is one such library.
basically you create objects, and you can register observers on properties of those objects.
var obj = Em.Object.create({
val: null
valDidChange:function(){...}.observes('val')
});
valDidChange will fire whenever val property changes, so
obj.set('val', 'newValue');
will cause the observer to fire.
What about something like this? Here's a jsfiddle.
var objectManager = function(obj, setCallback){
this.obj = obj;
this.setCallback = setCallback;
};
objectManager.prototype.setProperty = function(prop, value){
this.obj[prop] = value;
this.setCallback(prop);
};
objectManager.prototype.getObj = function(){
return this.obj;
};
// USAGE:
var testMgr = new objectManager({}, function(prop){
console.log(name + ' has been set.');
});
testMgr.setProperty("hello", "world"); //should log "hello has been set.";

Need some help understanding basics about JS module pattern

I am trying to organize my code using the revealing module pattern.
I have a very basic question about how to set up a setter method.
$(document).ready(function() {
var designs = (function() {
var curRow,
setCurRow = function(val) {
curRow = val;
},
initTable = function() {
setCurRow(0);
};
return {
curRow : curRow,
setCurRow : setCurRow,
initTable : initTable
}
}) ();
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.curRow);
});
The problem is that i dont get the someNewVal in the console output, I get undefined instead! I have a feeling I am doing something pretty silly here.
You can also solve this in another way by understanding the scopes of the variables and functions involved.
When you return your object constructor { curRow: curRow ... }, that just initializes the object member named curRow to the value of the variable curRow in the scope of the anonymous function; it doesn't create any persistent connection between them.
Once the anonymous function returns, calling designs.setCurRow is updating the curRow variable in that scope exactly as you expect, but that variable is now totally inaccessible to the outside world -- there is no connection between it and the curRow member of designs.
You can solve this by making the setCurRow method operate on this.curRow, as in the other solutions. In that case you don't need to make curRow a variable in the original scope, since it's entirely unused. The other solution is to add a 'getter' method to your current one:
var designs = (function() {
var curRow,
setCurRow = function(val) {
curRow = val;
},
getCurRow = function() {
return curRow;
},
initTable = function() {
setCurRow(0);
};
return {
getCurRow : getCurRow,
setCurRow : setCurRow,
initTable : initTable
};
}) ();
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.getCurRow());
Because getCurRow and setCurRow are functions that are closed in the scope containing the variable varRow, they can reach back into that scope and access and change variables that are only accessible within it.
In this case making curRow a member of the object you return is probably simpler, but the other way is useful too since you can use it to create effectively private members and methods.
Looks like you want an object, not a module:
$(document).ready(function() {
var designs = {
setCurRow: function(val) {
this.curRow = val;
},
initTable: function() {
this.setCurRow(0);
},
curRow: 0
};
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.curRow);
});
The problem is that setCurRow sets the value of the variable curRow after designs.curRow has already been set. Consider something like this:
var a = 1;
b = a; // sets b = a = 1
b = 2; // sets b = 2; leaves a = 1
Your code is doing the same thing, but with object-properties and setter methods to make it look complicated. :-)
As ruakh pointed out, you never re-assign curRow on the returned object, so it is always the default value. Change it to:
setCurRow = function(val) {
this.curRow = curRow = val;
},
And everything should work*.
* At least mostly - you won't be able to use call and apply on setCurRow (or pass it to setTimeout or setInterval without binding it first to your object (designs), since this is bound at call time in JavaScript.

Javascript - Variable in function name, possible?

i hope this question is not too simple, but i have no idea :(
How can i start a function with a var in the function name?
For example ...
my functions
function at_26();
function at_21();
function at_99();
start the function
var test_id = 21;
at_'+test_id+'(); // doesn't work
I hope somebody can help me.
Thanks in advance!
Peter
Store your functions in an object instead of making them top level.
var at = {
at_26: function() { },
at_21: function() { },
at_99: function() { }
};
Then you can access them like any other object:
at['at_' + test_id]();
You could also access them directly from the window object…
window['at_' + test_id]();
… and avoid having to store them in an object, but this means playing in the global scope which should be avoided.
You were close.
var test_id = 21
this['at_'+test_id]()
However, what you may want:
at = []
at[21] = function(){ xxx for 21 xxx }
at[test_id]()
An example to pass an array of params to those composed functions, .
/* Store function names and match params */
let at = {
at_26 : (a,b,c) => at_26(a,b,c),
at_21 : (a,b,c) => at_21(a,b,c),
at_99 : (a,b,c) => at_99(a,b,c),
at_om : (a,b,c,d,e) => at_om(a,b,c,d,e)
}
/* Dynamic function router: name + array of Params */
function dynFunc(name, arrayParams){
return at[name](...arrayParams)
}
/* Usage examples */
dynFunc(`at_${99}`, ["track001", 32, true])
dynFunc("at_" + "om", ["track007", [50, false], 7.123, false, "Bye"])
/* In the scope */
function at_99(a,b,c){
console.log("Hi! " + a,b,c)
console.log(typeof(a), typeof(b), typeof(c))
}
function at_om(a,b,c,d,e){
console.log("Hi! " + a,b,c,d,e)
console.log(typeof(a), typeof(b), typeof(c), typeof(d), typeof(e))
}
You can also try
function at_26(){};
function at_21(){};
function at_99(){};
var test_id = 21;
eval('at_'+test_id+'()');
But use this code if you have very strong reasons for using eval. Using eval in javascript is not a good practice due to its disadvantages such as "using it improperly can open your script to injection attacks."
There is a better way then the window object - which is NOT friendly in firefox - use "self" instead - so in the example posted by Quentin it looks like this:
self['at_' + test_id]();

Global variables, Javascript

Can I do this ?
var global = 0;
var truc = $.getJSON("events.json", function(json){
//alert("JSON Data: " + json[0].titre);
global = json;
});
I want to keep the contents of json and work with it outside the function.
If it was C, I would just keep the pointer but I don't know what to do with JS
yes you can do that
I don't know the details on how json works, so I cannot say what happens in your case, but this simple test works as a simplified example on how your global variable will actually work:
var global = 0;
function callTest(arr) {
//alert("JSON Data: " + json[0].titre);
global = arr;
}
var array = new Array("w", "q");
callTest(array);
alert(global);
This means that it has something to do with how json works. One thing: Are you sure the function initialized with json is actually run before you test with alert(global) ?

Categories