I'd like to be able to store the addresses of a bunch of different variables in an array. This allows me to access the variables by name or iterate through them if I need to. Is this possible in JS?
(function(ns){
ns.obj = new function(){
var foo = "foo";
var bar = "bar";
//i really want this:
//var ary = [&foo, &bar];
var ary = [foo, bar];
this.print = function() {
console.log( foo );
console.log( bar );
}
this.setFoo = function( newFoo ) {
//i really want this:
//*(ary[0]) = newFoo;
ary[0] = newFoo;
}
this.printAry = function() {
for( var i=0; i < ary.length; ++i ) {
console.log( ary[i] );
}
}
};
}(window.ns = window.ns || {}) );
ns.obj.print();
ns.obj.setFoo("newfoo!");
ns.obj.printAry();
ns.obj.print();
I looked at this:
JavaScript array of pointers like in C++
But I'd like to be able to use an element of ary on the LHS of an assignment and I don't think that example works in this situation.
WHY ON EARTH DO I WANT TO DO THIS?
A lot of comments so far have (rightfully) asked why I'd want to do this. I'm dealing with a proprietary API that involves an asynchronous object initialization mechanism. Basically I create an instance of an object and then pass it to this initializer to be able to actually use it. The initializer includes a field for an onSuccess handler to notify of successful initialization. My fully initialized object is passed as an argument into this success handler so that I can grab a reference to it.
I'm then free to initialize my next object. It looks kinda like this:
var a = new api.ApiObject();
var b = new api.ApiObject();
var c = new api.ApiObject();
var d = new api.ApiObject();
//omg this is ugly
api.initializeObject( {
objToInit: a,
onSuccess: function(args) {
a = args.obj;
api.initializeObject( {
objToInit: b,
onSuccess: function(args) {
b = args.obj;
api.initializeObject( {
objToInit: c,
onSuccess: function(args) {
c = args.obj;
api.initializeObject( {
objToInit: d,
onSuccess: function(args) {
d = args.obj;
}
} );
}
} );
}
} );
}
} );
a.doCoolStuff();
//and so on
This deeply nested mess just gets worse as I add more api.ApiObjects(). So what do I do to fix this? I can't change the API, but maybe a recursive function could help:
//maybe a recursive function could make this more concise?
function doInitialize( ary ) {
api.initializeObject( {
objToInit: ary[0];
onSuccess: function(args) {
//i'd like to assign this passed in reference to my local
//reference outside this function (var a, b, etc).
//An array of pointers would be useful here.
//how else can I get this assigned out, cuz this doesn't work...
ary[0] = args.obj;
if( ary.length > 1 ) {
ary.splice( 0, 1 );
doInitialize( ary );
}
}
}
}
doInitialize( [a,b,c,d] );
//this won't work because I don't have a reference to the fully initialized object
a.doCoolStuff();
So maybe the better question is: is there an established pattern to deal with asynchronous success chaining like this? I think I've seen other public JS frameworks (like dojo) use this sort of onSuccess chaining... how do I make this not ugly?
I might suggest that if your primary purpose for this is convenience as regards nesting of asynchronous callbacks, that you should consider a deferred/promise system.
I've written a couple of different promise libraries by hand.
jQuery comes with one built in (as do most "ajax libraries").
Here's what this might look like, in a better world:
doThingOne()
.then(doThingTwo)
.then(doThingThree)
.then(launch);
Assuming that doThingOne returns a promise.
A more familiar looking interface for people who use jQuery (or most other promise-using large libraries), might look like this:
var imageLoader = $.Deferred(),
loading = imageLoader.promise();
loading
.done(gallery.render.bind(gallery))
.done(gallery.show.bind(gallery));
var img = new Image(),
url = "...";
img.onload = function () { imageLoader.resolve(img); };
img.onerror = function () { imageLoader.reject("error message"); };
img.src = url;
Very basically, the Deferred above will hold two private arrays (one for "success", one for "failure"), and will extend an interface which allows the async part of the application to "succeed" or "fail", and will pass in whatever is chosen to be data/a callback/etc.
It also extends a promise method, which returns a promise object, containing subscription functions for the two private arrays. So you pass the promise object around to interested parties, and they subscribe callbacks to be iterated through, on success/failure of the async operation (and passed anything which is passed to the .resolve/.reject method of the operation).
This might seem like an inversion or extension of just adding a custom-event/listener/etc...
And it is.
The benefit of the abstraction is that the interface is cleaner.
Hiding this stuff inside of object interfaces, and just passing async promise-objects around can make your code look 100% synchronous:
var images = ImageLoader(),
gallery = ImageGallery(),
photo;
photo = images.load("//url.com/image.png"); // assuming `.load` returns a promise object
gallery.show(photo); // just a promise object, but internally,
//`.show` would subscribe a private method to the promise object
And doing things like having three separate async operations, which can arrive in any order, but must all be successful before advancing, then you can have something like this (again jQuery, but doing it by hand is possible, too).
$.when(promise_obj_1, promise_obj_2, promise_obj_3)
.done(nextPhase);
nextPhase, of course, being a callback which you anticipate to be fired if all three promises are successfully completed.
I'd be happy to provide implementation details for a barebones promise system, if you're like me, and don't like using different libraries without first understanding how each piece works on its own, and being able to replicate its functionality, without copying code.
The answer to the first part of your question is to use an object. You're thinking in C which doesn't have iteratable structs so C programmers reach for arrays. In JS objects are iteratable. So you should write it as:
ary = {
foo : 'foo',
bar : 'bar'
}
Or if we look at your second example:
var apis = {
a : new api.ApiObject(),
b : new api.ApiObject(),
c : new api.ApiObject(),
d : new api.ApiObject()
}
Now, as for the second part of your question. Your pseudo recursive code (pseudo because it's not really recursive in the stack sense since it's async) will now work with the apis object above. But you pass the keys instead of the object:
doInitialize( ['a','b','c','d'] );
Obviously, the bit above can be done dynamically by iterating through the apis object. Anyway, in the onSuccess part of the code you assign the result like this:
apis[ary[0]] = args.obj;
Oh, and obviously the objToInit should now be apis[ary[0]].
Now doing this should work as you expect:
apis.a.doCoolStuff();
Related
I'd like to 'proxy' (not sure if that's the term at all) a function inside a function object for easy calling.
Given the following code
function Soldier() {
this.el = $("<div></div>").addClass('soldier');
this.pos = this.el.position; // $(".soldier").position(), or so I thought
}
In the console:
s = new Soldier();
$("#gamemap").append(s.el); // Add the soldier to the game field
s.pos === s.el.position // this returns true
s.el.position() // Returns Object {top: 0, left: 0}
s.pos() // Returns 'undefined'
What am I doing wrong in this scenario and is there an easy way to achieve my goal (s.pos() to return the result of s.el.position()) ?
I thought about s.pos = function() { return s.el.position(); } but looks a bit ugly and not apropriate. Also I'd like to add more similar functions and the library will become quite big to even load.
When you're calling s.pos(), its this context is lost.
You can simulate this behavior using call():
s.pos.call(s); // same as s.pos()
s.pos.call(s.el); // same as s.el.position()
This code is actually ok:
s.pos = function() { return s.el.position(); }
An alternative is using bind():
s.pos = s.el.position.bind(el);
You can use the prototype, that way the functions will not be created separately for every object:
Soldier.prototype.pos = function(){ return this.el.position(); }
I'd recommend to use the prototype:
Soldier.prototype.pos = function() { return this.el.position(); };
Not ugly at all, and quite performant actually.
If you want to directly assign it in the constructor, you'll need to notice that the this context of a s.pos() invocation would be wrong. You therefore would need to bind it:
…
this.pos = this.el.position.bind(this.el);
It's because the context of execution for position method has changed. If you bind the method to work inside the element context it will work.
JS Fiddle
function Soldier() {
this.el = $("<div></div>").addClass('soldier');
this.pos = this.el.position.bind(this.el);
}
var s = new Soldier();
$("#gamemap").append(s.el);
console.log(s.pos());
I'm trying to learn javascript. As part of that effort, I am writing a basic minimax AI. I have the following methods:
Computer.prototype.expand = function(node) {
/* adds all state action pairs to the node.successors array */
};
Computer.prototype.getMove = function(boardAr) {
console.log("getMove");
var b2 = boardAr.slice();
var i;
var action;
this.root = new TNode(b2, this.mark);
this.root.AIPlayedLast = false;
this.expand(this.root);
this.root.successors.forEach(this.minVal);
action = maxNode(root.successors);
this.draw(action);
registerMove(action, this.mark);
};
Computer.prototype.minVal = function(node) {
if (node.isTerminal) {
return;
} else {
this.expand(node);
node.successors.forEach(maxVal);
node.utility = this.minNode(node.successors).utility;
}
};
When the getMove method is called the subsequent call to expand goes as expected. But, when expand is called from the minVal method I get: Uncaught TypeError: undefined is not a function. I'm utterly perplexed by this. Any help/suggestions would be greatly appreciated.
I think the reason is in this row:
this.root.successors.forEach(this.minVal);
You pass minVal as contextless reference, it will not be called in a context of your Computer instance (this)
Here is how you can improve it:
var self = this;
this.root.successors.forEach(function() {
self.minVal.apply(self,arguments);
})
The simplest and quickest solution is just to change
this.root.successors.forEach(this.minVal);
to
this.root.successors.forEach(this.minVal.bind(this))
This solves the problem in the same as the other answers, but in a way some might consider more compact.
Or, you can pass a "this" to the forEach function as the second argument, a somewhat under-utilized feature of forEach:
this.root.successors.forEach(this.minVal, this)
This feature is also available on other Array prototype methods that take functions, including map, filter, some, every (but not reduce and reduceRight).
ES6 arrow functions handle this differently, so you can do
this.root.successors(forEach(e => this.minVal(e)));
The forEach() method might be called for each of the successors. So, you pass the Computer::minVal method (this.minVal), but with the TNode(?) as this-pointer. Try:
var that = this;
this.root.successors.forEach(function(node) {
that.minVal(node));
});
My question is simple:
I'm passing a function to some other function to be call later (sample callback function), the question is when, why and what is the best practice to do it.
Sample:
I have the xxx() function, and I have to pass it, as I show you below in the window.onload event.
What is the best practice and why? There is any performance aspect or why should I choose to use call or bind to call this function
function xxx(text)
{
var div = document.createElement("div");
div.innerHTML = text + " - this: " + this.toString();
document.body.appendChild(div)
}
function callFunction(func)
{
func("callFunction");
}
function callUsingCall(func)
{
func.call(this, ["callUsingCall"]);
}
function callUsingBind(func)
{
func.call(this, ["callUsingCall"]);
}
window.onload = function(){
callFunction(xxx);
callUsingCall(xxx);
callUsingBind(xxx.bind(document));
}
Thank you,
Sebastian P.
I don't think there's any "best" practise.
You use call if the function you're calling cares what this is.
You use bind if you want to ensure that the function can only be called with the specified value of this.
[There's some overhead to both, i.e. at least one depth of function calls / scope]
Otherwise you just call the function.
Simples :)
The this object is the context of the function. It's like you make a machine that something for you, and the this object would be the place that the machine works in, like your house. You can move it as you like.
We have 4 ways setting this objects.
Calling the function that is not a method:
fn(someArguments)
This way the this object is set to null or probably the window object.
Calling the function as a method:
someObject.fn(someArguments)
In this case the this object will point to someObject and it's mutable.
Calling with call or apply methods of the function.
fn.call(anotherObject, someArguments)
someObject.call(anotherObject, someArguments)
someObject.apply(anotherObject, [someArguments])
In this case the this object will point to someObject here. You are forcing it to have another context, when calling it.
Binding a the function
var fn2 = fn.bind(anotherObject, someArguments)
This will create another function that is binded to that this object we gave it(anotherObject). No matter how you call it, the this object is going to be the same.
Use Cases
Now you can do some tricky stuff knowing this. The reason that why we have it here(I think it came first from C++) is that methods of an object need to access to their parent. The this object provides the access.
var coolObject = {
points : ['People are amazing'],
addPoint : function (p) { this.points.push(p) }
}
So if you do the following it won't work:
var addPoint = coolObject.addPoint;
addPoint('This will result in an error');
The error will be thrown because the this object is not our coolObject anymore and doesn't have the points property. So at times like this, you can something like this:
var addPoint = coolObject.addPoint;
addPoint.call({points : []}, 'This is pointless');
This is pointless, but the function will work, even the this object is not what its supposed to be.
var anotherCoolObject = {
points : ['Im a thief!'],
addPoint : coolObject.addPoint
}
anotherCoolObject.addPoint('THIS IS CALL STEALING');
Still the function will work if you call it like that, since the this object will point to anotherCoolObject which has the points property.
The most popular use case I've seen is slicing the arguments object:
function returnHalf() {
return [].slice.call(arguments, 0, arguments.length / 2);
}
returnHalf('Half', 'is', 'not', 'awesome');
// >> [Half', 'is']
So you see, arguments object is not an instanceof array. If we do arguments.slice(...) then you're gonna be killed by the compiler. But here we use the array's method on arguments object, since it's array like.
Sometimes you don't want your function context to be changed or you wanna add your own arguments, you use bind.
For example when you add a listener for an event with jquery, when jquery calls your function, the this object will be the element. But sometimes you wanna do tricky stuff and change it:
var myElement = {
init : function () {
$(this.element).click(this.listener.bind(this));
},
view : "<li>${Name}</li>",
name : 'ed',
element : $('#myelement'),
listener : function () {
this.element.append($.tmpl( this.view, this ));
}
}
myElement.init();
So here, you bind it to the myElement, so you can have access to the object properties to render the view. Another examples would be the following:
for (var i = 0; i < 10; i++) {
setTimeout(function () {console.log(i)}, 10)
}
// All of them will be 10.
for (var i = 0; i < 10; i++) {
setTimeout((function () {console.log(this.i)}).bind({ i : i }, 10)
}
If you have put an asynchronous function call in a loop, by the time the callback is called, the loop is finished, and the counter have reached the end, you can use bind to cleanly bind the current counter to your callback.
Another good use case of it, that I use a lot is when passing my functions with arguments to async module, without creating closures.
async.parallel({
writeFile : function (cb) {
fs.writeFile('lolz.txt', someData, cb);
},
writeFile2 : function (cb) {
fs.writeFile('lolz2.txt', someData, cb);
}
}, function (err){
console.log('finished')
});
async.parallel({
writeFile : fs.writeFile.bind(fs, 'lolz.txt', someData),
writeFile2 : fs.writeFile.bind(fs, 'lol2z.txt', someData),
}, function (err){
console.log('finished')
});
These two implementations are identical.
Performance
Just check these out:
http://jsperf.com/bind-vs-call2
http://jsperf.com/js-bind-vs-closure/2
http://jsperf.com/call-vs-closure-to-pass-scope/10
bind has a big performance overhead comparing to other types of calling, but make sure you don't sacrifice performance with maintainability with pre-mature optimizations.
Also you can have a look at this article.
Im wondering if someone might be able to help me with something that i think it fairly straight forward:
Essentially i want to extend the prototypes of all datatypes (including intrinsic types), to allow some kind of custom functions, consider:
var x = "some string";
var y = 101;
x = "some other value";
y++;
x.onChange();
y.onChange();
This is the basic idea im after, but really what i want is to actually have the onChange (in this example) to be different so a new function for the actual variable (rather than a stardard prototype extension), ie:
x.onChange = function() {
alert("x.onChange");
}
y.onChange = function() {
alert("y.onChange");
}
This doesnt seem to work but i must be missing something quite simple no? I mean surely i can extend all object and types and add on new functions... no?
Any help would be greatly appreciated!
I might be tempted to approach this not by trying to add methods to existing types, but to create an object that can wrap a primative type. I would call this "observing" a value, and might implement it something like this:
function observable(v){
this.value = v;
this.valueChangedCallback = null;
this.setValue = function(v){
if(this.value != v){
this.value = v;
this.raiseChangedEvent(v);
}
};
this.getValue = function(){
return this.value;
};
this.onChange = function(callback){
this.valueChangedCallback = callback;
};
this.raiseChangedEvent = function(v){
if(this.valueChangedCallback){
this.valueChangedCallback(v);
}
};
}
This can then be used to observe changes in any value (so long as that value is then changed only by methods on the observable class - a small detraction IMO).
Something like this would work with the above code:
var obs = new observable(123);
obs.onChange(function(v){
alert("value changed to: " + v);
});
// the onChange callback would be called after something like obs.setValue(456);
Live example here --> http://jsfiddle.net/MeAhz/
Extend the object prototype:
Object.prototype.foo = function() { alert('hello world'); };
var a = 1;
a.foo();
The standard DEPRECATED way : Object.observe()
The Object.observe() method was used for asynchronously observing the
changes to an object. It provided a stream of changes in the order in
which they occur. However, this API has been deprecated and removed
from browsers.
let myObservdObject = Object.observe( { a : 'foo' }, e=>console.log('change!', e) );
myObservdObject.a = 'bee';
// callback gets executed
// and prints 'changed! in console, with the change event data
But proxies arrived to the Standard (ES6) an Object.Observe became deprecated and, in consecuence, unsupported by the browsers.
Proxies are the new way to observe... but implement a generic observer requires a more complex implementation, in comparsion with the way Object.observe used to provide us.
Observe value changes with third party libraries
You can find arround many implementations based in proxies.
Some of them implement the Observer pattern, wich forces you to set or get the values using specific methods :
Observe :
https://www.npmjs.com/package/observe
// define your object
var object = {a:'bee'};
// generate an observer
var observer = observe(object);
// declare the onchange event handler
observer.on( 'change', change=> console.log(change) );
// ready!
// set the value of 'a' and see how the callback is executed...
observer.set('a', 'foo')
// get the new value
observer.get('a') // returns 'foo'
Other libraries instead, let you interact with your variables using a more natural way:
WatchJS :
https://github.com/melanke/Watch.JS/
// define your object
var object = {a:'bee'};
// generate an observer and declare de hadler
watch(object , "a" , e=>console.log(e) );
// ready!
// set the value of 'a' and see how the callback is executed...
object.a = 'foo';
// get the new value
object.a // returns 'foo'
My own apprach : deep-observer
All the implementaions have their own caveats, and none of them was working for my purposes, so i had to implement my own approach.
The result is a highly customizable Observer method with a really small footprint ( <100 bytes gziped)
Deep-observer : https://www.npmjs.com/package/deep-observer
// create an observable object
const myObserved = new Observer( { a : 'bee' } , e=>console.log(e) ),
// perform a modification
myObserved.a = 'foo';
// console : { action:'update', oldValue:'bee', object:{a:'foo'}, name:'a' }
myObserved.a; // returns 'foo'
I'm trying to create a simple, small and basic javascript framework just for learning purposes.
But the thing is that i'm allready stuck at the very basics.
I'm trying to do something like this:
$('testdiv').testFunction();
And the code i've written for that:
var elementID;
var smallFramework = {
$:function(id) {
this.elementID = id;
},
testFunction:function() {
alert(this.elementID);
}
};
window.$ = smallFramework.$;
But in return I get:
$('testdiv) is undefined
Can anyone help me with this small and hopefully easy question?
To get the behavior you're expecting, you need the $ function to return an object with a method named testFunction.
Try:
var smallFramework = // an object for namespacing
{
$:function(id) // the core function - returns an object wrapping the id
{
return { // return an object literal
elementID: id, // holding the id passed in
testFunction: function() // and a simple method
{
alert(this.elementID);
}
};
}
};
Of course, there are many other ways to achieve the behavior you desire.
If you're trying to add methods to an HTML element you could do something along these lines.
$ = function( elementId ) {
var element = document.getElementById( elementId );
element.testFunction = function(){
alert( this.id );
return this; // for chaining
}
return element;
}
$('test').testFunction();
Try
smallFramework.$('testdiv');
instead. According to the code you posted, that's where your $ function ended up.
Or alternatively, it looks like you're trying to replicate something like jQuery. You might want to try something like this.
var $ = smallFramework = (function () {
var f =
{
find:function(id) {
f.elementID = id;
return f; //every function should return f, for chaining to work
},
testFunction:function() {
alert(f.elementID);
return f;
}
}
return f.find //the find function will be assigned to $.
//and also assigned to smallFramework.
//the find function returns f, so you get access to testFunction via chaining
// like $("blah").testFunction()
})() //note this function gets called immediately.
this code may look confusing to someone new to JavaScript because it depends heavily on the concept of closures. I suggest that if this doesn't make sense, spend some time at Douglas Crockford's JavaScript website. This is important because the code above will bite if you happen to use this in the find function because this won't be bound to f, as you may expect it to be when you use it from $ or smallFramework.