I was reading about the ternary operator in different languages, and noticed something interesting in the Javascript section. http://en.wikipedia.org/wiki/%3F:#JavaScript
The conditional operator in JavaScript has the same syntax and precedence structure as in the other BCPL-derived variants, but a significant difference exists in the semantics: it returns an l-value.
The first sentence states that the return of the ternary in javascript is an lvalue, so I tried some examples, with odd results (in the chrome console).
Given:
var a = { 'yo' : 'momma' }
var b = { 'yo' : 'cool' }
var bool = true
(bool? a : b).yo = 'LLJ'
//a is now { 'yo' : 'LLJ' }
(bool? a.yo : b.yo) = 'LLJ' //throws a reference error
Why does the first work and the second fail? (Logically they're the same statements, no?)
Nope (it seems that Wikipedia's reference to "l-value" is misleading) - it is returning the value of the argument, not the reference to it; values in JavaScript cannot be assigned to directly1.
If you just did the following:
console.log(bool ? a.yo : b.yo);
// like doing the following:
'string' = 'eee';
... you would get a string - you can't assign to a string value/literal. All property references are converted to their value when passed into the conditional operator.
However, with an object, the reference value is an object, and since the property of an object is a reference, it works fine.
console.log(bool ? a : b); // you get an object, it's fine
The ECMAScript specification (that's the standard version of JavaScript) says that you can't get references (i.e. a l-value) from the conditional operator:
11.12 Conditional Operator ( ? : )
Let lref be the result of evaluating LogicalORExpression.
If ToBoolean(GetValue(lref)) is true, then:
Let trueRef be the result of evaluating the first AssignmentExpression.
Return GetValue(trueRef).
Else
Let falseRef be the result of evaluating the second AssignmentExpression.
Return GetValue(falseRef).
GetValue is an internal function that converts a reference to a value, therefore that's why you get a value, not a reference as you expected.
1: The internal assignment method in ECMAScript does not allow non-references to be assigned to:
8.7.2 PutValue (V, W)
If Type(V) is not Reference, throw a ReferenceError exception.
... (the rest is unimportant, my emphasis)
Wikipedia was wrong. The conditional operator returns an r-value, not an l-value.
The history of the article is quite interesting, so I've summarised it here:
30 August 2010: The Beginning
JavaScript section created. Correctly says that in JavaScript the ternary operator returns an r-value, but incorrectly says that in C/C++/Java it returns an l-value. Only in C++ the ternary operator returns an l-value.
31 January 2011: Cannot yield an l-value in C
C correctly removed from the JavaScript section because it doesn't return an l-value. Java remains.
15 February 2011: "Corrected"
The comparison to Java and C++ is removed (the comment correctly says that Java never yielded an l-value), but oh no! JavaScript suddenly returns an l-value!
7 March 2011: Hope is restored...
The incorrect "l-value" is changed to "value", linking to the Value article (which describes both l-values and r-values).
7 March 2011: ...but not for long
The link text is changed to say "l-value".
7 September 2013: Three cheers for Qantas 94 Heavy!
Thanks to this question, Wikipedia has been corrected.
Because the second line is not referencing the value of a.yo or b.yo, its referencing a flat object.
The first expression ends with .yo so it knows to reference the value of either a or b.
Has to do with how the js is actually implemented i guess...
But consider this..
(bool ? a: b) give a so the code becomes a.yo = 'LLJ', which is valid..
(bool ? a.yo : b.yo) gives what ever the string a.yo is holding. Essentially you're doing
'moma' = 'LLJ' which is invalid.
Here d becomes your set variable.
var obj = {'d' : 1, 'd1': 2}, obj2 = {'d': 2, 'd1': 2}, bool = true;
var dummyFn = function(obj, k, v) { obj['k'] = val; return obj; };
(bool ? (dummyFn(obj, 'd', (obj.d = newVal + 1))) : obj).d1 = newVal = 4;
console.log(obj.d);
The reason the code didn't work would be the same reason you can't replace dummyFn's value
with obj. Without a property to reference the object becomes anonymous.
Related
In javascript, there is a symbolic property known as Symbol.toprimitive, which have function value, am I right?
If so, then in this method, the first word (ie. Symbol) is an system symbol?
And when we call this method, is there a formation of temporary object as we are creating property for a value that is primitive (symbol), of which value is an method?
And third confusion is in this method (ie. [Symbol.toprimitive] (hint), how the parameter hint knowns that hint should be "string" or "number" or "default" , I mean I know the rules but from where this parameter gets its value?
Thanks for your valuable answer :)
...there is a symbolic property known as Symbol.toprimitive, which have function value, am I right?
No, Symbol.toPrimitive is a Symbol, not a function. It's used as the key of an object property whose value should be a function, but it's a Symbol.
...then in this method, the first word (ie. Symbol) is an system symbol?
It's the Symbol global object, which is a container for "well-known symbols" used for various purposes in JavaScript code.
And when we call this method, is there a formation of temporary object as we are creating property for a value that is primitive (symbol), of which value is an method?
Symbol.toPrimitive is not a method, so the question doesn't come up.
And third confusion is in this method (ie. [Symbol.toprimitive] (hint), how the parameter hint knowns that hint should be "string" or "number" or "default" , I mean I know the rules but from where this parameter gets its value?
The value of the hint is built into the places in the JavaScript specification that call the function. For example, the unary - operator uses ToNumeric on its operand, which uses ToPrimitive, passing in the "hint" that it wants a number. ToPrimitive is what passes the "number" hint to the [Symbol.toPrimitive] (aka ##toPrimitive) method of the object.
Let's consider a simple example, which should help you understand things a bit more:
// An object with its own Symbol.toPrimitive property
// referring to a function that implements the behavior
// we want for this object
const obj = {
[Symbol.toPrimitive](hint) {
console.log(`The hint is ${hint}`);
return hint === "number" ? 42 : "forty-two";
}
};
// `-` uses ToNumeric which uses ToPrimitive asking for a
// number if possible
let x = 4 - obj;
console.log(`x = ${x}`);
// In contrast, string concatenation doesn't have a preference
let y = "" + obj;
console.log(`y = ${y}`);
// But the String function, which always wants to get a
// string if it can, asks for a string
let z = String(obj);
console.log(`z = ${z}`);
Asking this question I want to evaluate the following statement true or false:
"There are methods built-in to every data type in JavaScript"
As undefined in data type in JavaScript. I try to find any build-in method for an "undefined" but it appears that it's an only primitive type that does not have one. Or there are some?
let undef = void 0;
console.log(undef.anyPotentialBuildInMethod());
Does any "anyPotentialBuildInMethod()" exists?
Methods are functions that are properties of objects.
Trying to read any property of undefined throws an exception.
undefined has no built-in methods and cannot be assigned any.
const foo = undefined;
console.log(foo.sampleMethod);
While it might appear so, not everything in Javascript is an object. Primitive values (like "foo", 12.34, undefined etc) are not objects and cannot have methods or properties. However, Javascript hides that fact by dynamically boxing (or "coercing") primitive values into objects when you access their properties. So when you do
x = "foo".length
what actually happens is
1. temp = new String("foo") // dynamically coerce a primitive value into an object
2. x = temp.length // get a property of that object
3. destroy temp // delete a temporary object
(Of course, Javascript engines don't actually allocate and then discard these temporary objects, this is just an algorithm defined by the standard, see (1) below).
Two primitive values: null and undefined are exception of this rule: any attempt to coerce them results in a TypeError. So when you do
x = undefined.something
Javascript tries to create a temporary object like in the step 1 above and fails.
The bottom line: null and undefined cannot have properties, because they are primitive values and cannot be converted to objects.
References:
https://262.ecma-international.org/11.0/#sec-getvalue
https://262.ecma-international.org/11.0/#sec-evaluate-property-access-with-identifier-key
https://262.ecma-international.org/11.0/#sec-requireobjectcoercible
No, property access on undefined always throws a TypeError in a standards-compliant engine.
From ECMA-262, 11th Ed., §12.3.2.1:
MemberExpression : MemberExpression [ Expression ]
[…]
Return ? EvaluatePropertyAccessWithExpressionKey(baseValue, Expression, strict).
[…]
MemberExpression : MemberExpression . IdentifierName
[…]
Return ? EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict).
In both §12.3.3 and §12.3.4 have:
Let bv be ? RequireObjectCoercible(baseValue).
And in §7.2.1 we have:
The abstract operation RequireObjectCoercible throws an error if argument is a value that cannot be converted to an Object using ToObject. It is defined by Table 15:
Table 15: RequireObjectCoercible Results
Argument Type
Result
Undefined
Throw a TypeError exception.
Null
Throw a TypeError exception.
The only thing that can possibly be considered an exception is the document.all object, which compares loosely-equal (== not ===) to both undefined and null, and returns 'undefined' when passed to the typeof operator, but actually has properties. This is specified in §B.3.7; before the 9th edition of the standard, it was actually contrary to the specification.
I'm not sure of the reason why you are asking this, but, to let you understand better, what you are trying to do is like trying (but not the same) to find an 'x' value so that (0 * x) != 0; 0 is 0 and whethever you use as 'x' you got 0.
And 'undefined' var in javascript is nothing. This is because 'var' doesn't have a type, it can be string, integer, object, function ecc
you can do
var test = "test";
console.log(test);
test = 1;
console.log(test);
and so on, and you'll get no error. var are evauated at execution time, and and undefined var is simply a pointer to nothing so you can't have a function or a property in that
This question already has answers here:
Javascript: || instead of IF statement - is this legal and cross browser valid?
(10 answers)
Closed 6 years ago.
So I'm reading Airbnb's JS styleguide and I don't understand what the OR operator is doing in the following example. More specifically in the Jedy constructor options || (options = {}); Is basically creating an empty object if no arguments were passed to the constructor? Therefore, the name property of the Jedi constructor would be set to 'no name'?
function Jedi(options) {
options || (options = {});
this.name = options.name || 'no name';
}
Jedi.prototype.getName = function getName() {
return this.name;
};
Jedi.prototype.toString = function toString() {
return 'Jedi - ' + this.getName();
};
PS. It seems like there are a lot shorthand ways of doing things with JS. Are there any good resources or articles explaining what these are and when it's best to use them?
The || operator takes two arguments. If the first argument is a "truthy" value, it returns the first argument; otherwise, it returns the second. It also short-circuits; that is, if the first argument is truthy it does not evaluate the second. If the second argument is an expression with side effects, this can be very significant.
The statement options || (options = {}); relies on this. If options is truthy, then the assignment expression will not be evaluated. If it is falsy, then the second expression will be evaluated.
Now, this is functional equivalent to the statement options = options || {};. In theory, that statement could be slightly slower, because it will assign options to itself rather than simply not assigning anything. However, the effect of this is negligible.
Js logical operators return not true or false, but truly or falsy value itself. For example in expression x && y, if x is falsy, then it will be returned, otherwise y will be returned. So the truth table for operator is correct.
The same for ||. It's a good way for specifying function default values.
You will often find this code in JavaScript plugins it basically means if an object with name options does not exists create a new one
If you try to access a property on options like
options.name and options does not exists then it will give you an error that options is undefined.But with this options || (options = {}) code you can always ensure that the JavaScript Object you are accessing always exists.
I will check if I could provide you some links for this to read about.
This is a good supporting link
How can I create an empty namespace object without overwriting another object with the same name?
seems like this is a more concise way of checking that the object exists and assigning it the value of an empty object if it does not. It isn't all that clear though. A little clearer implementation would be
var options = options || {};
even better, use es2015 default parameters
function Jedi(options = {}) {
this.name = options.name || 'no name';
}
In many (most) programming languages, at runtime unnecessary executions are optimized away. ||binary operator returns true if either of its operands evaluate to true. Since both the operands are serially evaluated, if the first one evaluates to true, the outcome of || operator is going to be true. so the second operand need not be evaluated. If the first one returns false, then second one decides what the result of || operator is going to be. this is the behavior that is being exploited here.
if options is set to non null value, it will evaluate to true. So don't execute the second operand which initializes it to empty object. on the next line if options.name is not null, then initialize it to 'no name'
{}[true] is [true] and ![true] should be false.
So why does !{}[true] evaluate to true?
I believe that's because plain {}[true] is parsed as an empty statement block (not an object literal) followed by an array containing true, which is true.
On the other hand, applying the ! operator makes the parser interpret {} as an object literal, so the following {}[true] becomes a member access that returns undefined, and !{}[true] is indeed true (as !undefined is true).
Because {}[true] does not return true, but undefined, and undefined is evaluated as false:
http://jsfiddle.net/67GEu/
'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true
Because
{}[true]
evaluates to undefined, and !undefined is true.
From #schlingel:
true is used as key and {} as hash map. There doesn't exist an property with the key true so it returns undefined. Not undefined is true, as expected.
Console session (Node.js [0.10.17]):
> {}[true]
undefined
> !{}[true]
true
> [true]
[ true ]
> ![true]
false
>
However, in the Google Chrome console:
> !{}[true]
true
So, no inconsistencies. You're probably using an old version of the JavaScript VM. For those who need further evidence:
UPDATE
With Firefox, it also evaluates to true:
The reason for the confusion is down to a misunderstanding of your first assertion:
{}[true] is [true]
What you're seeing when you run it is the result of an ambiguity. Javascript has a defined set of rules as to how to handle ambiguities like this, and in this case, it breaks what you see as a signle statement down into two separate statements.
So Javascript sees the above code as two separate statements: Firstly, there is a {}, and then there is an entirely separate [true]. The second statement is what is giving you the result [true]. The first statement {} is effetively entirely ignored.
You can prove this by trying the following:
({}[true])
ie wrapping the whole thing in brackets to force the interpreter to read it as a single statement.
Now you'll see that the actual value of your statement is undefined. (this will also help us later to understand the next part)
Now we know that the initial part of your question is a red herring, so let's move onto the final part of the question:
So why does !{}[true] evaluate to true?
Here, we have the same statement, but with a ! appended to the front of it.
In this case, Javascript's rules tell it to evaluates the entire thing as a single statement.
Refer back to what happened when we wrapped the earlier statement in brackets; we got undefined. This time, we are effectively doing the same thing, but putting a ! in front of it. So your code can be simplified as !undefined, which is true.
Hopefully that explains it a bit.
It is a complex beast, but the lesson to learn here is to use brackets around your statements when evaluating them in the console, to avoid spurious results like this.
{}[true] is undefined. To find that write this:
a = {};
a[true] === undefined // true
or simply:
({})[true] === undefined // true
We know that !undefined is true.
From #Benjamin Gruenbaum's answer:
Chrome dveloper tools does the following:
try {
if (injectCommandLineAPI && inspectedWindow.console) {
inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
}
var result = evalFunction.call(object, expression);
if (objectGroup === "console")
this._lastResult = result;
return result;
}
finally {
if (injectCommandLineAPI && inspectedWindow.console)
delete inspectedWindow.console._commandLineAPI;
}
So basically, it performs a call on the object with the expression. The expression being:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
So, as you can see, the expression is being evaluted directly, without the wrapping parenthesis.
More information can be found in this question.
The answers here are good, here's a breakdown in pseudo-code:
{}['whatever'] = empty block, NewArray('whatever') = NewArray('whatever')
{}[true] = empty block, NewArray(true) = NewArray(true)
!{}['whatever'] = LogicalNOT(convertToBool(NewObject.whatever)) = LogicalNOT(convertToBool(undefined)) = LogicalNOT(false) = true
({}['whatever']) = Grouping(NewObject.whatever) = Grouping(undefined) = undefined
This happens because {} in your meaning is not literal presentation of Object, but empty scope ( or empty code block ):
{ var a = 1 }[true] // [true] (do the same thing)
It just evaluates code inside scope and then shows you your array.
And from your
!{}[true]
Just converts to int this scope and return same array true. There is no bool checks in this code.
And if you will try to check result from {}[true] you will get your false:
{}[true] -> [true] -> ![true] -> false
As there is no more any scope.
So ! in your question do the same as:
!function() {
//...
}
{} is an object with no properties.
Since [] immediately follows an object, it means "Access a property of this name" and not "Create an array"
true is a boolean, but is being used as an property name so it is cast to a string ("true")
The object does not have a property called true (since it has no properties) so {}['true'] is undefined
!undefined casts undefined to a boolean (false)
The not operator turns false into true.
You're not reversing the value of it.
![true] != [!true]
Check this out: Why is !true ? 'false' : 'true' returning 'true'?
Let's Play a Little More!
First, let's have some fun!:
//----------#01#-----------
{}[true]; //[true]
//----------#02#-----------
var a = {}[true];
console.log(a); //undefined
//----------#03#-----------
{ b: 12345 }[true]; //[true]
//----------#04#-----------
{ b: 12345 }["b"]; //evaluates to ["b"] ?!?
//----------#05#-----------
{ b: 12345 }.b; // "Unexpected token ."
//----------#06#-----------
({ b: 12345 }).b; //12345
//----------#07#-----------
var c = { b: 12345 }.b;
console.log(c); //12345
//----------#08#-----------
var c = { b: 12345 }["b"];
console.log(c); //12345
//----------#09#-----------
{ true: 54321 }[true]; // "SyntaxError: Unexpected token : "
//----------#10#-----------
var d = { true: 54321 }[true]; //No error here ¬¬
console.log(d); //54321
//----------#11#-----------
!{}[true]; // true
Ok, let's try to understand these crazy behaviors, one by one:
1) Here, the {} is parsed as an empty code block. Without an assign, negation, grouping (with parentheses) or any syntax which indicates to the parser that this {} is an object literal, the default assumption is to think it is simply a useless empty block.
This is a proof of this behavior:
{ alert(123) }[true]
The code above will show the alert normally, and will be evaluated as [true], in the same way {}[true] is.
Block Statements Without Semicolons
A block-type statement doesn't need a semicolon after it.
For instance:
for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")
Both alerts are shown.
So, we can see that an empty block statement, without a semicolon, is valid and simply does nothing. This way, when you enter {}[true] in the Developer Tools (or Firebug) Console, the evaluated value will be the value of the last expression statement. In this case, the last expression statement is [true].
2) In an assignment context, the parser will make sure that {} is an object literal. When you do var a = {}[true], you remove any ambiguity and tip the parser off that {} is not a block statement.
So, here, you're trying to get a value with a key "true" from an empty object. Obviously, there's no key-value pair with this key name. This way, the a variable is undefined.
Reserved words as Object keys
ECMAScript 5 allows object keys to be reserved words. So, the following keys are legal:
var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}
3) The same explanation of example 1. But...
If the { b: 12345 } part is treated as a block statement, what's the type of the b: 12345 statement??
... (?????)
It's a label statement, you already saw it before... It's used in loops and in switch. Here are a few interesting links about label statements: 1, (2)[Best way to break from nested loops in Javascript?, (3)[How to break nested loops in javascript?.
NOTE: Just try to evaluate this:
{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :
Label statements can't be separeted by the comma operator, you would need to separate them with a semicolon. So this is valid: {a: 1; b: 2}
4) See the explanations for the examples 1 and 3...
5) One more time, we have a { b: 12345 } being treated as a code block, and you're trying to access a property of a code block by using the dot notation, and obviously, this is not allowed, and the parser throws an "Unexpected token :" exception.
6) The code is almost identical to the above example, but by surrounding the { b: 12345 } statement with the expression grouping operator, the parser will know that is an object. This way, you'll be able to access the "b" property normally.
7) Remember the example 2, we have an assignment here, the parser knows that { b: 12345 } is an object.
8) Identical to the above example, but instead of the dot notation, here we're using the bracket notation.
9) I already said that this "identifier: value" syntax inside a block statement is a label. But, you also have to know that a label name can't be a reserved keyword (the opposite of object property names). When we tried to define a label called "true", we got a SyntaxError.
10) Again, we're dealing with an object. No problems using reserved words here. =)
11) Finally, we have this: !{}[true]
Let's separate the things here:
a) By doing a negation, we're informing to the parser that the {} is an object.
b) As shown in the example 2, a {} object doesn't have a property called true, so this expression will evaluate to undefined.
c) The final result is the negation of undefined value. Javascript performs implicity type conversion, and undefined value is falsy.
d) So, the negation of false is... true!
I found three ways to cast a variable to String in JavaScript.
I searched for those three options in the jQuery source code, and they are all in use.
I would like to know if there are any differences between them:
value.toString()
String(value)
value + ""
DEMO
They all produce the same output, but does one of them better than the others?
I would say the + "" has an advantage that it saves some characters, but that's not that big advantage, anything else?
They do behave differently when the value is null.
null.toString() throws an error - Cannot call method 'toString' of null
String(null) returns - "null"
null + "" also returns - "null"
Very similar behaviour happens if value is undefined (see jbabey's answer).
Other than that, there is a negligible performance difference, which, unless you're using them in huge loops, isn't worth worrying about.
There are differences, but they are probably not relevant to your question. For example, the toString prototype does not exist on undefined variables, but you can cast undefined to a string using the other two methods:
var foo;
var myString1 = String(foo); // "undefined" as a string
var myString2 = foo + ''; // "undefined" as a string
var myString3 = foo.toString(); // throws an exception
http://jsfiddle.net/f8YwA/
They behave the same but toString also provides a way to convert a number binary, octal, or hexadecimal strings:
Example:
var a = (50274).toString(16) // "c462"
var b = (76).toString(8) // "114"
var c = (7623).toString(36) // "5vr"
var d = (100).toString(2) // "1100100"
In addition to all the above, one should note that, for a defined value v:
String(v) calls v.toString()
'' + v calls v.valueOf() prior to any other type cast
So we could do something like:
var mixin = {
valueOf: function () { return false },
toString: function () { return 'true' }
};
mixin === false; // false
mixin == false; // true
'' + mixin; // "false"
String(mixin) // "true"
Tested in FF 34.0 and Node 0.10
According to this JSPerf test, they differ in speed. But unless you're going to use them in huge amounts, any of them should perform fine.
For completeness: As asawyer already mentioned, you can also use the .toString() method.
if you are ok with null, undefined, NaN, 0, and false all casting to '' then (s ? s+'' : '') is faster.
see http://jsperf.com/cast-to-string/8
note - there are significant differences across browsers at this time.
Real world example: I've got a log function that can be called with an arbitrary number of parameters: log("foo is {} and bar is {}", param1, param2). If a DEBUG flag is set to true, the brackets get replaced by the given parameters and the string is passed to console.log(msg). Parameters can and will be Strings, Numbers and whatever may be returned by JSON / AJAX calls, maybe even null.
arguments[i].toString() is not an option, because of possible null values (see Connell Watkins answer)
JSLint will complain about arguments[i] + "". This may or may not influence a decision on what to use. Some folks strictly adhere to JSLint.
In some browsers, concatenating empty strings is a little faster than using string function or string constructor (see JSPerf test in Sammys S. answer). In Opera 12 and Firefox 19, concatenating empty strings is rediculously faster (95% in Firefox 19) - or at least JSPerf says so.
On this page you can test the performance of each method yourself :)
http://jsperf.com/cast-to-string/2
here, on all machines and browsers, ' "" + str ' is the fastest one, (String)str is the slowest