Using call to pass context - javascript

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.

Related

Run a function when deep property is set

I have an object like
const obj = { field1: obj1, field2: obj2 }
and now I'd like to run a function when anything in obj was changed:
function objChanged() { ... }
// decorate obj somehow ...
obj.field3 = data; // objChanged should be called (Proxy can see it)
obj.field1.val = data; //objChanged should be called (Proxy can't see it?)
AFAIK there is a MutationObserver which works only for DOM and Proxy which intercepts only own properties, right?
I do not own obj1 so I can not change it. Is there a way to achieve this functionality?
Following the piece of code will listen to object property you can iterate over object properties to listen all. I am curious, what are you trying to achieve?
const dog = { bark: true };
function Observer(o, property) {
var _this = this;
this.observers = [];
this.Observe = function (notifyCallback) {
_this.observers.push(notifyCallback);
};
Object.defineProperty(o, property, {
set: function (val) {
_this.value = val;
for (var i = 0; i < _this.observers.length; i++) {
_this.observers[i](val);
}
},
get: function () {
return _this.value;
},
});
}
const observer = new Observer(dog, "bark");
observer.Observe(function (value) {
l("Barked");
});
dog.bark = true;
dog.bark = true;
dog.bark = true;
dog.bark = true;
Orgil's answer works only with a single property that needs to be known and encoded. I wanted a solution which works for all properties, including later added. Inspired by his idea to create an observing object, I created a dynamic Proxy that adds another Proxies when needed.
In the following code dog1 serves as proxy: setting its properties modifies the original dog object and logs the assigned value to console.
function AssignProxy(o, fn, path) {
var tree = {};
if(!path) path = "obj";
return new Proxy(o, {
get: (_, prop) => {
if(typeof o[prop] != "object") return o[prop];
if(tree[prop] === undefined) tree[prop] = AssignProxy(o[prop], fn, `${path}.${prop}`);
return tree[prop];
},
set: (_, prop, val) => fn(o[prop] = val, prop, o, path) || 1
});
}
/****** TEST *******/
const dog = {
sounds: {},
name: "Spike"
};
let callback = (val, prop, o, path) => console.log(`assigning ${path}.${prop} to ${val}`)
const dog1 = AssignProxy(dog, callback, "dog1");
dog1.name = "Tyke"; // overwrite property
dog1.age = 4; // create a property
dog1.sounds.howl = "hoooooowl"; // create a deep property
dog1.sounds.howl = {text: "hoowl", pitch: 5000}; // overwrite the deep property
var howl = dog1.sounds.howl; // access by reference
howl.pitch = 6000; // overwrite later added property
console.log(dog); // verify the original object

How to override Function.length to return the length of an array, in strict mode

I am looking for a way to override the .length property of an Object in JavaScript.
I currently have a wrapper on parent.properties.objects array
(parent is used to for the code to be more readable in context)
This is the basic structure:
(parent variable is defined in namespace and intialized)
var parent = function () {
this.properties = {
objects: [];
};
};
wrapper
(function () {
"use strict";
objects = function () {
If no argument is passed, assume get
if (arguments.length === 0) {
var _objects = parent.properties.objects;
return _objects;
modify or filter objects
} else if (arguments.length > 0) {
...
}
};
this creates a object.prototype (not [prototype]) variable and adds the method length()
objects.prototype.length = function () {
var length = parent.properties.objects.length;
return length;
}
Error
objects.prototype.__proto__.length = function () {
var length = parent.properties.objects.length;
return length;
}
parent.objects = objects;
})();
Assuming I've understood your question correctly, the following code might help you:
function MyObject() {
this.myActualData = [];
}
Object.defineProperty(MyObject.prototype, 'length', {get: function() {
return this.myActualData.length;
}});
And here's an example of it in use:
var x = new MyObject();
x.myActualData.push("Hello");
x.myActualData.push("World");
x.length; // is 2
Note: this will only work on ecmascript 5 and above browsers.

Javascript, value types as reference

I've some scenarios where i need to pass value type as reference without changed the processing function.
Example Numeric Types (var limit)
var limit = 0; // Need to be the reference type
var multiCallback = new MultiCallback(limit, function(){});
for (element in myObject)
{
limit++;
element.DoSomething(multiCallback.callback);
}
function MultiCallback(limit, func)
{
var calls = 0;
function callback()
{
if (++calls == limit)
{
func();
}
}
return {
callback : callback
}
}
Examble Function Types
var resizeCallback = function(){};
$(window).resize(resizeCallback);
function showPage()
{
resizeCallback = resizePage();
}
function showLoader()
{
resizeCallback = resizeLoader();
}
is there a solution
Changing the value of a variable will never update the previous value of the variable.
For functions, you can do something like this:
var current = function() { ... };
function resizeCallback() {
return current.apply(this, arguments);
}
// Updating current will work:
current = function() { ... something ... };
For other values (primitives and objects), the closest thing is to pass an object:
var limit = {value: 0};
function MultiCallback(limit, func) {
....
if (limit.value == ++calls) ...
}
// Changing limit:
limit.value = 1;
There is no pass by reference in javascript (assigning arguments is not visible to the caller). What you are doing in your function example is modifying a global variable.
You can wrap it with an object and mutations of that object are visible to the caller:
var limit = {
value: 0
};

