When Does Js Interpret {} as an Empty Block Instead of an Empty Object

When does JS interpret {} as an empty block instead of an empty object?

Let's look at the language grammar, shall we? Section 12, Statements:

Statement :
Block
VariableStatement
EmptyStatement
ExpressionStatement
...lots of other stuff...

That's a very fancy way of saying that a statement can be a block, a variable statement, an empty statement, an expression statement, or lots of other stuff. Notice that the first option there is a 'Block':

Block :
{ StatementList(opt) }

StatementList :
Statement
StatementList Statement

Which is again, a fancy way of saying that a block is a {, optionally followed by a bunch of statements, followed by a }.

And that's what you see in your example: Before the JavaScript parser thinks that what you have could be an object literal (which is defined somewhere under ExpressionStatement, the 4th thing a 'Statement' could be), it first thinks that you have a 'Block'.

Edit: If you want, you can see it live in a JavaScript engine's source code:

  • In V8, Chrome's JavaScript engine, we go into Parser::ParseStatement. The first thing it checks is whether we're on a {, and if it does, parses as block.
  • In SpiderMonkey, Firefox's JavaScript engine, we go from Parser::statement to again see the first check being against a { and parsing it as a block statement.

Regarding your second question, that's been covered to great detail on this question. To summarise in a sentence: Node.js treats your input as if it were an expression (thus it can't be a 'Block'), while Firebug/Chrome dev tools treat it like a 'Statement'.

Why is the ![] == {} and {} == ![] result is different

The root of the problem is that {} got two meanings in JS:

{ let a = 1; } is a block statement

{ a: 1 } is an object literal expression

it will choose which to take wether it expects an expression or a statement. In your case, it is in a statement context, so {} is treated as a block statement, and therefore throws an error.

Now you could ask "Why does it accept {} == {} though?"

Well that's because your console sometimes evaluates the entered code as an expression and sometimes as a statement. I'ts rule is basically: If the code starts with { and ends with } it is parsed as an expression (it is wrapped in ( ). So when you type:

 { a: 1 }

that would actually be a SyntaxError in JS, as : is not defined inside a block statement, therefore the console is so nice to wrap it as:

({ a: 1})

the same happens with

{} == {}
// wrapped as
({} == {})

but this:

{} == []

does not fullfill the condition, the whole thing gets treated as a statement, {} is treated as a block statement.

Is object empty?

I'm assuming that by empty you mean "has no properties of its own".

// Speed up calls to hasOwnProperty
var hasOwnProperty = Object.prototype.hasOwnProperty;

function isEmpty(obj) {

// null and undefined are "empty"
if (obj == null) return true;

// Assume if it has a length property with a non-zero value
// that that property is correct.
if (obj.length > 0) return false;
if (obj.length === 0) return true;

// If it isn't an object at this point
// it is empty, but it can't be anything *but* empty
// Is it empty? Depends on your application.
if (typeof obj !== "object") return true;

// Otherwise, does it have any properties of its own?
// Note that this doesn't handle
// toString and valueOf enumeration bugs in IE < 9
for (var key in obj) {
if (hasOwnProperty.call(obj, key)) return false;
}

return true;
}

Examples:

isEmpty(""), // true
isEmpty(33), // true (arguably could be a TypeError)
isEmpty([]), // true
isEmpty({}), // true
isEmpty({length: 0, custom_property: []}), // true

isEmpty("Hello"), // false
isEmpty([1,2,3]), // false
isEmpty({test: 1}), // false
isEmpty({length: 3, custom_property: [1,2,3]}) // false

If you only need to handle ECMAScript5 browsers, you can use Object.getOwnPropertyNames instead of the hasOwnProperty loop:

if (Object.getOwnPropertyNames(obj).length > 0) return false;

This will ensure that even if the object only has non-enumerable properties isEmpty will still give you the correct results.

{} - 0 VS ({} - 0) in JavaScript

There are two possible interpretations of the line {} - 0:

  1. It can be interpreted as {}; -0, where {} is interpreted as an empty block statement, and - is the unary negation operator (so -0 is just "negative zero"). The value of this when evaluated is the value of the last statement, which is -0.
  2. It can be interpreted as ({} - 0), where {} is interpreted as an empty object, and - is the subtraction operator (so 0 is subtracted from {}).

In your first line, this is ambiguous, so it will choose the first interpretation. In the second line, the first interpretation is invalid (as a block statement can never be part of an expression, which you're forcing with the parantheses).

Why show object object when input ({} + {}) in Javascript?

When you write {} in some ways, if what the "duplicate" answer says is correct, it might be interpreted as a code block instead of an empty object. The empty block has no return statement, so it returns undefined.

undefined + undefined returns NaN because it tries to do a mathematical addition between two values that are not numbers. When you write {} + {} but don't do anything with the result, Chrome again evaluates the + as the addition and both {} as undefined.

However, as soon as you actually do something with the result, the behavior is different because the browser understands that you're using the implicit object declaration syntax. If you do say, var x = {} + {}, Chrome creates two objects and tries to convert them into a value that can be used with the + operator. So it converts the objects into string representations and concatenates the strings together.

The same thing happens when you use parentheses, because blocks can't exist inside parenthesis like that, so it can't mistake the {} for an empty block.

PS: I had it wrong at first and I'm just taking what I read on that other answer now.



Related Topics



Leave a reply



Submit