As you can see in the example below, I'm trying to wrap every function defined in obj so it gets to be able to be called with anotherObj as this, and then add that wrapper as a property to anotherObj.
Note: isFunction
var isFunction = function(x) {
return typeof(x) == "function";
}
for (prop in obj) {
if (isFunction(obj[prop])) {
var fn = obj[prop];
anotherObj[prop] = function() {
fn.call(anotherObj);
};
}
}
For some reason weird to me, every property now stored in anotherObj, references only the last property of the iteration.
However, if I use an external function like below, the references are ok.
var contextFn = function(fn, context){
return function() {
fn.call(context);
};
};
...
for (prop in obj) {
...
anotherObj[prop] = contextFn(fn, anotherObj);
...
}
Why is this happening? Is there something obvious I'm missing?
The (not-so-)obvious thing you're missing is that in your first loop, the variable "fn" is not local to the statement block it's declared in. Thus, it's shared by all the functions you're creating.
Your solution is in fact the correct one. By using a separate function, you're making copies of the values to be used in creating the actual wrapper functions, so that each wrapper will have it's own private copy of "fn".
Related
I am fairly new to Javascript and stomped across this while writing some frontend code. I reproduced this here:
var obj1 = {
func1(val) {
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(val);
}
}
}
this.obj2.func2();
}
}
obj1.func1(10);
obj1.func1(20);
Why is the value of the val not getting changed inside the func2() method? It seems that only the value is getting copied to the object obj2 without taking the reference into consideration.
But it works perfectly when I change the code to this:
var obj1 = {
func1(val) {
this.val = val;
var that = this;
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(that.val)
}
}
}
this.obj2.func2();
}
}
obj1.func1(10);
obj1.func1(20);
Can anyone tell the reason behind the difference? Is it something to do with the scope?
In the first snippet, when you do
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(val);
}
}
}
The obj2 method that has been assigned, which gets assigned once and never again, closes over the val parameter in its scope when it was assigned - that is, when obj1.func1(10) was run.
In the second snippet, you assign to the val property of the instance every time func1 runs:
func1(val) {
this.val = val;
so by the time you log that.val later, it's always the parameter you just passed.
On the first case, you have:
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(val);
}
}
}
So you make func2 always console.log the value it was originally created with. The second time it's called it will just call func2 with original val because functions retain access to the original scope they were declared (this is called closure).
The second time, when you do
this.val = val;
var that = this;
You're going to console.log a dynamic reference to this, so it's going to be value you passed because the this is going to be different on this scop
as far as I can understand the "This" keyword in javascript always points to the app itself or a global object. What you just did is setting a reference to the variable you are trying to use which is how I remedy this behaviour mistimes. I hope this helped at least?
have a look at this post. understanding the this keyword
cheers.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I am using Typescript for an Angular 2 project. I notice that when we use the keyword this inside a labmda expression vs a function, this refers to different things.
For example, let's say I have an Angular component like the following.
export class MyComponet {
isActive = true;
names = [ "john", "jeff", "jared" ];
doSomethingWithLambda() {
names.forEach( (value, index) => {
if(this.isActive) { //this.isActive refers to MyComponent.isActive
//do something...
}
});
}
doSomethingWithFunction() {
names.forEach( function(value, index) {
if(this.isActive) { //this.isActive is undefined, since this refers to the function
//do something
}
});
}
doSomethingWithFunction2() {
let isActive = this.isActive;
names.forEach( function(value, index) {
if(isActive) { //if we change isActive will this also change MyComponent.isActive?
//do something
}
});
}
}
What is really happening here (behind the scene, so to speak)? What's the magic behind this inside a lambda that makes it able to "correctly" refer to the outer class' fields? I understand this inside a function will refer to the function itself.
Also, I have a doSomethingWithFunction2 method that will reference MyComponent.isActive into a local variable. If I change that local variable, that should be like changing the one it references, right? (regardless of it being a "primitive" like integer/number or an "object" like JSON { })
The fat-arrow function syntax is shorthand for:
function () { }.bind(this);
bind is a Javascript ES5 method equivalent to this:
Function.prototype.bind = function bind(context) {
var func = this;
return function () {
return func.apply(context, arguments);
};
}
In regards to
Also, I have a doSomethingWithFunction2 method that will reference MyComponent.isActive into a local variable. If I change that local variable, that should be like changing the one it references, right? (regardless of it being a "primitive" like integer/number or an "object" like JSON { })
In Javascript, variables are like pointers and except for some limited cases (primitives and copy-on-write objects) will change the referenced value when mutated. Reassigning will not change the original value, e.g. isActive = false; but this.isActive = false would in fact re-assign the variable isActive on this which is now hopefully correctly assigned.
This has to do with how lambda function are implement in TS. this in arrow function is lexically inferred so it more in line with below code
function Person() {
var self = this; // Some choose that instead of self.
// Choose one and be consistent.
self.age = 0;
setInterval(function growUp() {
// The callback refers to the self variable of which
// the value is the expected object.
self.age++;
}, 1000);
}
So inside the lambda function it is not actually this but a context closer self. This may not be actual implementation but much closer to give you understanding of what is happening.
Now when you are outside the my impotent this refers to global var which would be window
The lambda function is similar to javascripts bind function.
Protip see your transpiled JS how your lambda function is transforming.
I am looking for getters and setters functionality but cannot rely on __defineGetter__ and __defineSetter__ yet. So how does one maintain a function variable's value between function calls?
I tried the obvious, but myvar is always undefined at the start of the function:
FNS.itemCache = function(val) {
var myvar;
if( !$.isArray(myvar)
myvar = [];
if( val === undefined)
return myvar;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
};
I could always put another FNS._itemCache = [] just above the function, but is there a way to encapsulate the values in the function between calls?
An alternative way to set a private variable is by wrapping the function definition in an anonymous function:
(function(){
var myvar;
FNS.itemCache = function(val) {
if( !$.isArray(myvar))
myvar = [];
if( typeof val == "undefined")
return myvar;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
};
})();
This way, myvar is defined in the scope of FNS.itemCache. Because of the anonymous function wrapper, the variable cannot be modified from elsewhere.
You can store the value on the function by using arguments.callee as a reference to the current function:
FNS.itemCache = function(val) {
if( !$.isArray(arguments.callee._val)
arguments.callee._val = [];
if(val === undefined)
return arguments.callee._val;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
};
However, this will break if the function is stored in a prototype and thus used by more than one object. In this case you have to use a member variable (e.g. this._val).
this is a standard pattern for creating your static variable and for creating private members of an object
FNS.itemCache = (function() {
var myvar;
if( !$.isArray(myvar)
myvar = [];
return function(val) {
if( val === undefined)
return myvar;
.. // Other stuff that copies the array elements from one to another without
// recreating the array itself.
}
})();
I found one interesting project on github which deals with pdf rendering in the browser.
I tried to read the code because I'm interested in this topic but I realized that my javascript knowledge is poor (insuficient).
There are constructs like:
var Obj = (function() {
function constructor(type, value) {
this.type = type;
this.value = value;
}
constructor.prototype = {
};
var types = [
"Bool", "Int", "Real", "String", "Name", "Null",
"Array", "Dict", "Stream", "Ref",
"Cmd", "Error", "EOF", "None"
];
for (var i = 0; i < types.length; ++i) {
var typeName = types[i];
constructor[typeName] = i;
constructor.prototype["is" + typeName] =
(function (value) {
return this.type == i &&
(typeof value == "undefined" || value == this.value);
});
}
constructor.prototype.lookup = function(key) {
function lookup(key) {
if (!(this.value.contains(key)))
return Obj.nullObj;
return this.value.get(key);
}
}
Object.freeze(constructor.trueObj = new constructor(constructor.Bool, true));
Object.freeze(constructor.falseObj = new constructor(constructor.Bool, false));
Object.freeze(constructor.nullObj = new constructor(constructor.Null));
Object.freeze(constructor.errorObj = new constructor(constructor.Error));
Object.freeze(constructor.prototype);
Object.freeze(constructor);
return constructor;
})();
You can see more of them in the link above.
Could you please advise me some resources which to study to be able to understand the code in the project with ease and even better to contribute later to the project?
Working outside in, the first big concept here are anonymous funcitons.
var Obj = (function() { /* do work */})();
Simply, put, we are making an anonymous function, and then immediately execturing it,
and assigning the return from the anonymous function to an variable named Obj.
Why would anyone want to do it?
In this case, it is used to create a private scope. Local variables in javascript are
scoped to the function where they are defined. For example:
function test() {
var a = 10;
}
// a is not defined here.
In the last example, a really only exists inside the scope of the function that
defined it. Javascript is a little tricky this regard because by omitting the var
keyword, you can define a global variable.
So in the example you've given, they are using this anonymous function to build a
scope for some variables that will be used, but will ultimately want to be thrown
away as soon as the function is finished executing.
Next:
var Obj = (function() {
function constructor(type, value) {
this.type = type;
this.value = value;
}
// SNIP
})();
This creates a new function called constructor. Its important to note that javascript functions
are first-class objects, which means they work a lot like any other object, and can be assigned
to a variable. This function is scoped to the anonymous function. So trying to get constructor out
side of the scope of its function, doesn't work. For example
var Obj = (function() {
function constructor(type, value) {
this.type = type;
this.value = value;
}
// SNIP
})();
typeof(constructor) // <= undefined
So far, if you were to execute the snippits so far, then Obj would have been undefined. Now
let's skip ahead a bit to end, and look at the return.
var Obj = (function() {
function constructor(type, value) {
this.type = type;
this.value = value;
}
// SNIP
return constructor;
})();
So when the anonymous function gets invoked, it returns the constructor. This function that gets
passed back is assigned to Obj. This hands back the constructor, out of the local scope of the
function, and assigns to the variable. You would then be able to invoke it
var Obj = (function() {
function constructor(type, value) {
this.type = type;
this.value = value;
}
// SNIP
return constructor;
})();
var o1 = new Obj("t", "v");
o1.type // <= "t"
o1.value // <= "v"
Next we've got an interesting line
var Obj = (function() {
function constructor(type, value) {
this.type = type;
this.value = value;
}
constructor.prototype = { };
// SNIP
return constructor;
})();
This sets the prototype for the constructor to an empty object. Explaining the details of prototypes is
a bit of the scope of this post, but an over-simplication is that a prototype defines the instance methods
that are available to an object that is created by a constructor. A single 'prototype' is shared between
and will be used to define the methods that will be available to the objects that are constructed by
calling new Obj().
Next we have a locally defined array
var types = [
"Bool", "Int", "Real", "String", "Name", "Null",
"Array", "Dict", "Stream", "Ref",
"Cmd", "Error", "EOF", "None"
];
Remember because we are inside of a function, this variable is bound within the outer anonymous function's scope.
Next we loop through that array, and set up some stuff.
for (var i = 0; i < types.length; ++i) {
var typeName = types[i];
constructor[typeName] = i;
constructor.prototype["is" + typeName] =
(function (value) {
return this.type == i &&
(typeof value == "undefined" || value == this.value);
});
}
Two things interesting happen here. First, it sets a 'static' property off of the constructor, and then
creates a new function on the constructor's prototype. This function is called "is" + typeName. So we should
generate a bunch of instance methods named stuff like: "isBool", "isInt", "isReal", and so on.
constructor.prototype.lookup = function(key) {
function lookup(key) {
if (!(this.value.contains(key)))
return Obj.nullObj;
return this.value.get(key);
}
}
Next we define another instance method called lookup and does some work.
Lastly we create some static properties off of our constructor, and freeze them (so they can't be changed or extended)
Once its all said and done, Obj, should point to a constructor function, and we should be able to say things like:
var myType = new Obj("MyType",undefined);
myType.isBool(undefined) //instance method
Obj.Bool // static property
Anyway, I hope that helped a little bit explaining a few of the concepts that were being used. The big take-away should
be that a function can be used to control scope, and that functions are First-class functions, and can be handed around
like variables. You can also reference a property off a object using dot notation (obj.property) or bracket notation
(obj["property"]).
There are a bunch of more things to learn, and all of the book suggestions are solid in this thread. If it hasn't been mentioned I
would also recommend Eloquent JavaSript by Haverbeke.
Douglas Crockford's book JavaScript: The Good Parts is a great place to gain an appreciation of the power in JavaScript, while steering you away from the ugly (or downright dangerous) parts. His website also has a collection of interesting articles about the language. I recommend both.
Maybe some of these links will help you out:
https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model,
https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript,
https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Objects,
https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited,
I can refer some links
Can I name a javascript function and execute it immediately?
http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
I hope you can learn with them
I find the blogs by Douglas Crockford(http://www.crockford.com/), John Resig(http://ejohn.org/blog/) useful for intermediate to advanced concepts. Looking at other people's code(just like what you are doing) can also be helpful. At the end of the day though nothing beats actually trying out the concept and for that the trusty Firebug console is still the best.
Does anyone have any example implementation of making individual object props readOnly/non-configurable? I mean primitive data types. Have tried using ES5 Object API, but hitting a brick wall.
I can't show code, because it's still at that "messy" phase, but basically I'm iterating through an outside object which, itself, holds numeruos objects. Those objects each hold various primitive data types. I have made the outer objects readOnly, non-config, etc, but can't figure out how to do likewise for individual props, the innermost props.
So, if outer.inner.prop === "Hello", I want to make that value readOnly.
Thanks!
UPDATE
I just figured this out, it was all in the for loop I was using to iterate over props. Now I've actually get data descriptors for the props, even the primitive ones. :) Thanks all!
You have to iterate through the inner object, since there is no way to deep-freeze an object using standard ES5 methods.
function deepFreeze(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepFreeze(obj[key]);
});
Object.freeze(obj);
}
Edit:
Also works for defineProperty if you don't want to freeze:
function deepWriteProtect(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepWriteProtect(obj[key]);
Object.defineProperty(obj, key, { writable: false });
});
}
I'm not 100% sure I understand your question correctly, but from what I gather you are asking for private variables. If so, that can be easily achieved using closures.
function myClass(){
var mySecretProperty = 10;
this.getMySecretProperty = function(){
return mySecretProperty;
}
this.changeMySecretProperty = function(s){
// whatever logic you need for a setter method
mySecretProperty = s;
}
}
var myObj = new MyClass();
myObj.changeMySecretProperty(120);
myObj.getMySecretProperty(); // will return 120
myObj.mySecretProperty // will return undefined
Would the following (ES5) example help? It creates an empty constructor, with a getter for property a (and no setter, so de facto a is read only):
var Obj = function(){};
Obj.prototype = {
get a() {return 5;}
}
var x = new Obj;
alert(x.a); //=> 5
x.a = 6; //=> TypeError: setting a property that has only a getter
Not using ES5 you can do
var Obj = function(){
var a = 5;
if (!Obj.prototype.getA) {
Obj.prototype.getA = {
toString: function() {
return a;
}
};
}
}
var y = new Obj;
alert(y.getA); //=> 5
But that is not 100% failsafe: Obj.prototype.getA can be overwritten.
Here is a jsfiddle showing how you can use ES5 getter/setter definitions to make a property of an object something that can only be fetched. The code looks like this:
var object = {
get x() {
return 17;
}, set x() {
alert("You cannot set x!");
}
};
Of course the getter could obtain the value of the property ("x") from anywhere, like a closure from a constructor or something. The point is that the setter simply does not change the value, so attempts to change it:
object.x = 100;
will not have any effect.