I want to pass JavaScript Objects as Arguments - javascript

function foo(o){
o=o || {};
}
foo(one:1); // ???
alert(foo(one); // ???
foo(one:1,two:2,three:3) // ???
alert(foo(one,two,three)); // ???
What exactly does this piece of JavaScript do?
o = o || {};
I've seen in many codes.

The expression
o = o || {};
means
Interpret the value of the variable "o" as a boolean. If that value is "true", then set "o" to its current value. If "false", set "o" to refer to a new Object instance.
The point is to make sure that "o" is not null, and to initialize it to a new Object instance if it is.
As far as calling the function, you need to use the "object literal" notation:
foo({ key1: value, key2: value, ... });
edit — as noted in a comment, the interpretation of the value of "o" as boolean is a rather interesting subject of its own. In this particular case, the intent is to check to see whether "o" is null. There are values for "o" that evaluate to false but which might need to be treated differently here, but there's obviously not enough context in the question to know.

you would create your object
var arg = {key: val};
and then
var result = foo(arg);
you pass the object that is the argument into the function. If your function can take more than one arg, when you define the function you would
var theFunction = function(arg1, arg2, arg3) {
// arg1, arg2, and arg3 are all references in this function
}
that way arg1, arg2, and arg3 are defined to be arguments. Javascript has some flexibility in that you could pass as many arguments as you want in; it is good design to define the function with explicit arguments so the API is clear. However, there are cases where you just don't know, so in Javascript you can get all the arguments that were passed in with the 'arguments' variable. Javascript makes this variable available in all functions. But you should use it rarely. Here is a link with examples
http://www.seifi.org/javascript/javascript-arguments.html
the
o = o || {};
sets the variable 'o' to be o, or if o is not defined, an empty object literal. It basically initializes the variable if it is 'falsy'. It is a technique to prevent null object issues.

Related

Passing `null` as context object vs directly calling the function

From this question, given that I don't want to specify any context, hence, passing null to thisArg in call().
What would be the difference between line 2 and line 3 in the following code? Is there any benefit from doing one over the other?
function sum(a,b) { return a + b; }
var result1 = sum.call(null,3,4); // 7
var result2 = sum(3,4); // 7
Similarly for apply():
var arr = [1,2,4];
var result3 = Math.max.apply(null, arr); // 4
var result4 = Math.max(...arr); // 4
It depends on whether the function you're calling was defined in loose mode or strict mode.
When calling a loose-mode function, the following three things all call the function such that this within the call is the global object for the environment (globalThis, aka window on browsers):
Calling the function without setting this: fn()
Calling the function providing a this value of undefined: fn.call(undefined) and similar
Calling the function providing a this value of null: fn.call(null) and similar
With a strict mode function, the first two both cause this during the call to be undefined, and the third (explicitly setting it to null) sets it to (you guessed it) null.
Examples:
function loose() {
console.log(`loose: ${this === null ? "null" : typeof this}`);
}
loose();
loose.call(undefined);
loose.call(null);
function strict() {
"use strict";
console.log(`strict: ${this === null ? "null" : typeof this}`);
}
strict();
strict.call(undefined);
strict.call(null);
In the normal case, if you don't need to set this to anything in particular, just call the function so the default behavior takes place.
One wrinkle: If you have an array of arguments you need to spread out as discrete arguments to the function, in any even vaguely up-to-date environment, you can use spread notation to do that: fn(...theArray). If you're stuck in an obsolete environment, the rough equivalent is fn.apply(undefined, theArray).
If you have a specific need to set a specific this value, you can do that via call or apply (as you've found), including (for strict mode functions) undefined or null.
TJ Crowder has the detailed response here, but as a general rule:
fn.call(null): In almost all cases, just call the function.
fn.apply(null, args): This is useful in some cases where you have an array of arguments and your environment doesn't support ...args, but otherwise spreading the arguments is probably more conventional: fn(...args)

JavaScript Object and Primitive

Please I want someone to explain the code below for me:
var f = new Number(44);
f.name = "Yusuf";
f.hello = function() {
console.log("Hello");
};
console.log(typeof f);
f.hello();
console.log(f.name);
console.log(f.toString() + "good");
console.log(Object.prototype.hasOwnProperty(name));
console.log(f.hasOwnProperty(hello));
console.log(f.length);
When I check the variable type. Object gets return and I am sure this is because of the Number object constructor call function. I added two properties, one a member and a method and when I call them , it work but when I used hasOwnProperty(), false is return for the member key and undefined for the method key.
Why is it so?
where are the methods going to if the hasOwnProperty doesn't work as usual when it is supposed to when I am actually checking the property on the containing object.?
I checked Number and object object and they all return false.
The hasOwnProperty method takes the property key as a string:
console.log(Number.prototype.hasOwnProperty("name"));
console.log(Object.prototype.hasOwnProperty.call(f, "name"));
console.log(f.hasOwnProperty("name"));
console.log(f.hasOwnProperty("hello"));
I recommend to always "use strict" mode so that you get exceptions when you try to use undeclared variables.

What is Function's Data Type : function or object? in JavaScript

The MDN said :
Six data types that are primitives:
Boolean
Null
Undefined
Number
String
Symbol (new in ECMAScript 6)
and Object
But I confused, the function data type and object data type.
Let's see :
var func = function() {
console.log ('Hello World ! ')
};
var obj = {
property : something
}
console.log(typeof(func)); // ===> function
console.log(typeof(obj)); // ===> object
Is it different function data type and object data type? Why typeof(func) is function? not a object? The document said there are 7 data type (6 primitive, 1 object). function is not include anywhere.
Until now, over 1 year, I think function's data type is object, I heard the function is first class object in JavaScript, so I don't have doubt about function is object but today I think more time, and wondered.
Is it different?
You can logically think of Function as a subclass of Object. It has all the methods of Object plus some more that are specific to a function (such as .bind(), .call(), .apply(), etc...).
Why Javascript decided to make Function report it's own unique type, but not Array (which is a similar derivation from Object) is anyone's guess and probably only known to the original designers of the language. It is extremely useful that Function does report its own type so you can easily check if a property is callable as a function and perhaps that is the main reason why it was done this way.
Here's a demonstration of how a Function object has the methods from an Object:
function f() {}
f.someProperty = "foo";
log(f.hasOwnProperty("someProperty"));
log(f instanceof Object);
log(f instanceof Function);
function log(x) {
var div = document.createElement("div");
div.innerHTML = x;
document.body.appendChild(div);
}
typeof returns the type of what ever is passed to it. A function is an object ((function () {}) instanceof Object === true), but the typeof function is defined to return "function" when an Object implements [[Call]] in ECMA-262 is supplied to it.
Functions are objects, but typeof treats them as a special case.

Is it not possible to set arguments that have not been provided, using arguments property

I was testing things. And discovered that i could not set arguments if i have not provided it.
Using arguments[1] etc.
Example:
function abc (a,b) {
arguments[1] = 'new value';
console.log(b);
}
abc('a');
It won't work.
I know i could set value like if (b=='undefined') b='default'; but why i can't like this. In other words this behavior is unexpected, isn't it?
On the other hand, if you do provide argument it will get changed!
calling function like this will output new value
abc('a','b');
is there a solution, if you wanted to set value using arguments[2] and pass argument when calling function.
after more testing it seems: b doesnt get connected with arguments[1] if not called.
My understanding is argument is dynamic whose length is set by number of arguments / parameters provided to the function.
In first case, you have provided only one parameter so size of argument is 1 and hence argument[1] should be out of bound, while in second case, you have argument of length 2 so you can change either parameter value by using its index.
After posting a terribly wrong answer, I took a look at the ECMA Spec and here is in code, what JavaScript does when the arguments object will be created:
function abc () {
var names = ["a", "b"]; //as normally provided in the function declaration: function (a, b)
var a, b;
var args = {};
var mappedNames = [];
args.length = arguments.length;
var index = args.length - 1;
//this is the crucial part. This loop adds properties to the arguments object
//and creates getter and setter functions to bind the arguments properties to the local variables
//BUT: the loop only runs for the arguments that are actually passed.
while (index >= 0) {
var val = arguments[index];
if (index < names.length) {
var name = names[index];
if (mappedNames.indexOf(name) === -1) {
mappedNames.push(name);
var g = MakeArgGetter(name);
var p = MakeArgSetter(name);
Object.defineProperty(args, index.toString(), {get : g, set : p, configurable : true});
}
}
args[index.toString()] = val;
index--;
}
function MakeArgGetter(name) {
return function zz(){
return eval(name);
};
}
function MakeArgSetter(name) {
return function tt(value) {
eval(name + " = value;");
};
}
console.log(args[0]); //ab
args[0] = "hello";
args[1] = "hello";
console.log(a); //hello
console.log(b); //undefined
}
abc('ab');
Note, that there is some more going on in the Spec and I simplyfied it here and there, but this is essentially what is happening.
What are you trying to achieve by this?
If you want to have "dynamic arguments" like abc('a) and abc('a', 'b') are both valid, but the first will set the missing argument to a default value, you either have to check for the arguments length and/or for all arguments values.
Suppose the following: abc('a', null) is given, what then? - depends on logic, can be good but can also be bad.
Given this, checking the argument vector isn't smarter but more cryptic and having something like if (b=='undefined') b='default' much straighter and better to understand.
TL;DR: Not possible per ECMA spec since arguments is binded to only formal parameters that match the provided arguments. Its recommended to only reference arguments and not alter it.
Examples: http://jsfiddle.net/MattLo/73WfA/2/
About Arguments
The non-strict arguments object is a bidirectional and mapped object to FormalParameterList, which is a list generated based on the number of provided arguments that map to defined parameters in the target function defintion/expression.
When control enters an execution context for function code, an arguments object is created unless (as specified in 10.5) the identifier arguments occurs as an Identifier in the function’s FormalParameterList or occurs as the Identifier of a VariableDeclaration or FunctionDeclaration contained in the function code. ECMA 5.1 spec (as of 03/26/2014)
arguments to variables / variables to arguments
Argument-to-variable mappings exist only internally when the method is invoked. Mappings are immutable and are created when a target function is invoked, per instance. The update bindings between the two is also disabled when the use strict flag is available within the scope of the function. arguments becomes strictly a reference and no longer a way to update parameters.
For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. This correspondence is broken if such a property is deleted and then redefined or if the property is changed into an accessor property. For strict mode functions, the values of the arguments object‘s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values. ECMA 5.1 spec (as of 03/26/2014)
What about length?
arguments.length can be an indicator initially to determine how many formal parameters were met but it's unsafe since arguments can be changed without length ever updating automatically. length doesn't update because it's not a real array and therefore doesn't adhere to the Array spec.

JavaScript Object instantiation

Sometimes I'll see code like this:
var Obj = Obj || {};
What does this do? I have had success writing
array = array || [];
To instantiate an array if it hasn't already been instantiated, however I would like to know a bit more about the mechanics of this.
The technique tries to make use of something called short circuit evaluation... but it's tricky in Javascript, and turns out to be quite dangerous if you try to make use of it for Object instantiation.
The theory behind short circuit evaluation is that an OR statement is only evaluated up to the first true value. So the second half of an OR statement is not evaluated if the first half is true. This applies to Javascript......
But, the peculiarities of Javascript, in particular how undeclared variables are handled, make this a technique that has to be used with great care to instantiate objects.
The following code creates an empty object except if Obj was previously declared in the same scope:
var Obj = Obj || {}; // Obj will now be {}, unless Obj was previously defined
// in this scope function.... that's not very useful...
This is because after var Obj, Obj will be undefined unless it was declared in the same scope (including being declared as a parameter to the function, if any).... so {} will be evaluated. (Link to an explanation of var provided in the comments by T.J. Crowder).
The following code creates an empty object only if Obj has been previously declared and is now falsy:
Obj = Obj || {}; // Better make sure Obj has been previously declared.
If the above line is used when Obj has not been previously declared, there will be a runtime error, and the script will stop!
For example this Javascript will not evaluate at all:
(function() {
Obj = Obj || "no Obj"; // error since Obj is undeclared JS cannot read from
alert(Obj);​ // an undeclared variable. (declared variables CAN
})(); // be undefined.... for example "var Obj;" creates
// a declared but undefined variable. JS CAN try
// and read a declared but undefined variable)
jsFiddle example
But this Javascript will always set Obj to "no Obj"!
var Obj ="I'm here!";
(function() {
var Obj = Obj || "no Obj"; // Obj becomes undefined after "var Obj"...
alert(Obj); // Output: "no Obj"
})();​
jsFiddle example
So using this type of short circuit evaluation in Javascript is dangerous, since you can usually only use it in the form
Obj = Obj || {};
Which will fail precisely when you would most want it to work... in the case where Obj is undeclared.
Note: I mention this in the comments of the penultimate example, but it's important to understand the 2 reasons that a variable can be undefined in Javascript.
A variable can be undefined because it was never declared.
A variable can be undefined because it was declared but has not had a value assigned to it.
A variable can be declared using the var keyword. Assigning a value to an undeclared variable creates the variable.
Trying to use an undefined variable that is also undeclared causes a runtime error. Using an undefined variable that has been declared is perfectly legal. This difference is what makes using Obj = Obj || {}; so tricky, since there is no meaningful form of the previous statement if Obj is either undeclared OR it is a previously existing variable.
The mechanics are a bit unusual: Unlike most languages, JavaScript's || operator does not return true or false. Instead, it returns the first "truthy" value or the right-hand value. So for instance:
alert("a" || "b"); // alerts "a", because non-blank strings are "truthy"
alert(undefined || "b") // alerts "b", because undefined is falsey
alert(undefined || false || 0); // alerts "0", because while all are falsy, 0 is rightmost
More in this blog post.
As Darin said, your var Obj = Obj || {}; is probably not a literal quote, more likely something like this:
function foo(param) {
param = param || {};
}
...which means, "if the caller didn't give me something truthy for param, use an object."
var Obj = Obj || {};
I think that the var here is not necessary. It should be:
Obj = Obj || {};
Where Obj is defined elsewhere. This will simply assign Obj to an empty object if it is null or leave as is of not. You might also leave the var keyword in which case it will ensure that the object is declared even if it wasn't before this statement.
Same for the array: if it is null it will assign it to an empty array.
The key to understanding this syntax is that the result of a boolean or (or and) expression in JavaScript is the last-evaluated component. As has been pointed out by other commenters, JavaScript's shortcircuiting is being used along with this feature to conditionally set the value of array or Obj.
Obj = Obj || {};
This means Obj is set to the value of the expression Obj || {}. If Obj is "true", meaning it evaluates to true (for an object, this means it exists), the result of the expression is Obj, because the expression short-circuits. However, if Obj is "false" (non-existent), the second part of the expression must be evaluated. Therefore, in that case, the value of the expression is {}.

Categories

Resources