Chrome: Javascript replaces `undefined` by `window` in "this" context [duplicate] - javascript

I'm trying to understand what rule for "this" that "use strict"; modifies in the below case.
After reading (http://unschooled.org/2012/03/understanding-javascript-this/) my best guess is that since the functon isStrictModeOn() is not "attached" to anything, this refers to null. Which is suppose to be a more sensible alternative to Javascript just attaching the this to the global object. Is that the correct interpretation of the change that "use strict" is making in this case?
http://www.novogeek.com/post/ECMAScript-5-Strict-mode-support-in-browsers-What-does-this-mean.aspx
function isStrictMode(){
return !this;
}
//returns false, since 'this' refers to global object and '!this' becomes false
function isStrictModeOn(){
"use strict";
return !this;
}
//returns true, since in strict mode, the keyword 'this' does not refer to global object, unlike traditional JS. So here,'this' is null and '!this' becomes true.

That's almost correct. In strict mode, when a function is invoked without a receiver then this is undefined (not null). A better version of that function would be:
function isStrict() {
"use strict";
return (typeof this) === 'undefined';
}
An inherent problem with functions like that is that "strictness" is determined lexically, like scope, so it's static. A tester function that includes its own "use strict"; isn't very useful; it really only tells you whether the JavaScript runtime understands strict mode. One without its own "use strict"; tells you whether the lexical context in which it's defined is in strict mode. That is:
function isStrict() {
function test() {
return (typeof this) === 'undefined';
}
return test();
}
will tell you, when called, whether a "use strict"; was in effect for the scope at which the function is defined. I guess that could be useful. However, if a reference to that function "leaks" into some other context whose "strictness" differs, it's going to continue to report on its static strictness at the point of its definition.
Personally, I would opt for simply ensuring that my code is definitely in strict mode by invoking "use strict"; at the outermost layer possible. That way there's really no need to check for it.

Related

What does "this" mean in this revealing module pattern

var abc=(function(){
var self=this;
return {
self:self
}
})();
When doing abc.self I get undefined what does this happen to be in this context.
What you have can be simplified for the purpose of the explanation in
(function(){ console.log(this) })();
Your expression (in the first set of parenthesis) defines a function. You then call this function without context (the this). This construct is called an IIFE. As you don't pass a context, the behavior depends whether it is called in strict mode or not :
In non strict mode, you would have the global object (window in a browser, global in node).
In strict mode, a missing context of a function call isn't replaced, it's undefined.
As you get undefined, I guess you're in strict mode. You probably have "use strict"; at the start of the file or in an enclosing function.
If you wanted to pass a context, you might for example have done
(function(){ console.log(this) }).call(someobject);
in that "root scope" this is window
and
console.log(abc.self);
results for me in
Window {top: Window, window: Window, ...}
this refers to the current object. In your condition this will be window, and as you're trying to get the value abc.self, you need to use like this:
this.self = this;
Now, only you can get the value:
var xyz = new abc();
xyz.self
But to note, you cannot use abc as the constructor like above code because you are using the closure.

How is strict mode ("use strict";) inherited by functions?

Here is my code that seems to indicate that the answer is yes - http://jsfiddle.net/4nKqu/
var Foo = function() {
'use strict'
return {
foo: function() {
a = 10
alert('a = ' + a)
}
}
}()
try {
Foo.foo()
} catch (e) {
alert(e)
}
Could you please cite the statements from the standard that clarifies that 'use strict' is automatically applied to all closures and functions defined within a function to which we have applied 'use strict'?
The relevant part of the spec:
http://www.ecma-international.org/ecma-262/5.1/#sec-10.1.1
which says:
Code is interpreted as strict mode code in the following situations:
Global code is strict global code if it begins with a Directive Prologue that contains a Use Strict Directive (see 14.1).
Eval code is strict eval code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval
is a direct call (see 15.1.2.1.1) to the eval function that is
contained in strict mode code.
Function code that is part of a FunctionDeclaration, FunctionExpression, or accessor PropertyAssignment is strict function
code if its FunctionDeclaration, FunctionExpression, or
PropertyAssignment is contained in strict mode code or if the function
code begins with a Directive Prologue that contains a Use Strict
Directive.
Function code that is supplied as the last argument to the built-in Function constructor is strict function code if the last argument is a
String that when processed as a FunctionBody begins with a Directive
Prologue that contains a Use Strict Directive.
So for functions defined explicitly within a 'strict scope', they will inherit strict mode:
function doSomethingStrict(){
"use strict";
// in strict mode
function innerStrict() {
// also in strict mode
}
}
But functions created using the Function constructor don't inherit strict mode from their context, so must have an explicit "use strict"; statement if you want them in strict mode. For example, noting that eval is a reserved keyword in strict mode (but not outside of strict mode):
"use strict";
var doSomething = new Function("var eval = 'hello'; console.log(eval);");
doSomething(); // this is ok since doSomething doesn't inherit strict mode
The answer is yes, but you probably won't find the exact sentence in the documentation, instead it talks of contexts.
When you define a function Foo inside another function Bar, Foo is created in the context of Bar. If Bar's context is in strict mode, that means Foo's context is in strict mode.
You can look at the documentation here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
If you think about it, not having that behavior would be really impractical (and there is no real downside to it).
This is also helpful to make your entire library use strict mode without any issue in case of concatenation of several scripts:
You can also take the approach of wrapping the entire contents of a
script in a function and having that outer function use strict mode.

Why does `this` not point to the window object?

In the browser, it is expected that this, inside an IIFE, points to the window object. However, it is undefined in this case.
(function () {
"use strict";
console.log(this) // undefined
// more stuff
}());
In ECMAScript 5's strict mode only, when the value of this is undefined or null (i.e. when not in an object's scope or this is explicitly set), this will not return the global object from the function scope.
What actually happens when a function is called is the following - the ThisBinding is jargon for the value of this when called (ECMA-262).
10.4.3 Entering Function Code
The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList:
1. If the function code is strict code, set the ThisBinding to thisArg.
2. Else if thisArg is null or undefined, set the ThisBinding to the global object.
If you want the global object, you can use a global variable that is defined in the global scope or use some hacks around this, such as using an immediately invoked new Function()1.
1: Using new Function() works as it does not go into strict mode unless the function has the pragma 'use strict'; within the body of the new Function() itself (reference).
From MDN, under "Securing" JavaScript
First, the value passed as this to a function in strict mode isn't
boxed into an object. For a normal function, this is always an object:
the provided object if called with an object-valued this; the value,
boxed, if called with a Boolean, string, or number this; or the global
object if called with an undefined or null this. (Use call, apply, or
bind to specify a particular this.) Automatic boxing is a performance
cost, but exposing the global object in browsers is a security hazard,
because the global object provides access to functionality "secure"
JavaScript environments must restrict. Thus for a strict mode
function, the specified this is used unchanged:
Example:
"use strict";
function fun() { return this; }
assert(fun() === undefined);
assert(fun.call(2) === 2);
assert(fun.apply(null) === null);
assert(fun.call(undefined) === undefined);
assert(fun.bind(true)() === true);
One way to pass the global object in explicitly in strict mode is to use call(this)
(function(){
"use strict";
console.log(this) // this points to window
// more stuff
}).call(this);

