Given the following code are foo, bar and baz all effectively the same? What if any is the advantage of using the get keyword?
var getValue = function () {
return 'value';
}
var foo = {
value: getValue(),
};
var bar = {
get value() {
return getValue();
},
};
var baz = {
get value() {
return 'value';
},
};
console.log('foo.value', foo.value); // foo.value value
console.log('bar.value', bar.value); // bar.value value
console.log('baz.value', baz.value); // baz.value value
Given the following code are foo, bar and baz all effectively the same?
No, not at all.
foo will have a value property that will be the result of calling getValue when foo was created, and will not call getValue later.
bar will have a value property that, when accessed like bar.value, calls getValue and returns its return value.
baz will have a value property with the explicit value 'value'.
The differences are:
Whether getValue is called
When getValue is called
This is more obvious with some logging and with a slightly updated version of getValue:
var getValue = function () {
var value = Math.floor(Math.random() * 1000);
console.log("getValue called, returning " + value);
return value;
}
console.log("Creating foo");
var foo = {
value: getValue(),
};
console.log("Creating bar");
var bar = {
get value() {
return getValue();
},
};
console.log("Creating baz");
var baz = {
get value() {
return 42;
},
};
console.log("Calling foo");
console.log('foo.value', foo.value);
console.log("Calling bar");
console.log('bar.value', bar.value);
console.log("Calling baz");
console.log('baz.value', baz.value);
.as-console-wrapper {
max-height: 100% !important;;
}
The advantage (and disadvantage) to a getter is you can execute logic (such as calling getValue) in response to what looks like a simple property lookup (bar.value, rather than bar.value() or bar.getValue()).
Related
Why does the following code return just an empty string:
var a = {
name:"321",
foo: function(){
console.log(name);
}
}
a.foo();
because you haven't scoped name to anything so it's looking for a global variable.
try replacing
console.log(name);
with
console.log(this.name);
you can use this keyword like this - console.log(this.name); .In result of your code, you see an empty string and not a undefined error because window.name variable already exists and has nothing to do with the name variable in your object
Following comments on Rich Linnell answer:
foo is for the object's function scope exemple, and bar for callbacks's scopes.
Code:
var foo = "global",
bar = "global",
a = {
foo: (callback) => {
// var foo = 'local';
console.log('foo: ' + foo);
callback();
}
};
(() => {
// var bar = "parent";
a.foo(() => {
// var bar = "local";
console.log('bar: ' + bar);
});
})();
What is the value of this in the two contexts, and how does one nested function reference the other function's returned value?
var rootObj = {
nestedObjA: {
functionA: function() {
// what is value of 'this' here?
return 'foo';
}
},
nestedObjB: {
functionB: function() {
// how to reference? >> rootObj.nestedObjA.functionA
// what is the value of 'this' here?
}
}
}
There is no guaranteed answer to "What is the value of this inside of a function?", as you can set it with the apply()/call() methods of the function prototype.
var rootObj = {
nestedObjA: {
functionA: function() {
var foo = "bar";
return foo;
}
},
nestedObjB: {
functionB: function() {
var foo = this.nestedObjA.functionA();
console.log(foo);
}
}
}
// When calling functionB() you could use:
rootObj.nestedObjB.functionB.apply(rootObj);
The value of this by default is the function scope of functionB;
The value of this within both functions should be rootObj.nestedObjA.functionA , rootObj.nestedObjB.functionB, respectively. To check value of this , could add console.dir(this) within each function.
To return a value from a function you should add return within function body , e.g.; return rootObj.nestedObjA.functionA() withinrootObj.nestedObjB.functionB
var rootObj = {
nestedObjA: {
functionA: function() {
// what is value of 'this' here?
console.dir(this);
return 'foo';
}
},
nestedObjB: {
functionB: function() {
// how to reference? >> rootObj.nestedObjA.functionA
// what is the value of 'this' here?
console.dir(this);
return rootObj.nestedObjA.functionA()
}
}
}
var res = rootObj.nestedObjB.functionB();
console.log(res); // 'foo'
Looking at the foo function on Bar.prototype:
Bar.prototype.foo = function() {
return console.log("Foo");
};
What's the difference between
Bar = function(name) {
...
this.foo();
};
and
Bar= function(name) {
...
return this.foo(); // note the 'return'
};
The first Bar function returns undefined, which is the default return value of a function in javascript.
The second Bar function returns the result of the this.foo function, which in turn appears to return the result of console.log, which again is undefined.
So they both return undefined, but they do take a different path to get that undefined value.
I'm trying to get this:
a = new Foo(name); // a is function
a(); // returns a result
a.set(); // returns another result
I've implemented above like that:
function Foo (name) = {
val = name;
ret = function () { return val; }
ret.set = function (v) { return val = v; }
return ret;
}
Then, for multiple instances of Foo I'd like not to create method 'set', but share it through prototype property. However, all experiments I did have no effect. It works only on objects, not on functions. Even the code below doesn't work:
foo = function () { return 'a'; }
foo.foo = function () { return 'foo'; }
foo.prototype.bar = function () { return 'bar'; }
foo(); // a
foo.foo(); // foo
foo.bar(); // Uncaught TypeError: Object function () { return 'a'; } has no method 'bar'
Unfortunately there is no way to add a property to only some functions via the prototype chain. Functions have one object in their prototype chain, which is Function.prototype. There is no way to create functions which have other [[Prototype]]s.
The closest you can come to what you want are these two examples:
Your solution
function Foo (name) = {
val = name;
ret = function () { return val; }
ret.set = function (v) { return val = v; }
return ret;
}
Changing Function.prototype
Function.prototype.set = function (v) { return this.val = v; };
function Foo (name){
ret = function () { return this.val; }
ret.val = name;
return ret;
}
var f = new Foo('myfunc');
f.set('myval');
console.log(f.val);
I would strongly recommend the first solution, because in the second one, every function shares the set property/method. Changing predefined Prototypes is usually frowned upon unless it's to port functionality from newer editions of the language.
In your last example foo does not have the function bar, only it's prototype does.
Therefore only a foo object would have the function bar
So you could do this:
foo = function () { return 'a'; }
foo.foo = function () { return 'foo'; }
foo.prototype.bar = function () { return 'bar'; }
var f = new foo(); // [object]
f.foo(); // TypeError: Object [object Object] has no method 'foo'
f.bar(); // bar
Try this:
foo = function (name){
this.name = name;
}
foo.prototype.set = function(name){ return this.name = name; }
var f = new foo('yourName');
alert(f.name);
f.set('yourNameEdited');
alert(f.name);
Here's DEMO
I think I understand why variables exist outside of the function they were declared in, because you're returning another function:
myFunction = function() {
var closure = 'closure scope'
return function() {
return closure;
}
}
A = myFunction(); // myFunction returns a function, not a value
B = A(); // A is a function, which when run, returns:
console.log(B); // 'closure scope'
The way that it's written now, calling A() is like a getter.
Q: How can I write myFunction so that calling A(123) is a setter?
Try the following:
myFunction = function() {
var closure = 'closure scope'
// value is optional
return function(value) {
// if it will be omitted
if(arguments.length == 0) {
// the method is a getter
return closure;
} else {
// otherwise a setter
closure = value;
// with fluid interface ;)
return this;
}
}
}
A = myFunction(); // myFunction returns a function, not a value
A(123); // set value
B = A(); // A is a function, which when run, returns:
console.log(B); // '123'
You could do something like this if you want both getter and setter for example:
var func = function() {
var closure = 'foo';
return {
get: function() { return closure; },
set: function(value) { closure = value; }
}
};
var A = func();
A.set('foobar');
console.log(A.get()); //=> "foobar"
Should be as simple as:
myFunction = function() {
var closure = 'closure scope'
return function(setTo) {
if (typeof setTo !== "undefined") {
closure = setTo;
return this; //support call chaining, good idea hek2mgl
} else {
return closure;
}
}
}
Since the closure variable is within the closure of the function's scope, you should be able to assign to it the same way you can read from it.
See jsFiddle: http://jsfiddle.net/WF4VT/1/
Another alternative would be to use a class and define getters and setters:
function MyClass(p){
this._prop = p;
}
MyClass.prototype = {
constructor: MyClass,
get prop(){
return this._prop;
},
set prop(p){
this._prop = p;
}
}
var myObject = new MyClass("TEST");
console.log(myObject.prop);
myObject.prop = "test";
console.log(myObject.prop);
Demo: http://jsfiddle.net/louisbros/bMkbE/
jsFiddle Demo
Have your returned function accept an argument. Use it as a setter:
myFunction = function() {
var closure = 'closure scope';
return function(val) {
closure = val;
return closure;
}
}
A = myFunction(); // myFunction returns a function, not a value
B = A(123); // A is a function, which when run, returns:
console.log(B); // 'closure scope'
Revisiting this question, I see that I could do it this way:
function outside() {
var result = 'initialized'
return inside
function inside(argVariable) {
if(arguments.length) {
result = argVariable
return this
} else {
return result
}
}
}
myFunction = outside() // outside returns a function
X = myFunction() // returns: 'initialized'
$('body').append(X + '<br>')
myFunction(123) // setter
X = myFunction() // returns: 123
$('body').append(X)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>