Will this calc function be defined once (put on the prototype chain for the 'obj' variable)? If not, then how can I get the calc function on the prototype chain so all instantiations of Obj will reference the same calc function?
I tried assigning the calc function to Obj.prototype.calc, but then when 'obj' is created, it can't find it in the creation process.
window.onload = function () {
var Obj = function (obj) {
var calc = function (o) {
for (p in o) {
if (o.hasOwnProperty(p) && typeof o[p] === 'function') {
o[p] = o[p]();
}
}
return o;
};
return calc(obj);
};
function test() {
var obj = new Obj({
a: 1,
b: 2,
c: function () {
return this.a + this.b;
},
d: function () {
return this.b * this.c;
}
});
window.console.log(obj.a); // 1
window.console.log(obj.b); // 2
window.console.log(obj.c); // 3
window.console.log(obj.d); // 6
}
test();
}
The purpose of the Obj constructor is creating an object literal type syntax when I define many versions of 'obj' but allowing the use of the 'this' keyword to calculate properties in terms of other properties in each object.
Here is the version with the prototype definition which doesn't work:
<!DOCTYPE HTML>
<html>
<head>
<script>
window.onload = function () {
var Obj = function (obj) {
return calc(obj);
};
Obj.prototype.calc = function (o) {
for (p in o) {
if (o.hasOwnProperty(p) && typeof o[p] === 'function') {
o[p] = o[p]();
}
}
return o;
};
function test() {
var obj = new Obj({
a: 1,
b: 2,
c: function () {return this.a + this.b;},
d: function () {return this.b * this.c;}
});
window.console.log(obj.a);
window.console.log(obj.b);
window.console.log(obj.c);
window.console.log(obj.d);
}
test();
}
</script>
</head>
<body>
</body>
</html>
Will this calc function be defined once (put on the prototype chain for the 'obj' variable)?
No, it gets re-created every time your Obj function is called. (Also note that as Pointy, er, pointed out, you're falling prey to The Horror of Implicit Globals with your calc symbol.)
If not, then how can I get the calc function on the prototype chain so all instantiations of Obj will reference the same calc function?
By putting it there, and then using it from there:
Obj.prototype.calc = /* ...the function, use `this` rather than an argument... */;
and in Obj:
this.calc(); // No `return` needed
Simplified example:
var Foo = function(x, y) {
this.x = x;
this.y = y;
this.calc();
};
Foo.prototype.calc = function() {
this.z = this.x + this.y;
};
var f = new Foo(2, 3);
console.log(f.z); // "5"
Related
why this logs 1 and not 2 ? i am trying to pass this scope to initData function but no success. after running init i should trigger iniData but this should refer to the object itself not to a new scope
let startFunction = function (){
let initData = () => {
this.x = 2
}
return {
x:1,
init:initData.bind(this)
};
};
obj=startFunction()
obj.init();
console.log(obj.x); // should be 2
update:
let startFunction = function (){
let initData = function(){
this.x = 2
}
return {
x:1,
init:initData
};
};
obj=startFunction()
obj.init();
console.log(obj.x); // should be 2
and why this works ? shouldn't the function create a new scope ?
There are two issues here. The first issue is that arrow functions are immutably bound to their execution context. Function.prototype.bind has no effect on an arrow function. The second issue here is what this refers to when you call startFunction. When you invoke a function freely, without a binding to a particular object, this refers to the object in which the function is invoked. So this refers to the global object in initData permanently.
So let's think about the value of obj and the global object's x value after each line.
After obj=startFunction:
// global x is undefined
// obj
{
x: 1,
init: initData // with the same binding to the global object
}
After obj.init(), initData sets the global object's x value to 2:
// global x is 2
// obj
{
x: 1,
init: initData // with the same binding to the global object
}
Problem you are facing is the x in the object has nothing to do with the this.x that is being assigned in the init method. You need to set an object and in the init code adjust that object.
let startFunction = function() {
const initData = () => {
data.x = 2
};
var data = {
x: 1,
init: initData,
};
return data;
};
const obj = startFunction()
obj.init();
console.log(obj.x);
Better solution, use a proper class.
class MyClass {
x = 1;
init() {
this.x = 2;
}
}
const obj = new MyClass();
obj.init();
console.log(obj.x);
class MyClass2 {
x = 1;
constructor() {
this.x = 2;
}
}
const obj2 = new MyClass2();
console.log(obj2.x);
I'm learning JS and am wondering, is there a way to return the function bar() or buz() by without returning foo()? For example, if I wanted to return the function bar(); to get 2, could I do that? Would it be something like foo().bar(); ?
// Nested Scopes
function foo() { // can only access itself
var a = 1;
function bar() { // access to foo(), not buz()
var b = 2;
function buz() { // access to bar() and foo()
var c = 3;
console.log(a, b, c); // 1, 2, 3
}
buz();
console.log(a, b); // 1, 2
}
bar();
console.log(a); // 1
}
foo(); // 1
Certainly. You can return an object at each stage which holds the function, or you can return the function itself. This utilizes what's called a closure.
function foo() {
var a = 1;
function bar() {
var b = 2;
function buz() {
var c = 3;
console.log(a, b, c);
}
console.log(a, b);
return { buz: buz };
}
console.log(a);
return { bar: bar };
}
foo().bar().buz();
You can do this, but it’s quite over-complicated.
The basic syntax is:
foo().bar().buz();
Where-ever you add another () after an existing one, it’ll print that level out. See the snippet for examples.
// Nested Scopes
function foo() { // can only access itself
var a = 1;
function bar() { // access to foo(), not buz()
var b = 2;
function buz() { // access to bar() and foo()
var c = 3;
return (function() {
console.log(a, b, c);
});
}
return (function() {
var tmp = function() {
console.log(a, b);
return {
buz: buz
};
};
tmp.buz = buz;
return tmp;
})();
}
return (function() {
var tmp = function() {
console.log(a);
return {
bar: bar
};
};
tmp.bar = bar;
return tmp;
})();
}
foo().bar().buz(); // (nothing)
foo().bar()().buz(); // 1, 2
foo()().bar()().buz(); // 1 // 1, 2
foo()().bar().buz()(); // 1 // 1, 2, 3
foo()().bar()().buz()(); // 1 // 1, 2 // 1, 2, 3
This kind of abuses the fact that you can assign properties to anything in JavaScript, including functions.
foo is a function that refers to the outer foo.
foo() is another function that refers to that inner tmp which has a bar property that refers to the inner bar function.
foo()() actually calls that inner tmp function but still leaves you with an object that has a bar property that again refers to the inner bar function.
This approach is basically the same for bar.
For buz, however, (something).buz() is just a function, without any extra properties and (something).buz()() doesn’t return anything, because that’s the final level.
you do this more like setting a variable.
var foo = {
bar: function() {
return 3;
}
}
console.log(foo.bar());
I am trying to simulate a simple Holder "class" in JavaScript with a "private" property that holds something and "public" getter and setter "methods" to access the value.
The approach exhibited by HolderA below is mentioned e.g. here. The other approach I more or less arrived at by mutation but I guess it must be recognizable as an idiom as well. I like it because it contains no this or prototype stuff and seems very elementary and functional. Is there a difference between the two?
The test code (I run it under nodejs) seems to suggest that the two approaches are identical except that in the first case the objects I get have typeof object whereas in the second function.
var test = function(o) {
var initialValueCorrect = (!(typeof o.getX()==='undefined'))&&(o.getX()===0);
var VALUE_TO_SET = 10;
o.setX(VALUE_TO_SET);
var getSetWorks = o.getX()===VALUE_TO_SET;
var xIsPrivate = (typeof o.x === 'undefined');
var xHasCorrectValue;
if (!xIsPrivate)
xHasCorrectValue = o.x === VALUE_TO_SET;
return {initialValueCorrect: initialValueCorrect,
getSetWorks : getSetWorks,
xIsPrivate: xIsPrivate,
xHasCorrectValue: xHasCorrectValue};
};
var HolderA = (function() {
function foo(x) {
this.getX = function() {
return x;
};
this.setX = function(_x) {
x = _x;
};
};
return foo;
})();
var createHolderB = (function() {
var x;
function foo(_x) {
x = _x;
return foo;
}
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
})();
var objects = [{object: new HolderA(0), name: "approach with constructor-invocation and 'this'"},
{object: createHolderB(0), name: "approach with normal function invocation and closed variable"}];
for (var i = 0; i<objects.length ; i++) {
var testResult = test(objects[i].object);
console.log('['+objects[i].name+']: the object is a: '+(typeof objects[i].object)
+'\n\n\t\t\t'+JSON.stringify(testResult)+'\n\n\n\n\n');
}
update
As Bergi has pointed out function createHolderB in my code above is plain wrong and only creates a singleton object. So, is not really a "constructor" function. To that end I've now created createHolderC which can be used to really create multiple objects with a hidden private property like this:
var objectC1 = createHolderC()(0);
Now, is there any material difference between HolderA and the createHolderC function or is the difference purely stylistic?
var createHolderC = function () {
return (function() {
var x;
function foo(_x) {
x = _x;
return foo;
};
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
})();
};
createHolderB does not create new holders like HolderA does. It's essentially a singleton pattern. You might also want to call it a module. Notice that createHolderB() === createHolderB.
createHolderC is still different from HolderA in that it returns function objects, not instances. You may see the differences better when you strip out the unnecessary IEFEs:
function HolderA(x) {
this.getX = function() {
return x;
};
this.setX = function(_x) {
x = _x;
};
// implicit `return this;` when called via `new`
}
function createHolderC() {
var x;
function foo(_x) {
x = _x;
return foo;
};
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
}
A typical factory would rather look like this:
function createHolderD(x) {
var foo = {};
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
}
(or even with return {getX: …, setX: …};), the only difference to HolderA is the prototypical inheritance then.
Basically both exhibits the private access behavior to the x variable. But the difference between those two are
Constructor function
var HolderA = (function() {
function foo(x) {
this.getX = function() {
return x;
};
this.setX = function(_x) {
x = _x;
};
};
return foo;
})();
This is a self executing function, where it returns Constructor foo.
That is the reason you are using new while creating this type of holder {object: new HolderA(0)
A function
var createHolderB = (function() {
var x;
function foo(_x) {
x = _x;
return foo;
}
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
})();
Even this is also a self executing function, but while execution it creates x variable and returns function foo, and foo access x by closure.
You are creating this type of holder just by normal function call object: createHolderB(0).
Both cases are really bad in practice.
If you're making closures (anonymous functions) that hold your "private variable" scope, it means you're creating those functions for every instance of the class. That costs memory and performance. I used to create classes like this, but then once I was making large number of instances and found out that it hits performance hard.
Just as in Python, make private variables private by some convention, like underscore in _name. Then you can break it for debug reasons (because variables in closure scope are not accessible).
This is how I would do it:
function MyClass(arg) {
this._privateVar = arg;
}
MyClass.prototype.getPrivateVar = function() {
return this._privateVar;
}
You can also make getters and setters:
Object.defineProperty(MyClass.prototype, "privateVar", {
get: function() {
return this._privateVar;
}
}
But don't try to push javascript into things it's not designed to, or you'll pay with performance, code readability and debugging complexity. Applies to other languages too.
let o = {
x: 1,
foo() {
setTimeout(()=>
console.log(this.x),
100);
}
}
o.foo();
This prints out 1 after 100ms.
Is this because it is equivalent to the following, meaning that the lexical this binding of arrow functions works?
let o = new (function Object() {
this.x = 1;
this.foo = ()=> console.log(this.x);
});
o.foo();
Is this because it is equivalent to the following, meaning that the lexical this binding of arrow functions works?
No, it's much simpler than that. It's equivalent to
var o = {
x: 1,
foo: function() {
setTimeout(()=>
console.log(this.x),
100);
}
};
o.foo();
and with the arrow function converted:
var o = {
x: 1,
foo: function() {
var self = this;
setTimeout(function() {
console.log(self.x)
}, 100);
}
};
o.foo();
Since you are calling o.foo(), this inside foo refers to o. Because an arrow function's this is subject to lexical scope, it access foo's this.
When defining an object literal its possible to use a self-invoking function so the function has access to private variables,
obj={
value:(function(){
var private;
return function(){
return true;
}
}())
};
But is it possible to do the same thing with a getter/setter in an object literal?
obj={
get value(){
return value;
},
set value(v) {
value=v;
}
};
[edit 2022]
A pretty old answer.
More actual: you can create a factory function. In the snippet the factory creates an object with (get and set) access (through the closure) to a private variable.
const obj1 = objFactory(`Hello`);
const obj2 = objFactory(`World`);
console.log(`${obj1.privateThing} ${obj2.privateThing}`);
obj1.privateThing = `Goodbye`;
console.log(`${obj1.privateThing} ${obj2.privateThing}`);
function objFactory(somethingPrivate) {
return {
get privateThing() { return somethingPrivate; },
set privateThing(value) { somethingPrivate = value; }
};
}
The old answer:
Not really. You can also create an Immediately Invoked Function Expression (IIFE) for obj though:
obj = function(){
var privatething = 'hithere';
return {
get value() {
return privatething;
},
set value(v) {
privatething = v;
}
};
}();
obj.value; //=> 'hithere';
obj.value = 'good morning to you too';
obj.value; //=> 'good morning to you too'
As per ES6 and later style, default values can also be set in the signature.
const _ = function(_x = 'leafy greens', _y = 'chicken', _z = 'noodle soup') {
// console.log(_x)
return {
_x,
_y,
_z,
get x() { return this._x },
set x(value) { this._x = value }
}
}()
console.log(_.x)
_.x = 'beef & pork'
console.log(_.x)
This works.
var obj = {a:1};
console.log(obj.a); //1
Object.defineProperty(obj,"a",{
get: function(){
return this.b;
},
set: function(x){
this.b = x;
},
configurable:true,
});
obj.a = 10;
console.log(obj); //10
for(var key in obj)
{
console.log(key)
}
If you don't want the property b to be enumerated while using for...in loop or Object.keys(), just add the line
Object.defineProperty(obj,"b",{enumerable:false})
Note : The above code can also be used as a listener, to detect changes in the property's value. (By implementing the needed function in the set method, after setting the value.)
var obj = {a:1};
console.log(obj.a); //1
Object.defineProperty(obj,"a",{
get: function(){
return this.b;
},
set: function(x){
this.b = x;
console.log("obj.a value has been changed to "+x);
},
configurable:true,
});
obj.a = 10;
obj.c = 20;
obj.a = 30;