How do I compute a variable in JavaScript if and only if it is used?

This is what I'm doing right now.
var foo = function() {
var x = someComplicatedComputationThatMayTakeMoreTime();
this.foo = function() { return x; };
return x;
}
It works but only if foo is called as a function like so
foo();
But what if I want to call it as a normal variable with a value? I could modify the code to be
var foo = function() {
var x = someComplicatedComputationThatMayTakeMoreTime();
this.foo = x;
return x;
}
That would allow me to only call it once as a function and after that as a regular variable. But it's still not what I want. Plus it gets complicated if it accidentally gets called as a function again, returning an error.
Is this even possible in JavaScript?
BTW, this is for a Chrome/Firefox extension, so IE compatibility does not matter.
Ended up using toString because getters don't allow me to redefine the whole attribute, a function must be associated with it. And toString has cleaner syntax.
How about using toString?
var foo = function() {
function someComplicatedComputationThatMayTakeMoreTime() {
//your calculations
}
return {
toString: function() {
return someComplicatedComputationThatMayTakeMoreTime();
}
}
}
More about Object-to-Primitive Conversions in JavaScript
EDIT based on comment. Use a singleton (I think it's called):
myObject.prop = (function(){
function someComplicatedComputationThatMayTakeMoreTime() {
//your calculations
}
return {
toString: function() {
return someComplicatedComputationThatMayTakeMoreTime();
}
}
})()
If only Internet Explorer didn't exist, you could use getters and setters as described by John Resig in this blog article:
John Resig: JavaScript Getters and Setters
... They allow you to bind special functions to an object that look like normal object properties, but actually execute hidden functions instead.
Using a function is your best option for now, however the new JavaScript standard (ECMAScript 5th Ed.) which is being implemented now by all major browser vendors, gives you a method to create accessor properties, where you can define a property with a get and set functions that will be internally called, without worrying to treat this properties as functions, e.g.:
var obj = {};
Object.defineProperty(obj, 'foo', {
get: function () { // getter logic
return 'foo!';
},
set: function (value) {
// setter logic
}
});
obj.foo; // "foo!", no function call
This new standard will take some time to be implemented for all browsers, (the IE9 preview version really disappointed me), and I wouldn't recommend you to use it for production, unless you have total control on the environment where your application will be used.
What I think you want is a lazily instantiated variable, which can be implemented like this.
var myProperty = null;
function getMyProperty() {
return (myProperty = myProperty || builder());
}
This is not practical on the web because IE does not support it, but you can look at
https://developer.mozilla.org/en/defineGetter for examples how to do this.
There are a couple ways to do it, here is one example:
var data = {};
data.__defineGetter__("prop",
(function () {
var value = null;
return function () {
if (null == value) {
value = getYourValueHere();
}
return value;
};
})());
and now you can use it like:
var a = data.prop;
var b = data.prop;
I would recommend a variation on ChaosPandion's answer, but with a closure.
var myProperty = (function () {
var innerProperty = null;
return function() {
return (innerProperty = innerProperty || someComplicatedComputationThatMayTakeMoreTime());
};
})();
and then use myProperty() every time you need to access the variable.
You could define a JavaScript getter. From the Apple JavaScript Coding Guidelines:
myObject.__defineGetter__( "myGetter", function() { return this.myVariable; } );
var someVariable = myObject.myGetter;
See John Resig's post, JavaScript Getters and Setters, and the Defining Getters and Setters page at the Mozilla Developer Centre for more information.
I would use explicit lazy evaluation. Here's my implementation of it based on Scheme's take:
var delay, lazy, force, promise, promiseForced, promiseRunning;
(function () {
var getValue = function () {
return this.value;
};
var RUNNING = {};
var DelayThunk = function (nullaryFunc) {
this.value = nullaryFunc;
};
DelayThunk.prototype.toString = function () {
return "[object Promise]";
};
DelayThunk.prototype.force = function () {
if (promiseRunning (this)) {
throw new Error ("Circular forcing of a promise.");
}
var nullaryFunc = this.value;
this.value = RUNNING;
this.value = nullaryFunc ();
this.force = getValue;
return this.value;
};
var LazyThunk = function (nullaryFunc) {
DelayThunk.call (this, nullaryFunc);
};
LazyThunk.prototype = new DelayThunk (null);
LazyThunk.prototype.constructor = LazyThunk;
LazyThunk.prototype.force = function () {
var result = DelayThunk.prototype.force.call (this);
while (result instanceof LazyThunk) {
result = DelayThunk.prototype.force.call (result);
}
return force (result);
};
delay = function (nullaryFunc) {
return new DelayThunk (nullaryFunc);
};
lazy = function (nullaryFunc) {
return new LazyThunk (nullaryFunc);
};
force = function (expr) {
if (promise (expr)) {
return expr.force ();
}
return expr;
};
promise = function (expr) {
return expr instanceof DelayThunk;
};
promiseForced = function (expr) {
return expr.force === getValue || !promise (expr);
};
promiseRunning = function (expr) {
return expr.value === RUNNING || !promise (expr);
};
}) ();
Example Syntax:
var x = lazy (function () { return expression; });
var y = force (x);
var z = delay (function () { return expression; });
var w = force (z);
Note values are stored once evaluated, so repeated forcing will not do extra computations.
Example usage:
function makeThunk (x, y, z) {
return lazy (function () {
// lots of work done here
});
}
var thunk = makeThunk (arg1, arg2, arg3);
if (condition) {
output (force (thunk));
output (force (thunk)); // no extra work done; no extra side effects either
}
You can use the javascript Proxy class for creating such functionality.
var object = {};
var handler = {
resolvers: {},
get ( target, property, proxy ) {
if ( ! target.hasOwnProperty( property ) && this.resolvers.hasOwnProperty( property ) ) {
// execute the getter for the property;
target[ property ] = this.resolvers[ property ]();
}
return target[ property ];
},
set ( target, property, value, receiver ) {
// if the value is function set as a resolver
if ( typeof value === 'function' ) {
this.resolvers[property] = value;
// otherwise set value to target
} else {
target.property = value;
}
},
has ( target, property, receiver ) {
//true when proxy handler has either a resolver or target has a value;
return this.resolvers.hasOwnProperty( property ) || target.hasOwnProperty( property );
}
};
var lazyObject = new Proxy( object, handler );
Now you can use it like this:
'exampleField' in lazyObject; //returns false
lazyObject.exampleField = function(){ return 'my value' }; // add a resolver function
'exampleField' in lazyObject; //returns true
lazyObject.exampleField; //executes your resolver function and returns 'my value'
This example is to demonstrate the working. You can change after your needs.
Here is a fiddle with a demonstration

What does 'this' refer to in this function?

The entire code snipped is:
var observer = {
addSubscriber: function(callback) {
this.subscribers[this.subscribers.length] = callback;
},
removeSubscriber: function(callback) {
for (var i = 0; i < this.subscribers.length; i++) {
if (this.subscribers[i] === callback) {
delete(this.subscribers[i]);
}
}
},
publish: function(what) {
for (var i = 0; i < this.subscribers.length; i++) {
if (typeof this.subscribers[i] === 'function') {
this.subscribers[i](what);
}
}
},
make: function(o) { // turns an object into a publisher
for(var i in this) {
o[i] = this[i];
o.subscribers = [];
}
}
};
It depends on how it is called. I see it is part of an object literal called observer.
observer.make(o) would mean this == observer.
observer.make.call(otherObj, o) would mean this == otherObj.
new observer.make(o) would make a new object to be this
So it would do something like this.
var model = {
name: 'bike',
id: 4,
gears: 7
};
observer.make(model);
//now model has methods from observer
model.addSubscriber(someListener);
model.publish('gearsChanged');
"this" refers to "observer" assuming that is the object in which it was invoked (and in 99% of cases it is);
so: observer.addSubscriber
in the method addSubscriber, "this" will refer to "observer".
When you have objects within objects (or nodes) it can be confusing to resolve "this":
observer = {
node: $("myDiv"),
callIt: function(){
// note "this.node" - node belongs to observer
this.node.onclick = function(){
// "this" now refers to the "node" object
// onclick was invoked by node
}
}
}
this, is how you refere at the scope of a function. it's the function itsel.!!! this example in prototypejs framework is quite handy.
http://api.prototypejs.org/language/function/prototype/bind/
for example if you the following code.
function foo(){
//here this is foo
var x = {}; //object
var me = this;
var img = new Image();
img.load = function(){
//but here this is img.load.. is the scope of the function =)
// if you want to use the x object you have to assing this FOO a global variable is why you use me = this;
me //is foo :P
}
}

Categories

Resources