I always thought of JavaScript closures as a perfect way for encapsulating data, sort of making variables private. But I recently realized that this pattern is very easily broken by exploiting reference semantics:
function creator() {
var x = {
key: 3
};
return function() {
return x;
}
}
var instance = creator();
var y = instance();
y.key = 4;
//returns 4
//y is a refernce to x
console.log( instance() );
How do I make sure that the private part (variables defined in scope of creator() cannot be mutated from outside?
You should use getters and setters . Following MDN example you should be able to return the same value even if set differently:
function creator() {
var x = {
get key() {
return 4;
},
set key(x) {
// do nothing
}
};
return function() {
return x;
}
}
This way when you set key, the setter drops the input value and keeps the original init value.
Related
Regarding private variable encapsulation - achieved by defining the private variable as var instead of it being a property of this ( not private this.private ). This is the most direct way of making a member private.
But, the above rule makes sense if the instance is being returned and used. In case we return a new object with get/set methods being exposed. Now, does storing the private variable in the this param still achieve private variable encapsulation
Is there any way that I can get access to the instance param when it's not being returned?
function X(init) {
this.private = init;
var that = this
function get() {
return that.private;
}
function set (tmp) {
that.private = tmp;
}
return {
get: get,
set: set
}
}
var tmp = new X(1);
console.log(tmp.get()) // 1
console.log(tmp instanceof X) // false
tmp.private = 20 // doesnt work as tmp isnt an instance object
console.log(x.get()) //1
x.set(20)
console.log(x.get()) //20
Do I have access to private as it's a property of this when the this isnt being returned?
No, we can not have access to private property on this as you are explicitly returning new object.
Consider this example when using a constructor:
function X()
{
// Scope of X()
var i = 1; // this variable is accessible only in this scope
this.get = function() { return i; };
}
a = new X(); // call the constructor
console.log(a.i); // this will be undefined
a.i = 2; // even if you try to set `i` on `a`
console.log(a.get()); // the actual `i` of `a` will still be 1
console.log(a.i); // this will be two.
Now for the example which uses a function which returns an object.
function Y()
{
// Scope of Y()
var i = 1; // this variable is accessible only in this scope
function get() { return i; };
return { // now you return an object which exposes a function that returns the value of `i` of this SCOPE.
get: get
}
}
b = Y();
console.log(b.i); // this will be undefined
console.log(b.get()); // this will be 1
b.i = 3; // this will work
console.log(b.get()); // this will still be 1
console.log(b.i); // this will be 3
I'm sorry I don't have enough time to continue the explanation, I'll return to this later.
You can hide(make private) member variables by hiding it in the scope.
Also, between these two approaches, only the first approach where you will be able to make use of the this keyword. You can't use this keyword in the second approach as its value will be the Window
You can achieve true privacy using a WeakMap.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
WeakMaps allow you to create an affiliated object on which you can append any values.
You can't access them if you can't access the scope in which they were defined.
Using ES5 in a browser
"use strict";
{
const privacy = new WeakMap();
function X(init)
{
privacy.set(this, {});
const props = privacy.get(this);
props.init = init;
}
X.prototype.setInit = function(tmp)
{
privacy.get(this).init = tmp;
};
X.prototype.getInit = function()
{
return privacy.get(this).init;
};
window.X = X;
}
Using ES6 class notation in NodeJS
const privacy = new WeakMap();
class X
{
constructor(init)
{
privacy.set(this, {});
const props = privacy.get(this);
props.init = init;
}
setInit(tmp)
{
privacy.get(this).init = tmp;
}
getInit()
{
return privacy.get(this).init;
}
}
module.exports = X;
Hi I would like to know if it is possible to make a variable behave like this:
var someFlag = true;
var someWidth = (()=>(someFlag) ? 16 : 12)();
console.log(someWidth) // 16
someFlag = false;
console.log(someWidth) // would be nice if it was 12
// right now it still prints 16
Is something like this possible? Also I know that someWidth could be a function, the idea is I have a lot of code I would need to refactor so I don't want to do someWidth();
Great way to describe object property is here
var someFlag = true;
Object.defineProperty(window, 'someWidth', {
get:()=>someFlag ? 16 : 12
})
console.log(someWidth) // 16
someFlag = false;
console.log(someWidth) // 12
I dont think its good idea to have such global variables.You can try to create your own object maybe?
I'm not sure if this would be a solution depending on what kind of refactoring you're looking at, but how about creating your own object with a modified getter/setter?
var VariableWidth = {
flag: true,
get value() {
return this.flag ? 16 : 12;
},
set setFlag(p_bool) {
this.flag = p_bool;
}
}
console.log(VariableWidth.value) // 16
VariableWidth.setFlag = false;
console.log(VariableWidth.value) // would be nice if it was 12
// right now it still prints 16
Short answer: Yes, but it's not recommended.
If a name does not belong to a local variable, then it is looked for as the name of a property of the global object - which on the browser is window. It is possible to use defineProperty on the window object to define a property with a getter function.
Object.defineProperty(window, 'test', {
get: function () { return 3; },
});
var x = test; // x = 3
However this is absolutely not recommended, because there is only one global context. In the event that multiple separate JS modules define the same global variable, the definitions will clash and you will get crashes or some odd behavior.
Another thing you can do that's not recommended, is to use a with block, which would look like this:
var o = {};
Object.defineProperty(o, 'test', {
get: function () { return 3; },
});
with (o) {
var x = test; // x = 3
}
The with keyword takes one object as a parameter. Names inside the block are looked up first as properties of that object, then as local variables, then as properties of the global object. This is not recommended either, because it requires that all names to be looked for first as properties of the object, which slows down code.
with (o) {
var test = 4;
var x = test; // x = 3
}
Also, Javascript has lexical scoping, not dynamic scoping, so you can't just wrap the top-level entry point in a with block, the whole program would have to be written inside a with block.
var f = function () {
return test;
};
with (o) {
var x = f(); // reference error: test is not defined
}
If I create a callback within a function, can I get that callback to access the local variables within that function?
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc;
callback();
}
Obj.prototype.innerFunc = function()
{
x++;
}
x naturally is not within the scope of innerFunc and will produce an error if called by itself. But if I call it from outerFunc can I extend innerFunc's scope in order to access x?
Edit: Should've mentioned that I don't want to pass arguments into the function or make x and instance of Obj. I'm more looking to treat innerFunc as though it was declared locally in outerFunc. Similar to what can be done below:
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = function() {
x++;
}
callback(); // works
}
Yes: this is exactly what function parameters are for. They allow you to pass a value from one scope into another.
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc;
x = callback(x);
}
Obj.prototype.innerFunc = function(x)
{
x++;
return x;
}
Note that the value is sent to the other function, not the variable. So you need to return the value and assign it in order to use it.
If you're using prototypes, just set an instance property:
// constructor
var Obj = function () {}
Obj.prototype.outerFunc = function()
{
this.x = 0;
var callback = this.innerFunc.bind(this);
callback();
}
Obj.prototype.innerFunc = function()
{
this.x++;
}
var instance = new Obj()
instance.outerFunc()
console.log(instance.x) // returns 1
Edit: But #lonesomeday's answer is a much better solution as it takes a more functional approach avoiding side effects :)
The preffered way of doing this is to assign x to the scope of the object then all functions can access it, via this.x
Obj.prototype.outerFunc = function()
{
this.x= 0; // set x to zero
this.innerFunc();
}
Obj.prototype.innerFunc = function(x)
{
this.x++;
return this.x;
}
This is a bit hard to solve without knowing why you don't want to pass a parameter; if you just want to have a specific function signature, maybe a higher-order function might help?
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc(x);
callback();
}
Obj.prototype.innerFunc = function(x)
{
return function () { /* use x in here */ };
}
This way you have two functions one inside the other. The outer one takes the parameter, and the inner one can access the variable that is passed to the outer one.
This of course only gives you half of what you demonstrate in your example: You can access the local variable but not modify it.
You can never access any function's internal variables from outside the function under any circumstances, in an OOP context or otherwise.
The only sort-of-exception is that a function A defined inside a function B, and returned from that function B, continues to have access to the variables in function B--the basic notion of closure.
I have no idea why you don't want to use instance variables. That's what they're for--sharing data across methods. I have no idea why you don't want to pass values in or out--that's what parameters and return values are for.
can I extend innerFunc's scope in order to access x?
No, you can't, whatever that means. There is no such notion in JS.
The closest you can come to what you seem to maybe want to do is to define the variable in the constructor:
function Obj() {
var x = 0;
this.outerFunc = function() {
var callback = this.innerFunc;
callback();
};
this.innerFunc = function() {
x++;
}
}
However, this will not work as-is because this.innerFunc is missing its context. Therefore, you would need to write
var callback = () => this.innerFunc();
However, it's a mystery why you would want to do this instead of just writing this.innerFunc().
I want to pass a function reference "go" into another function "redefineFunction", and redefine "go" inside of "redefineFunction". According to Johnathan Snook, functions are passed by reference, so I don't understand why go() does not get redefined when I pass it into redefineFunction(). Is there something that I am missing?
// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction(fn) {
fn = function(x) { return x * 3; };
}
// initial version of go()
function go(x) {
return x;
}
go(5); // returns 5
// redefine go()
go = function(x) {
return x * 2;
}
go(5); // returns 10
// redefine go() using redefineFunction()
redefineFunction(go);
go(5); // still returns 10, I want it to return 15
Or see my fiddle http://jsfiddle.net/q9Kft/
Pedants will tell you that JavaScript is pure pass-by-value, but I think that only clouds the issue since the value passed (when passing objects) is a reference to that object. Thus, when you modify an object's properties, you're modifying the original object, but if you replace the variable altogether, you're essentially giving up your reference to the original object.
If you're trying to redefine a function in the global scope: (which is a bad thing; you generally shouldn't have global functions)
function redefineFunction(fn) {
window[fn] = function() { ... };
}
redefineFunction('go');
Otherwise, you'll have to return the new function and assign on the calling side.
function makeNewFunction() {
return function() { ... };
}
go = makeNewFunction();
Nothing is "passed by reference" in JS. There are times that references are passed, but they're passed by value. The difference is subtle, but important -- for one thing, it means that while you can manipulate a referenced object pretty much at will, you can't reliably replace the object (read: alter the reference itself) in any way the caller will see (because the reference was passed by value, and is thus merely a copy of the original reference; attempting to reassign it breaks in the same way it would if the arg were a number or string).
Some cowboys will assume you're redefining a global function and mess with it by name to get around the limitations of pass-by-value, but that will cause issues the second you decide not to have globals all over the place.
The real solution: return the new function, and let the caller decide what to do with it. (I'd argue that redefining functions right out from under the code that uses them is a pretty bad design decision anyway, but eh. I guess there could be a reason for it...)
Snook is wrong. And I don't think it's pedantic at all (#josh3736 :) to point out that EVERYTHING in JavaScript is pass by value. The article by Snook gets this COMPLETELY wrong. Passing a primitive and passing an object work the exact same way. These are equivalent:
var x = 2;
var y = x;
y = 3; //x is STILL 2.
function stuff(y){
y = 3; //guess what. x is STILL 2
}
stuff(x);
///////////////////
var x = {stuff: 2};
var y = x;
y = {stuff: 3}; //x.stuff is STILL 2
function stuff(y){
y = {stuff: 3}; //guess what. x.stuff is STILL 2
}
stuff(x);
This is important. Java, C#, and MOST languages work this way. That's why C# has a "ref" keyword for when you really do want to pass something by reference.
You can't modify the variable from inside the function, so the quick fix is to return the value and assign it outside the function, like this
// log() just writes a message to the text area
function log(message) {
$('#output').val($('#output').val() + message + "\n");
}
// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction() {
newvalue = function(x) { return x * 3; };
return newvalue;
}
// initial version of go()
function go(x) {
return x;
}
log(go(5)); // returns 5
// redefine go()
go = function(x) {
return x * 2;
}
log(go(5)); // returns 10
// redefine go() using redefineFunction()
go = redefineFunction();
log(go(5)); // returns 10, I want it to return 15
I believe functions are 'passed in by value'. If you put log(f(5)); inside your redefineFunction function it will output 15, but 10 when you call log(go(5)) afterwards.
If you change redefineFunction to return the function and then assign it to go (go = redefineFunction()) it will work as you expect.
This is equivalent to asking if you can redefine any variable by passing it as an argument to some function. No. You can reassign it by, uhh, reassigning it. In this case, if you make redefineFunction return a function, you can simply assign it to go:
function redefineFunction() {
var fn = function(x) { return x * e; };
return fn;
}
function go(x) {
return x;
}
go = redefineFunction();
go(5); // return 15
This is working in firefox:
function redefineFunction(fn) {
window[fn] = function(x) {
return x * 3;
}
};
function go(x) {
return x;
};
alert(go(5));
go=function(x) {
return x * 2;
}
alert(go(5));
redefineFunction('go');
alert(go(5));
The secret is that a global function called go also is called window.go and window["go"].
This can also be used at styles: element.style["overflow"] = "hidden", and in attributes:
element["value"] = "hello there".
This is a very useful knowlege.
Why dont use a object? something like this:
var o = {
go: function( x ) {
return x;
},
redefineFunction: function ( fn ) {
if (typeof fn === 'function') {
this.go = fn;
}
}
}
console.log(o.go(5)); // return 5
var fn = function (x) {
return x * 2;
};
o.redefineFunction(fn);
console.log(o.go(5)); //return 10
Hope it helps!
This is the javascript closure code I saw at Javascript Definitive Guide. I'd like to write it as C++11
var uniqueID1 = (function()
{
var id = 0;
return function() { return id++; };
})();
This is the cpp code I wrote. But it isn't be compiled. Can C++11 represent the same expression?
auto c = []() -> int (*)() { int x = 0; return [&x]() -> int { return x++; }};
I'm using VS2010
Edit:
This is the full javascript sample code I made. You can test easily how the code works at your web browser.
<head>
<script language="javascript">
var uniqueID1 = (function()
{
var id = 0;
return function() { return id++; };
})();
var uniqueID2 = (function()
{
var id = 0;
return function() { return id++; };
})();
</script>
</head>
<body>
<input value = "uniqueid1" type="button" OnClick="alert(uniqueID1());"></input>
<input value = "uniqueid2" type="button" OnClick="alert(uniqueID2());"></input>
</body>
</html>
OK, first let's break down what your JavaScript does.
function()
{
var id = 0;
return function() { return id++; };
}
This creates a function. A function with no name, which takes no parameters. This function, when called, will return a new function. The inner function will have access to a locally scoped variable, and this variable will be part of the state of that inner function.
Each time this function is called, it will return a new function. That new function will have its own state (var id = 0; has to do something, after all). Each call of the outer function will return a new function with new state.
This:
(function()
{
var id = 0;
return function() { return id++; };
})
Wraps the function in a pair of parenthesis. This is needed for operator precedence rules, to allow this to work:
(function()
{
var id = 0;
return function() { return id++; };
})()
This creates a function, and then calls the function. That's what the last () do at the end. It calls the outer function, which creates an inner function with its own scope and returns it.
In this expression, the outer function is lost. It's gone; you can't access it anymore. You created it for just long enough to call it, then let it drop into the trashcan of garbage collection.
Given all of this, we can see that this statement:
var uniqueID1 = (function()
{
var id = 0;
return function() { return id++; };
})();
Creates the outer function, calls the function which returns a new function, and then stores the inner function in a variable called uniqueID1.
If you need proof that this is true, try this in your HTML:
var uniqueMaker = function()
{
var id = 0;
return function() { return id++; };
};
var uniqueID1 = uniqueMaker();
var uniqueID2 = uniqueMaker();
You'll get the same answer as your copy-and-paste version.
If we want C++ code to mimic this, we need to perform each step with proper C++ code.
First, the inner function. In C++, lexical scoping does not exist. So you cannot return functions that reference variables in other scopes. You can only return a lambda that has a copy of variables from another scope. Also, lambdas cannot modify scope unless you explicitly allow it. Thus, the inner code must look like this:
int id = 0;
return [=]() mutable { return ++id; };
That's all well and good, but now we need to create a lambda that will return this stateful lambda function. In C++, functions that have state are not the same as function pointers. And since the type of a lambda is compiler-defined, there's no way to type its name. Therefore, we must employ std::function as the return type of the outer function.
[]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
}
This creates a lambda function that, when called, will return an inner function with its own state. State that is independent from any subsequent calls to this function. Just like the JavaScript example.
Now, that's not enough. Remember, your JavaScript creates the outer function, calls it, and stores only its return value. The outer function itself is discarded. So we need to mimic this. Fortunately, this is easy enough in C++; it looks just like JavaScript:
([]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
})()
Lastly, we stick it in a variable:
auto uniqueID1 = ([]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
})();
The type of uniqueID1 will be std::function<int()>. It won't be the type of the outer function. The outer function is just a temporary that was used to create the inner scope.
I assume you're not asking for a literal translation, but rather how to best express this construct in C++. Your JavaScript construct is in some sense "faking a constructor", and your ID generator is best expressed as a simple class in C++. Then you just make instances of that class:
class UniqueID
{
unsigned int value;
public:
UniqueID() : value(0) { }
unsigned int operator()() { return ++value; }
};
Usage:
UniqueID gen1, gen2;
some_function(gen1());
another_function(gen2());
Foo x(Blue, "Jim", gen1());
This approach is lighter-weight than a std::function wrapper, although a straight-up lambda will produce a similar data structure (though you cannot know its type name). You can initialize value to -1 if you want the first ID to be 0 (though it might be useful to reserve 0 as a special value).