You will have to forgive me, as I am sure this is addressed elsewhere, but I have no idea what to call this bit of syntax or the concept that this example illustrates. How does this get() function know that the parameter I am passing into it refers to an index of the adjacent array? I am not giving get() any indication of what object I am referring to, unless putting an object in parenthesis directly next to it has this effect. Is this correct? Is there a broader concept here that I am unaware of involving proximity and function calls?
function get(prop) {
return function(obj) {
return obj[prop]
}
}
get(1)([1,2,3]);
// output = 2
It might make more sense if you split get(1)([1,2,3]) out into 2 lines like this:
var get1Function = get(1);
get1Function([1,2,3])
// output = 2
Note: after execution of this line
var get1Function = get(1);
get1Function is now set to function(obj) { return obj[1] }
There's no magic here. You have a function that returns a function. When you call get(2), the returned function has 2 for the value of prop. Your code is essentially equivalent to this:
var fn = get(2);
// fn = function(obj) {
// return obj[2]
// }
fn([1,2,3]);
// => 3
You've just encountered one of the most confusing concepts for early JS programmers. It's called a "closure". MDN has a good article on this topic.
In general though, you can think of get returning a new method where the value of prop has been "saved" to the same value it was when get was first invoked.
The code example you provided would probably be best understood if we renamed some things and broke it down:
function createFunctionToReturnValueForProp(prop) {
return function(obj) {
return obj[prop]
}
}
var getPropertyFor1 = createFunctionToReturnValueForProp(1);
var array1 = [1,2,3];
var array2 = [4,5,6];
var obj = { "0": "foo", "1": "bar" };
getPropertyFor1(array1); // 2
getPropertyFor1(array2); // 5
getPropertyFor1(obj); // "bar"
Related
for example, i have an object where the value of a key is yet to be known/computed but when i call that key for the first time it computes the value and replaces the calculation / function with the computed value. The point being that the value is only worked out when needed and then can be reused again without having to work it out again...
this is what i have so far...
function newobj() {
this.test=function(){
this.test=[1,2,3,4]//complex function in real world use
return this.test
}
}
a = new newobj()
a.test() //[1,2,3,4]
a.test() //not a function!
a.test //[1,2,3,4]
as you can see this requires parenthesis to call initially but not the second time, so this requires knowing whether it's already been called or not - not ideal
version 2
function newobj() {
this.test=function(){
var a=[1,2,3,4]
this.test=function(){return a}
return a
}
}
a = new newobj()
a.test() //[1,2,3,4]
a.test() //[1,2,3,4]
this just somehow doesn't seem the correct way to go about this.. but maybe it is?
apologies if this is a dumb question and thanks in advance for your help
You can use the ability of a getter to overwrite itself to create a "lazy" property whose value is only calculated the first time it's accessed:
There's a good example at MDN.
get test() {
delete this.test;
return this.test = someExpensiveFunctionCall();
}
Subsequent accesses to the property don't even use the getter - they retrieve the value direct from the object.
In your case since you're not using the usual getter syntax, you'd have to modify your function thus:
function newobj() {
Object.defineProperty(this, 'test', {
get: function() {
delete this.test;
return this.test = someExpensiveFunctionCall();
},
configurable: true
});
}
I think what you need is the Module Pattern. You could do
let Module = (function(){
let test = null;
return function(){
if(test == null){
console.log('initialized test');
test = [1, 2, 3, 4];
}
return test;
}
})();
let a = new Module();
console.log(a);
console.log(new Module());
I read this article http://web.archive.org/web/20110725013125/http://www.digital-web.com/articles/scope_in_javascript/.
In the last example, he provided the code:
var first_object = {
num: 42
};
var second_object = {
num: 24
};
function multiply(mult) {
return this.num * mult;
}
Function.prototype.bind = function (obj) {
//console.log(this); -> TypeError: Object #<Object> has no method 'log'
var method = this,
temp = function () {
//console.log(this); -> RangeError: Maximum call stack size exceeded
return method.apply(obj, arguments);
};
return temp;
}
var first_multiply = multiply.bind(first_object);
console.log(first_multiply(5)); // returns 42 * 5
var second_multiply = multiply.bind(second_object);
console.log(second_multiply(5)); // returns 24 * 5
Although he explained it, I still don't understand several things.
First, why we need do method = this, why this refers to the multiply function here and why this will change when the function temp is created on the next line? Second, why we need to create a function temp here? Third, I tried to print out the this by using console.log(). The strange thing is they both show some errors, could you tell me why?
PS: I used WebStorm IDE.
UPDATE: Please don't ignore the third question, why there are two errors when using console.log, thanks
var method = this;
Might be more clear if written:
var bindObj = this;
The bind function is really to assign which object to multiply function.
Lookup JavaScript Mixin might help explain more.
For regular functions, in JavaScript, what decides what this is going to be is how it's called. So it could be anything.
For example:
Calling it as a property of an obj, object is "this"
var obj = {run: multiply}; obj.run() // "this" will be "obj"
Calling it direct
multiply(); // "this" will be the global context, or null in strict mode
Using call or apply
multiply.call(something, 5); // "this" is "something"
Fat arrow functions, however, keep the same this as its containing function.
Function.prototype.bind = function (obj) {
return () => {
return this.apply(obj, arguments);
};
}
Also, you do not need a temporary function in either case. You could just inline the temp variable.
Since I can determine the number of arguments a function expects to have by calling its Function.length property, is there any way for me to programmatically create the right number of parameters to insert into that function at runtime? Example:
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) { }; // vararg example
var doc = document, func_length = xyz.length;
doc.xyz = (function() {
return function(a,b,c,d,e) { /* works for one but not the other */ } }).call(doc);
/* would prefer to `return function(a,b)` with only 2 parameters, if it is
used for function `xyz` (though returning 5 works fine in this case), and to
`return function(a,b,c,d,e,f)` with 6 if used for function `bcd` (which does
not work with only five params). */
// thinking about xyz.apply(null,arguments)...but which arguments..? :(
// Returning function(a,b,c,d,e) does not support functions with more than five
// parameters...which would mostly be varargs - hence my question
// I am also well aware that I can use an object or an array instead of
// using many params.
/* This is for incorporating a user-defined function for use in my code, while
* allowing for my function to do 'other stuff' afterward. (And allowing for
* varargs, of course).
* Because coding something like: doc.xyz = xyz is inflexible */
As you can see, I don't know how to do this, or if it is even possible. The search bar hasn't given me any other questions like this one, otherwise I would not have asked...
NOTE: This answer is a product of misunderstanding but
may help the future visitors of this site.
Another way:
Do you really need to add parameters? Writing the function this way would be enough:
function foo(){ //No arguments predefined
a = arguments[0] || ""; //first argument or (if not defined) empty string
b = arguments[1] || ""; //second argument etc.
c = arguments[2] || ""; //third argument etc.
alert(a+b+c);
}
foo("Hello ", "world!");
This alerts "Hello world".
The solution you want:
The simplest way:
This is what you've asked for but it's not as simple as the previous solution.
You can define a meta function with all the parameters and a handler function that changes over the time.
(function(){ //Wrapper
var foo_meta = function(a,b,c,d){ //Local meta of foo
alert(a+b+c+d); //Do the code
};
window.foo = function(a,b){ //Global foo
return foo_meta(a,b,"","");
};
window.redefine_foo = function(){ //Global foo-changer
//Rewrites foo
window.foo = function(a,b,c){
return foo_meta(a,b,c,"");
};
};
})(); //Wrapper
//Do some code
foo("a","b");
redefine_foo(); //Rewrite foo
foo("a","b","c");
//Note that foo_meta is not defined here
foo_meta == undefined; //It's safe in the wrapper :)
This will alert "ab" and then "abc". For the meaning of wrapper function, see the references.
Reference:
Arguments array: http://goo.gl/FaLM1H
Wrapping code: http://goo.gl/uQ5sd0
If you send two parameters 6 and 7 to a function doWork(a,b,c,d,e),a=7 and b=6 will be automatically set and rest of the parameters will be ignored.
Why not just pass one object into the function and use JQuery extend.
e.g.
var parm =
{ x: 1, y : 2};
f(p) {
p = $_.extend({...defaults here}, p);
...
}
This is an example for joining the arguments, regardless of the number of arguments, to show how function arguments can be turned into an array and then processed like any other array.
function foo(){ //No arguments predefined
// convert to real array
var args = Array.prototype.slice.call(arguments);
// or if Array generics are available
var args = Array.slice(arguments);
console.log(args.join(' '));
}
foo('Hello', 'world!');
foo('Hello', 'wonderful', 'world!');
Here is the fiddle
Ref: arguments MDN
Well, I think I've figured it out at last. I've realized that there may be no way to 'truly' add a parameter to a function the way that I was asking, but there is a way to emulate the same result:
var doc = document;
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) {};
var obj = {};
// Now, here it is (mostly (sort of)):
obj.userFunc = function(args) {
var args_Array = [];
for (var i=0;i < arguments.length; i++ ) {
args_Array.push(arguments[i])
}
xyz.apply(null,args_Array); // or 'this'. or 'undefined'. Whatever you want.
// do other stuff
return this; // we know what to do to make 'this' scope explicit
} // end
var thisFunc = 'xyz'
doc[thisFunc] = obj.userFunc;
doc.xyz('h','i');
doc.xyz('h','i','j');
doc.xyz('h','i','j','k');
doc.xyz('h','i').xyz('j','l').xyz('j','q'); // etc.
The trick was to use the arguments object, which conveniently assimilated all the parameters into a readily available object, push each value into an array then apply the function.
In case you're wondering what the fuss was all about, I wanted to completely incorporate a user-defined function into another function, while still being able to do 'other stuff' afterward. My previous example worked to an extent, but did not have support for varargs. This does.
This approach is greatly more flexible than: doc[thisFunc] = userDefinedFunction
:) 4/26/2014
I'm, curios how the _.chaining function is implemented and how (or better, why) it works the way it does.
Especially my question is where does the wrapping for each function happen. Let's assume I'm using _.chain(someArray).filter(...); When I step into the function, I can see that the filter function got transformed into something like
function () {
var args = [this._wrapped]; //the data from chain(...)
push.apply(args, arguments); //push to the (?) array
return result.call(this, func.apply(_, args)); //?? where are these coming from?
}
I can see that the function has 3 Closures in it's scope (compare this to the un-chained function that show the definition of the function without all the Closure to it's original function)
The first one is the find function itself, the second "the safe reference to the object itself" and the third on the underscore class itself.
When calling _.chain(), how and where (code-wise) does the transformation (the creating of the scopes etc). I can see that
//http://underscorejs.org/docs/underscore.html#section-139
_.chain = function(obj) {
return _(obj).chain();
};
gets called and this goes to
//http://underscorejs.org/docs/underscore.html#section-145
//...
chain: function() {
this._chain = true;
return this;
},
//...
Then I'm stuck. I can't figure out what happens from there. I assume that the magic happens inside the constructor, but I can't seem to figure out where the additional creation of the Closures comes in. All the functions themselves don't show any sign of being wrapped, the chain call doesn't look like it wraps something. result seems to be there but I don't know where it came from. So, where and how does this happen?
_.chain(obj) returns new instance of _ with attribute _chain = true, that instance of _ has a _wrapped attribute set to current object (great work here). _.mixin(_) in line #1210 add all of underscore methods to underscore (constructor). _.mixin method replace and extend _ methods (still has the parent functions! Accessible via _.prototype). _.mixin change functions of that _ instance (this is the place you see that new function).
New function is:
function () {
var args = [this._wrapped];
push.apply(args, arguments);
return result.call(this, func.apply(_, args));
}
(doesn't matter what method it is, same for all, func is referenced to the original method)
result method function is :
var result = function(obj) {
return this._chain ? _(obj).chain() : obj;
};
so if the object returned by func.apply(_, args) has _chain (_.chain set that attribute) returns _(obj).chain() then you can use it again :)
This is process of chaining but what about prototypes!
In constructor function :
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj); // This line do the magic
this._wrapped = obj;
};
Consider this :
func = function(a){this.a = a;}
b = func(2);
b.a // TypeError: Cannot read property 'a' of undefined
c = new func(2);
c.a // returns 2, whooa this the magical javascript!
Read this (Underscore docs about OOP) if you want to learn more about underscore mixin function
Am I missing something?
I want to create a quick function that will console.log a variable name and the value. I'd like the result of the function to show in the console: foo: bar.
My basic idea for the function looks like this:
function varlog(var_name)
{
console.log(var_name + ": " + eval(var_name));
}
And I'd call is thusly:
function someRandomFunction()
{
var foo = "bar";
// ... some stuff happens
varlog("foo");
}
This works if foo is global, but doesn't work in the example provided. Another option that also only works globally is using window[var_name] instead of the scary eval.
I don't think what I'm asking is possible, but I figured I'd throw it out there.
I'm spending a lot of time attempting to be lazy. My current method is just console.log('foo: ' + bar); which works just fine. But now I just want to know if this is possible.
Some other questions I referenced in searching for this / creating what I have now:
Variable name as a string in Javascript
How to convert variable name to string in JavaScript?
Javascript, refer to a variable using a string containing its name?
How to find JavaScript variable by its name
--
Edit: I'd love to just call varlog(foo), if the name "foo" can be derived from the variable.
Solution - (for your actual use case) - console.log({foo})
In ES6 IdentifierReferences are being accepted as PropertyDefinitions on the ObjectLiteral's PropertyDefinitionList (see compatibility chart):
The variable name is being set to the Object's Property's key
and the variable value is being set to the Object's Property's value.
As console.log shows Objects with their Propertiy/ies' keys and values you can use that to see both your variable's name and value by invoking console.log({foo}).
Note that when you initialize a single anonymous object with several
variables as I did in the second console.log while they appear in
the same order as initialized here in the snippet's output they might
get reordered (alphabetically) elsewhere.
var testint = 3
var teststring = "hi"
var testarr = ["one", 2, (function three(){})]
var testobj = {4:"four", 5:"five", nested:{6:"six",7:"seven"}}
console.log({testint})
console.log({testint, teststring, testarr, testobj})
Answer - (to the question title) - Object.keys({foo})[0]
You can also use this shorthand Object Initializer together with Object.keys() to straightly access the variable name:
var name = "value"
console.log(Object.keys({name})[0])
The reason it doesn't work is because the variable foo is not accessable to the function varlog! foo is declared in someRandomFunction, and is never passed into varlog, so varlog has no idea what the variable foo is! You can solve this problem by passing the variable foo into the function(or using some sort of closure to make foo in the scope of varlog) along with its string representation, but otherwise, I think you are out of luck.
Hope this helps.
While I'm not aware of such a possibility, I'd wanted to share a small idea:
Object.prototype.log = function(with_message) {
console.log(with_message + ":" + this);
}
var x = "string";
x.log("x");
Like I said, a small idea.
Kind of combining a couple of anwers into a small function
Would this work for you?
const log = function() {
const key = Object.keys(this)[0];
const value = this[key];
console.log(`${key}: ${value}`);
}
let someValue = 2;
log.call({someVlaue}); //someValue: 2
Works with function too, even itself.
log.call({log});
// It would return the following
log:function() {
const key = Object.keys(this)[0];
const value = this[key];
console.log(`${key}: ${value}`);
}
I don't believe what you want to do is possible.
The best alternative I can think of is to pass an object to varlog that is basically a key-value hash:
function varlog(obj)
{
for (var varname in obj) {
console.log(varname + ": " + obj[varname]);
}
}
function someRandomFunction()
{
var foo = "bar";
// ... some stuff happens
varlog({foo: foo});
}
I loved #mhitza idea, so I'm making it a little bigger...
The downside is the need to use .valueto reach the variable content.
Object.prototype.log = function(message) {
if (message) console.log(this.name, this.value, message);
else console.log(this.name, this.value);
}
function nar (name, value) {
var o = {name: name, value: value};
this[name] = o;
return o;
}
// var globalVar = 1;
nar('globalVar', 1);
globalVar.log();
// > globalVar 1
globalVar.value += 5;
globalVar.log('equal six');
// > globalVar 6 equal six
var someFunction = function () {
// var localVar = 2;
nar('localVar', 2);
localVar.log('someInfo');
// > localVar 2 someInfo
};
someFunction();
Surprised to see no super simple solution yet.
let varname = "banana"
console.log(`${JSON.stringify({varname}).split('"')[1]}`)
Prints varname in the console