Related
In JavaScript, I can write:
x = new Object({ a: 3 })
and I will have x = { a: 3 }
Similarly, I can write
x = Object({ a: 3 })
and I will have x = { a: 3 } again.
My question is: How is Object implemented to satisfy both these ways of calling it? In the first scenario, it will receive a fresh this, while in the second it will receive the global object.
My best guess is something like:
var Object = function(obj) {
var global = (function() { return this; })();
if (global == this) { // I am called as a regular function
// Create a copy of obj, potentially like this
return { ...obj };
} else { // I am called via new
// Copy all fields of obj onto this
// not sure what the best way to do this is.
}
}
The answer is in the specificaton:
When Object function is called with optional argument value, the following steps are taken:
If NewTarget is neither undefined nor the active function, then
Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
Return ! ToObject(value).
Step #1 is about what the code should do when the call is happening as part of creating something that inherits from Object, so we can ignore that step for your question.
Step #2 doesn't apply because you're passing in value and it's neither null nor undefined.
So Step #3 is what happens: It uses the ToObject operation to do type conversion to turn value into an object. Since value is already an object, that's a no-op, and the result is the same object you passed in. The new Object part of new Object({a: 1}) is completely unnecessary.
In the first scenario, it will receive a fresh this, while in the second it will receive the global object.
As you can see from the spec steps above, Object doesn't use this at all.
I think it is something like
function Object(obj) {
If (this instanceof Object) {
return Object.assign(this, ...obj)
}
return new Object(obj);
}
It's simple as that
function Object(obj) {
return obj;
}
When you call it as function it inherits its parent's scope that is window.
Buy when you initialize it as a class, the function itself is the constructor that has its own scope this.
And it's not creating a new instance with copied properties as you can see in this example:
var a = {a : 3};
var b = new Object(a);
var c = Object(a);
console.log(a === b);
console.log(a === c);
As #user2357112 specified that it's not that simple here is a more close to Object functionality:
function Object(value) {
if (typeof value === 'number') {
return new Number(value);
}
if (typeof value === 'string') {
return new String(value);
}
if (value === null || value === undefined) {
return {};
}
return value
}
var a = new Object(undefined);
console.log(new Object(1));
console.log(new Object('sad'));
console.log(new Object([]));
console.log(new Object({}));
console.log(new Object(null));
console.log(new Object());
I'm working through and trying to understand the source code of https://trianglify.io/ which can be found at https://github.com/qrohlf/trianglify. In the lib/trianglify.js file, I come across the following lines of code:
var x_color = chroma.scale(opts.x_colors).mode(opts.color_space);
var y_color = chroma.scale(opts.y_colors).mode(opts.color_space);
gradient = function(x, y) {
return chroma.interpolate(x_color(x), y_color(y), 0.5, opts.color_space);
};
My question is when the x_color(x) gets called, where does the "x" argument go? How does this argument get passed into the function if it doesn't appear in the definition? My main purpose for doing this is to add some extra custom parameters to x_color() but I can't do that if I have no idea how the parameters even get processed in the function.
EDIT
The .mode(opts.color_space) function can be found at https://github.com/gka/chroma.js/blob/master/src/scale.coffee line 158. It reads as follows:
f.mode = (_m) ->
if not arguments.length
return _mode
_mode = _m
resetCache()
f
not sure what to make of this since my coffeescript knowledge is limited.
chroma is part of chroma.js.
Looking at the code, chroma.scale(...) constructs a function with prototypes with fluent methods.
f = function(v) {
var c;
c = chroma(getColor(v));
if (_out && c[_out]) {
return c[_out]();
} else {
return c;
}
};
f.mode = function(_m) {
if (!arguments.length) {
return _mode;
}
_mode = _m;
resetCache();
return f;
};
So when you call chroma.scale(...) it returns f, and then when you call .mode(...) on the returned object, it again returns the same instance f.
The instance of f is created by the following method:
chroma = function() {
if (arguments[0] instanceof Color) {
return arguments[0];
}
return (function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return Object(result) === result ? result : child;
})(Color, arguments, function(){});
};
As you can see, this makes use of the arguments object. Mozilla defines the arguments object as:
The arguments object is an Array-like object corresponding to the arguments passed to a function.
In short, even if you do not specify parameter names in the function signature, the arguments object will still exist, and any parameters you pass will exist in the arguments array.
I've created an example of using the arguments array here
function a() {
alert(arguments[0] + ' is ' + arguments[1] + ' years old.');
}
function b(name) {
return function test() {
alert(name + ' will vw ' + arguments[0] + ' years old on his next birthday.');
}
}
a('John', 29);
var example2 = b('John');
example2(30);
In the first example, there is a straight function call, but in the second example I am returning an actual function from the b() method, and then I'm calling that returned function.
I'm learning JavaScript and am trying to learn the proper terms for what I am doing. There are so many ways to create a function.
I have created 3 examples that do the same thing, but the functions are created in completely different ways.
My questions are:
Are any one of these methods better than the other?
Why would I choose to do one way or another?
What is the last "object" method called?
What advice would you have to make this example better?
//EXAMPLE 1
// is this called function declaration?
function add( a, b ) {
return a + b;
}
function subtract( a, b ) {
return a - b;
}
function compute( a, b ) {
var sum = add( a, b );
var difference = subtract( a, b );
var total = sum + difference;
return total;
}
compute( 2, 3 ); //returns 4
//EXAMPLE 2
// is this called function expressions?
var add = function ( a, b ) {
return a + b;
};
var subtract = function ( a, b ) {
return a - b;
};
var compute = function ( a, b ) {
var sum = add( a, b );
var difference = subtract( a, b );
var total = sum + difference;
return total;
};
compute( 2, 3 ); //returns 4
//EXAMPLE 3
// what is this method called?
var calculator = {
add: function ( a, b ) {
return a + b;
},
subtract: function ( a, b ) {
return a - b;
},
compute: function ( a, b ) {
var sum = this.add( a, b );
var difference = this.subtract( a, b );
var total = sum + difference;
return total;
}
}
calculator.compute( 2, 3 ); //returns 4
is this called function declaration?
function add( a, b ) {
return a + b;
}
Yes.
is this called function expressions?
var add = function ( a, b ) {
return a + b;
};
Yes. Notice that only the function(…){…} part is the function expression, the rest is a normal assignment (variable declaration with initialiser, to be pedantic).
what is this method called?
… {
add: function ( a, b ) {
return a + b;
},
…
}
Again, it's a function expression. Used as a property value in an object literal here, to define a method.
Are any one of these methods better than the other?
Function declarations are preferred over assigning function expressions to variables (there are slight differences). You should use expressions only where you need them as an expression (e.g. in IIFEs, conditional assignments, property assignments, property definitions, return statements etc).
Function declaration:
function add(a,b) { return a+b; }
A function declaration is defined at parse time for a certain script block. It can be called anywhere in the block without producing an error:
(function() {
add(3,3) //The function block has already been parsed, add() is available
function add(a,b) { return a+b; }
})();
Function expressions:
var add = function(a,b) { return a+b; }
Function expressions assign a variable to an anonymous function. These are evaluated at run time and cannot be called before being declared.
(function() {
add(3,3) //Error: add() has not yet been defined.
var add = function(a,b) { return a+b; }
})();
Object Methods:
Methods, are functions that are a property of an object.
var obj = {
propert1: 'property1 value',
add: function(a,b) {
return a+b;
}
};
These may be called via obj.add(3,3), however not prior to declaring the object via an object literal or assignment of a method to a property.
Is there a preffered way?
Declaring functions via a function declaration offers flexibility. It may however lead to unexpected results, For example(raised functions):
(function returnVal() {
function getSomething() {
return 'foo';
}
return getSomething();
function getSomething() {
return 'bar';
}
})(); //returns 'bar'
The return of the function may appear unexpected, however functions are raised during parse-time, and getSomething() is overridden.
Rewriting the code using a function expression produces the desired result
(function returnVal() {
var getSomething = function() {
return 'foo';
}
return getSomething();
getSomething = function() {
return 'bar';
}
})(); //returns 'foo'
Object methods on the other hand act much like function expressions however they are accessible under the object's name.
var obj = {};
obj.foo = function() { /*code*/ }
obj.bar = function() { /*code*/ }
They act similarly to function expressions, however this groups code under the ownership of obj. For clarity you may wish to choose this.
In Javascript, how can I bind arguments to a function without binding the this parameter?
For example:
//Example function.
var c = function(a, b, c, callback) {};
//Bind values 1, 2, and 3 to a, b, and c, leave callback unbound.
var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope?
How can I avoid the side-effect of having to bind the function's scope (e.g. setting this = null) as well?
Edit:
Sorry for the confusion. I want to bind arguments, then be able to call the bound function later and have it behave exactly as if I called the original function and passed it the bound arguments:
var x = 'outside object';
var obj = {
x: 'inside object',
c: function(a, b, c, callback) {
console.log(this.x);
}
};
var b = obj.c.bind(null, 1, 2, 3);
//These should both have exact same output.
obj.c(1, 2, 3, function(){});
b(function(){});
//The following works, but I was hoping there was a better way:
var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice?
I'm still new at this, sorry for the confusion.
Thanks!
You can do this, but best to avoid thinking of it as "binding" since that is the term used for setting the "this" value. Perhaps think of it as "wrapping" the arguments into a function?
What you do is create a function that has the desired arguments built into it via closures:
var withWrappedArguments = function(arg1, arg2)
{
return function() { ... do your stuff with arg1 and arg2 ... };
}(actualArg1Value, actualArg2Value);
Hope I got the syntax right there. What it does is create a function called withWrappedArguments() (to be pedantic it is an anonymous function assigned to the variable) that you can call any time any where and will always act with actualArg1Value and actualArg2Value, and anything else you want to put in there. You can also have it accept further arguments at the time of the call if you want. The secret is the parentheses after the final closing brace. These cause the outer function to be immediately executed, with the passed values, and to generate the inner function that can be called later. The passed values are then frozen at the time the function is generated.
This is effectively what bind does, but this way it is explicit that the wrapped arguments are simply closures on local variables, and there is no need to change the behaviour of this.
In ES6, this is easily done using rest parameters in conjunction with the spread operator.
So we can define a function bindArgs that works like bind, except that only arguments are bound, but not the context (this).
Function.prototype.bindArgs =
function (...boundArgs)
{
const targetFunction = this;
return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
};
Then, for a specified function foo and an object obj, the statement
return foo.call(obj, 1, 2, 3, 4);
is equivalent to
let bar = foo.bindArgs(1, 2);
return bar.call(obj, 3, 4);
where only the first and second arguments are bound to bar, while the context obj specified in the invocation is used and extra arguments are appended after the bound arguments. The return value is simply forwarded.
In the native bind method the this value in the result function is lost. However, you can easily recode the common shim not to use an argument for the context:
Function.prototype.arg = function() {
if (typeof this !== "function")
throw new TypeError("Function.prototype.arg needs to be called on a function");
var slice = Array.prototype.slice,
args = slice.call(arguments),
fn = this,
partial = function() {
return fn.apply(this, args.concat(slice.call(arguments)));
// ^^^^
};
partial.prototype = Object.create(this.prototype);
return partial;
};
var b = function() {
return c(1,2,3);
};
One more tiny implementation just for fun:
function bindWithoutThis(cb) {
var bindArgs = Array.prototype.slice.call(arguments, 1);
return function () {
var internalArgs = Array.prototype.slice.call(arguments, 0);
var args = Array.prototype.concat(bindArgs, internalArgs);
return cb.apply(this, args);
};
}
How to use:
function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");
It's a bit hard to tell exactly what you ultimately want to do because the example is sort of arbitrary, but you may want to look into partials (or currying): http://jsbin.com/ifoqoj/1/edit
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] === undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
var c = function(a, b, c, callback) {
console.log( a, b, c, callback )
};
var b = c.partial(1, 2, 3, undefined);
b(function(){})
Link to John Resig's article: http://ejohn.org/blog/partial-functions-in-javascript/
Using LoDash you can use the _.partial function.
const f = function (a, b, c, callback) {}
const pf = _.partial(f, 1, 2, 3) // f has first 3 arguments bound.
pf(function () {}) // callback.
May be you want to bind reference of this in last but your code:-
var c = function(a, b, c, callback) {};
var b = c.bind(null, 1, 2, 3);
Already applied binding for instance this and later you can not change it.
What I will suggest that use reference also as a parameter like this:-
var c = function(a, b, c, callback, ref) {
var self = this ? this : ref;
// Now you can use self just like this in your code
};
var b = c.bind(null, 1, 2, 3),
newRef = this, // or ref whatever you want to apply inside function c()
d = c.bind(callback, newRef);
Use a protagonist!
var geoOpts = {...};
function geoSuccess(user){ // protagonizes for 'user'
return function Success(pos){
if(!pos || !pos.coords || !pos.coords.latitude || !pos.coords.longitude){ throw new Error('Geolocation Error: insufficient data.'); }
var data = {pos.coords: pos.coords, ...};
// now we have a callback we can turn into an object. implementation can use 'this' inside callback
if(user){
user.prototype = data;
user.prototype.watch = watchUser;
thus.User = (new user(data));
console.log('thus.User', thus, thus.User);
}
}
}
function geoError(errorCallback){ // protagonizes for 'errorCallback'
return function(err){
console.log('#DECLINED', err);
errorCallback && errorCallback(err);
}
}
function getUserPos(user, error, opts){
nav.geo.getPos(geoSuccess(user), geoError(error), opts || geoOpts);
}
Basically, the function you want to pass params to becomes a proxy which you can call to pass a variable, and it returns the function you actually want to do stuff.
Hope this helps!
An anonymous user posted this additional info:
Building on what has already been provided in this post -- the most elegant solution I've seen is to Curry your arguments and context:
function Class(a, b, c, d){
console.log('#Class #this', this, a, b, c, d);
}
function Context(name){
console.log('#Context', this, name);
this.name = name;
}
var context1 = new Context('One');
var context2 = new Context('Two');
function curryArguments(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function bindContext() {
var additional = Array.prototype.slice.call(arguments, 0);
return fn.apply(this, args.concat(additional));
};
}
var bindContext = curryArguments(Class, 'A', 'B');
bindContext.apply(context1, ['C', 'D']);
bindContext.apply(context2, ['Y', 'Z']);
Well for the exemple you gave, this will do
var b= function(callback){
return obj.c(1,2,3, callback);
};
If you want to guarenty enclosure of the parameters :
var b= (function(p1,p2,p3, obj){
var c=obj.c;
return function(callback){
return c.call(obj,p1,p2,p3, callback);
}
})(1,2,3,obj)
But if so you should just stick to your solution:
var b = obj.c.bind(obj, 1, 2, 3);
It's the better way.
Simple like that?
var b = (cb) => obj.c(1,2,3, cb)
b(function(){}) // insidde object
More general solution:
function original(a, b, c) { console.log(a, b, c) }
let tied = (...args) => original(1, 2, ...args)
original(1,2,3) // 1 2 3
tied(5,6,7) // 1 2 5
I'm using this function:
function bindArgs(func, ...boundArgs) {
return function (...args) {
return func(...boundArgs, ...args);
};
}
// use
const deleteGroup = bindArgs(this.props.deleteGroup, "gorupName1");
Why not use a wrapper around the function to save this as mythis ?
function mythis() {
this.name = "mythis";
mythis = this;
function c(a, b) {
this.name = "original";
alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name);
return "ok";
}
return {
c: c
}
};
var retval = mythis().c(0, 1);
jQuery 1.9 brought exactly that feature with the proxy function.
As of jQuery 1.9, when the context is null or undefined the proxied function will be called with the same this object as the proxy was called with. This allows $.proxy() to be used to partially apply the arguments of a function without changing the context.
Example:
$.proxy(this.myFunction,
undefined /* leaving the context empty */,
[precededArg1, precededArg2]);
Jquery use case:
instead:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(i){
$(this).val(i); // wont work, because 'this' becomes 'i'
}.bind(i));
}
use this:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(e){
var i = this;
$(e.originalEvent.target).val(i);
}.bind(i));
}
If you want to use global functions and variable dynamically you can use:
window[functionName](window[varName]);
Is it possible to do the same thing for variables in the local scope?
This code works correctly but currently uses eval and I'm trying to think of how else to do it.
var test = function(){
//this = window
var a, b, c; //private variables
var prop = function(name, def){
//this = window
eval(name+ ' = ' + (def.toSource() || undefined) + ';');
return function(value){
//this = test object
if ( !value) {
return eval('(' + name + ')');
}
eval(name + ' = value;')
return this;
};
};
return {
a:prop('a', 1),
b:prop('b', 2),
c:prop('c', 3),
d:function(){
//to show that they are accessible via to methods
return [a,b,c];
}
};
}();
>>>test
Object
>>>test.prop
undefined
>>>test.a
function()
>>>test.a()
1 //returns the default
>>>test.a(123)
Object //returns the object
>>>test.a()
123 //returns the changed private variable
>>>test.d()
[123,2,3]
To answer your question, no, there is no way to do dynamic variable lookup in a local scope without using eval().
The best alternative is to make your "scope" just a regular object [literal] (ie, "{}"), and stick your data in there.
No, like crescentfresh said. Below you find an example of how to implement without eval, but with an internal private object.
var test = function () {
var prv={ };
function prop(name, def) {
prv[name] = def;
return function(value) {
// if (!value) is true for 'undefined', 'null', '0', NaN, '' (empty string) and false.
// I assume you wanted undefined. If you also want null add: || value===null
// Another way is to check arguments.length to get how many parameters was
// given to this function when it was called.
if (typeof value === "undefined"){
//check if hasOwnProperty so you don't unexpected results from
//the objects prototype.
return Object.prototype.hasOwnProperty.call(prv,name) ? prv[name] : undefined;
}
prv[name]=value;
return this;
}
};
return pub = {
a:prop('a', 1),
b:prop('b', 2),
c:prop('c', 3),
d:function(){
//to show that they are accessible via two methods
//This is a case where 'with' could be used since it only reads from the object.
return [prv.a,prv.b,prv.c];
}
};
}();
I think you actually sort of can, even without using eval!
I might be wrong so please correct me if I am, but I found that if the private variables are declared inside the local scope as arguments, instead of using var, i.e:
function (a, b, c) { ...
instead of
function () { var a, b, c; ...
it means that those variables/arguments, will be bound together with the function's arguments object if any values are given to them in the function's invocation, i.e:
function foo (bar) {
arguments[0] = 'changed...';
console.log(bar); // prints 'changed...'
bar = '...yet again!';
console.log(arguments[0]); // prints '..yet again!'
}
foo('unchanged'); // it works (the bound is created)
// logs 'changed...'
// logs '...yet again!'
foo(undefined); // it works (the bound is created)
// logs 'changed...'
// logs '...yet again!'
foo(); // it doesn't work if you invoke the function without the 'bar' argument
// logs undefined
// logs 'changed...'
In those situations (where it works), if you somehow store/save the invoked function's arguments object, you can then change any argument related slot from arguments object and the changes will automatically be reflected in the variables themselves, i.e:
// using your code as an example, but changing it so it applies this principle
var test = function (a, b, c) {
//this = window
var args = arguments, // preserving arguments as args, so we can access it inside prop
prop = function (i, def) {
//this = window
// I've removed .toSource because I couldn't apply it on my tests
//eval(name+ ' = ' + (def.toSource() || undefined) + ';');
args[i] = def || undefined;
return function (value) {
//this = test object
if (!value) {
//return eval('(' + name + ')');
return args[i];
}
//eval(name + ' = value;');
args[i] = value;
return this;
};
};
return {
a: prop(0, 1),
b: prop(1, 2),
c: prop(2, 3),
d: function () {
// to show that they are accessible via to methods
return [a, b, c];
}
};
}(0, 0, 0);
If the fact that you can pass the values as arguments into the function annoys you, you can always wrap it with another anonymous function, that way you really don't have any access to the first defined values passed as arguments, i.e:
var test = (function () {
// wrapping the function with another anomymous one
return (function (a, b, c) {
var args = arguments,
prop = function (i, def) {
args[i] = def || undefined;
return function (value) {
if (!value) {
return args[i];
}
args[i] = value;
return this;
};
};
return {
a: prop(0, 1),
b: prop(1, 2),
c: prop(2, 3),
d: function () {
return [a, b, c];
}
};
})(0, 0, 0);
})();
Full Dynamic Access Example
We can map all argument variable names into an array by getting the function itself (arguments.callee) as a string, and filtering its parameters using a regex:
var argsIdx = (arguments.callee + '').replace(/function(\s|\t)*?\((.*?)\)(.|\n)*/, '$2').replace(/(\s|\t)+/g, '').split(',')
Now with all the variables in an array, we can now know the corresponding variable name for each function's arguments slot index, and with that, declare a function (in our case it's prop) to read/write into the variable:
function prop (name, value) {
var i = argsIdx.indexOf(name);
if (i === -1) throw name + ' is not a local.';
if (arguments.hasOwnProperty(1)) args[i] = value;
return args[i];
}
We can also dynamically add each variable as a property, like in the question's example:
argsIdx.forEach(function (name, i) {
result[name] = prop.bind(null, name);
});
Finally we can add a method to retrieve variables by name (all by default), and if true is passed as the first argument, it returns the hard-coded array with all the variables by their identifiers, to prove that they are being changed:
function props (flgIdent) {
var names = [].slice.call(arguments.length > 0 ? arguments : argsIdx);
return flgIdent === true ? [a, b, c, d, e, f] : names.map(function (name) {
return args[argsIdx.indexOf(name)];
});
}
The prop and props functions can be made available as methods inside the returned object, in the end it could look something like this:
var test = (function () {
return (function (a, b, c, d, e, f) {
var argsIdx = (arguments.callee + '').replace(/function(\s|\t)*?\((.*?)\)(.|\n)*/, '$2').replace(/(\s|\t)+/g, '').split(','),
args = arguments,
result = {
prop: function (name, value) {
var i = argsIdx.indexOf(name);
if (i === -1) throw name + ' is not a local.';
if (arguments.hasOwnProperty(1)) args[i] = value;
return args[i];
},
props: function (flgIdent) {
var names = [].slice.call(arguments.length > 0 ? arguments : argsIdx);
return flgIdent === true ? [a, b, c, d, e, f] : names.map(function (name) {
return args[argsIdx.indexOf(name)];
});
}
};
args.length = argsIdx.length;
argsIdx.forEach(function (name, i) {
result[name] = result.prop.bind(null, name);
});
return result;
})(0, 0, 0, 0, 0, 0);
})();
Conclusions
It's impossible to read/write a function's local scope variable without eval, but if those variables are function's arguments and if they're given values, you can bound those variable identifiers to the function's arguments object and indirectly read/write into them from the arguments object itself.
Hopefully I'm not over-simplifying, but what about something as simple as using an object?
var test = {
getValue : function(localName){
return this[localName];
},
setValue : function(localName, value){
return this[localName] = value;
}
};
>>> test.a = 123
>>> test.getValue('a')
123
>>> test.a
123
>>> test.setValue('b', 999)
999
>>> test.b
999