Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Motive behind strict mode syntax error when deleting an unqualified identifier?

I'm having trouble understanding why, in strict mode, a syntax error occurs when delete is used on an unqualified identifier.

In most cases, it makes sense... if you are declaring variables in the usual way with the var keyword, and then trying to use delete on them, in non-strict mode it would silently fail, so it makes sense for strict mode to fail with an error in those cases.

However, there are cases where you can't delete identifiers that are qualified:

(function() {

  // "use strict";

  var obj = Object.create({}, { bloop: { configurable: false } });

  delete obj.bloop; // throws TypeError in strict mode, silently fails in non-strict.

  console.log('bloop' in obj); // true

}());

Strict mode must do a runtime check here, because a TypeError is thrown when this is encountered. There are also cases where you can successfully delete unqualified identifiers in non-strict mode...

// "use strict";

window.bar = 6;

console.log(typeof bar); // number

delete bar; // works in non-strict, syntax error in strict!

console.log(typeof bar); // undefined

In fact, to my understanding, whether or not you can delete things (in non-strict mode) depends on the internal [[Configurable]] property, and has nothing to do with qualified identifiers. As far as I can tell, there is no way in strict mode to delete non-global variables that (as properties of the local VO) are configurable:

(function() {

  // "use strict";

  eval('var foo = 5;');

  console.log(typeof foo); // number

  delete foo; // works in non-strict, SyntaxError in strict.

  console.log(typeof foo); // undefined

}());

So, my question is, what's the point of throwing a SyntaxError when using delete on an unqualified identifier, when the TypeError would throw anyway if the property is not configurable? This seems like an unnecessary restriction, and in some cases there doesn't seem to be any workaround other than not using strict mode (third example). Can anyone explain the motivation behind this decision?


Update: I just realized that I was overlooking the fact that direct eval calls have their own scope in strict mode, instead of the calling function's scope, so in the third example foo would not be defined under strict mode. Anyway, the runtime check would still catch this, but it raises a side question: Is there no way to have configurable local variables in strict mode, as we do with eval'd variable declarations in non-strict? AFAIK that was one of the few legitimate uses of eval.

like image 488
Dagg Nabbit Avatar asked May 17 '12 21:05

Dagg Nabbit


2 Answers

You are talking about Section 11.4.1, paragraph 5.a. of the specs:

  1. Else, ref is a Reference to an Environment Record binding, so
    a. If IsStrictReference(ref) is true, throw a SyntaxError exception.
    b. Let bindings be GetBase(ref).
    c. Return the result of calling the DeleteBinding concrete method of bindings, providing GetReferencedName(ref) as the argument.

What you called "unqualified identifiers" is officially named "Environment Record binding".

Now, to your question. Why throw a SyntaxError when 5.c. would fail anyway? I think you answered it yourself!

Strict mode must do a runtime check here, because a TypeError is thrown when this is encountered.

That's right. But it's always better to fail fast. So, when there is a chance of detecting a SyntaxError (at parse time), that opportunity should be taken.

Why? It saves you the trouble of fixing your app if an error occurs. Think about IDEs that may show you the error right away, as opposed to hours of debugging.
Also, such restrictions may be advantageous for optimized JIT compilers.

like image 163
user123444555621 Avatar answered Sep 20 '22 17:09

user123444555621


If you want to delete object in strict mode. You have to explicitly mention about the property access. Also note that, how you call the function is important. If new operator isn't used this is undefined under use strict, and you cant use the below method. Example:

'use strict'
function func(){
  var self = this;
  self.obj = {};
  self.obj.x = 'y'

  console.log(self.obj);
  delete self.obj // works
  // delete obj // doesn't work
  console.log(self.obj);
}

var f = new func();

For deleting object outside of the function(closure), you will have to call like

// same code as above
delete f.obj
like image 39
rda3mon Avatar answered Sep 19 '22 17:09

rda3mon