"use strict" causes undefined error

I am defining the following function in my JavaScript:
function _snr(id) {
"use strict";
this.e = "something";
}
I ran my code through JSLint and it suggested that I add "use strict" to the function.
When I do e now throws and undefined error. From some initial investigation it looks as though this which used to refer to _snr is no longer defined.
I have read about "use strict" and discovered that it is used to prevent unsafe practices. Could some one explain what was unsafe about this? What "use strict" is actually doing and how I can fix my code?
If a function is called without setting its this, in non–strict mode its this will be set to reference the global (window in a browser) object. In strict mode, it wil remain undefined.
If your function is called as _snr(...) then its this is not set, so in non–strict mode this will be set to the global object so this.e = ... references (or creates due to the assignment) a global e property.
However, in strict mode this will be undefined, and trying to access a property of undefined throws an error.
It's explained in ECMA-262 §10.4.3 Entering Function Code.
Edit
If you wish to access the global object from inside a function in a manner that is consistent with both strict and non–strict mode, you can use something like:
var _snr = (function(global) {
return function (id) {
global.e = "something";
};
}(this));
In non-strict mode, you can do:
function _snr(id) {
var global = (function(){return this;}());
global.e = "something";
}
so that global within the function references the global object and you don't have to worry about how the function is called. But the second example won't work in strict mode.
Other answers:
I have read about "use strict" and discovered that it is used to prevent unsafe practices. Could some one explain what was unsafe about this?
Absolutely nothing in this particular case.
However, in a more general case, it was considered a good idea to be able to execute code within a context that stopped it accessing the global object directly. The second example above shows how that can be done in non–strict code (i.e. how you can get direct access to the global object from inside a function context).
What "use strict" is actually doing
It is stopping this being set to the global object if the call sets it to undefined or null. See above for the consequence of that.
and how I can fix my code?
See above.
Oh, and finally, there is an informative summary of strict mode in ECMA-262 Annex C The Strict Mode of ECMAScript.

javascript "use strict" and Nick's find global function

So I saw a function that was, quite frankly beautiful in its simplicity as it allowed you to find the global object ( which depending on environ at the time may NOT have been window ) while within an anonymous function; however when you throw javascripts' "use strict"; mode it crumbles, due to the evaluation of the keyword 'this' changing. There were a few ways to accomplish this?
(function () {
var win = function () {
return (function () {
return this;
}());
};
//win now points to the global object no matter where it is called.
}());
Now, if these are called within the context of "use strict" we lose the functionality described, is there any equivalent that can be done in ES5 strict mode?
For reference
(function () {
"use strict"
//code here is in strict mode
}())
Access to the Global Object (before ES5)
If you need to access the global object without hard-coding the identifier window, you can do the following from any level of nested function scope:
var global = (function () {
return this;
}());
This way you can always get the global object, because inside functions that were invoked
as functions (that is, not as constrictors with new) this should always point to
the global object.
This is actually no longer the case in ECMAScript 5 in strict mode,
so you have to adopt a different pattern when your code is in strict mode.
For example,
if you’re developing a library, you can wrap your library code in an immediate function
(discussed in Chapter 4) and then from the global scope, pass a reference to this as a
parameter to your immediate function.
Access to the Global Object (after ES5)
Commonly, the global object is passed as an argument to the immediate function so
that it’s accessible inside of the function without having to use window: this way makes
the code more interoperable in environments outside the browser:
(function (global) {
// access the global object via `global`
}(this));
“JavaScript Patterns, by Stoyan Stefanov
(O’Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750.”
Solution:
var global = Function('return this')();
Works in all Browsers, Engines, ES3, ES5, strict, nested scope, etc.
A slight variation will pass JSLINT:
var FN = Function, global = FN('return this')();
Discussion
See How to get the global object in JavaScript?
Here's a snippet from Perfection Kills, using global eval.
var root = (function () {
return this || (0 || eval)('this');
}());
ECMA3, ECMA5, Strict mode, etc compatible, passes JSLint.

Categories