Setting this to a var causes possible strict violation: [duplicate] - javascript

I think this may be a duplicate of Strict Violation using this keyword and revealing module pattern
I have this code:
function gotoPage(s){
if(s<=this.d&&s>0){this.g=s; this.page((s-1)*this.p.size);}
}
function pageChange(event, sorter) {
var dd = event.currentTarget;
gotoPage.call(sorter, dd[dd.selectedIndex].value);
}
And JSHINT (JSLINT) is complaining. It says "Strict violation." for the highlighted line:
Is my use of Function.call() and then referencing the instance, somehow inappropriate?
Is this considered to be bad style?

JSHint says "Possible strict violation" because you are using this inside something that, as far as it can tell, is not a method.
In non-strict mode, calling gotoPage(5) would bind this to the global object (window in the browser). In strict mode, this would be undefined, and you would get in trouble.
Presumably, you mean to call this function with a bound this context, e.g. gotoPage.bind(myObj)(5) or gotoPage.call(myObj, 5). If so, you can ignore JSHint, as you will not generate any errors. But, it is telling you that your code is unclear to anyone reading it, because using this inside of something that is not obviously a method is quite confusing. It would be better to simply pass the object as a parameter:
function gotoPage(sorter, s) {
if (s <= sorter.d && s > 0) {
sorter.g = s;
sorter.page((s - 1) * sorter.p.size);
}
}
function pageChange(event, sorter) {
var dd = event.currentTarget;
gotoPage(sorter, dd[dd.selectedIndex].value);
}

I've had this message for a function that did not start with a capital letter.
"use strict";
// ---> strict violation
function something() {
this.test = "";
}
// ---> just fine (note the capital S in Something)
function Something() {
this.test = "";
}

If you declare the function as a variable instead of using the standard function declaration, jshint will not flag this as a strict violation. So you may do the following -
var gotoPage = function (s){
if(s<=this.d&&s>0){this.g=s; this.page((s-1)*this.p.size);}
};
var pageChange = function (event, sorter) {
var dd = event.currentTarget;
gotoPage.call(sorter, dd[dd.selectedIndex].value);
};

If you're trying to implement a method, you might want to assign to the prototype instead:
ExampleClassName.protytpe.gotoPage = function gotoPage(s){
// code using this
};
JSHint won't warn when the function is being assigned.

Related

Is it possible to overwrite "global" variable via Webpack?

I am finding a way to make MathJax be able to run on a specific JS runtime with lots of limitations.
MathJax use global to access the MathJax object, and this is compiled by Webpack into the following snippet:
function (e, t) {
var n;
n = function () {
return this;
}();
try {
n = n || new Function("return this")()
} catch (e) {
"object" == typeof window && (n = window)
}
e.exports = n
}
The code above will try to assign the global this to e.exports, and the usage of global in MathJax's source code will be replaced with e.exports. However, in my JS runtime, window/global are not available, function () { return this; } returns undefined, new Function is restricted and only returns an empty object instead of a function.
My question is that, is it possible to configure Webpack to replace global with some other variable I specify (like limitedGlobal.someVar)?
For referrence, I found that the snippet above is defined in GlobalRuntimeModule.js, and I want to change its implementation.
Sure, please have a look at globalObject
Its default is global="window"
You can override it like this in your webpack configurations:
output: {
globalObject: 'this' // or limitedGlobal.someVar in your case
}

How to check that ES6 "variable" is constant?

Does anyone know some tricks how to do it? I tried to use try-catch:
"use strict";
const a = 20;
var isConst = false;
try {
var temp = a; a = a+1; a = temp;
} catch (e) {
isConst = true;
}
But unfortunately it works only in "strict" mode. Without "use strict" it perform all statements silently, without modification of a. Also I cannot wrap this code into some handy function (isConstant(someConst) for example) as any argument I'll pass to that function will be a new variable. So anyone know how to create isConstant() function?
I don't think there is, but I also don't think this is a big issue. I think it might be useful to have the ability to know if a variable is const, and this exists in some other languages, but in reality since you (or someone on a team) will be defining these variables, you'd know the scope and the type of the variables. In other words, no you can't, but it's also not an issue.
The only case where it might be useful is if you could change the mutable property during runtime, and if changing this property had actual performance benefits; let, const, and var are treated roughly equally to the compiler, the only difference is that the compiler keeps track of const and will check assignments before it even compiles.
Another thing to note is that just like let, const is scoped to the current scope, so if you have something like this:
'use strict';
const a = 12;
// another scope
{
const a = 13;
}
it's valid. Just be careful that it will look up in higher scopes if you don't explicitly state const a = 13 in that new scope, and it will give a Read Only or Assignment error:
'use strict';
const a = 12;
{
a = 13; // will result in error
}
Based on some of the answers here I wrote this code snippet (for client side JS) that will tell you how a "variable" was last declared--I hope it's useful.
Use the following to find out what x was last declared as (uncomment the declarations of x to test it):
// x = 0
// var x = 0
// let x = 0
// const x = 0
const varName = "x"
console.log(`Declaration of ${varName} was...`)
try {
eval(`${varName}`)
try {
eval(`var ${varName}`);
console.log("... last made with var")
} catch (error) {
try {
eval(`${varName} = ${varName}`)
console.log("... last made with let")
} catch (error) {
console.log("... last made with const")
}
}
} catch (error) {
console.log("... not found. Undeclared.")
}
Interestingly, declaring without var, let or const, i.e x = 0, results in var getting used by default. Also, function arguments are re-declared in the function scope using var.
Just check if your reassignment actually did something:
var isConst = function(name, context) {
// does this thing even exist in context?
context = context || this;
if(typeof context[name] === "undefined") return false;
// if it does exist, a reassignment should fail, either
// because of a throw, or because reassignment does nothing.
try {
var _a = context[name];
context[name] = !context[name];
if (context[name] === _a) return true;
// make sure to restore after testing!
context[name] = _a;
} catch(e) { return true; }
return false;
}.bind(this);
You need the try/catch because reassign Could throw an exception (like in Firefox), but when it doesn't (like in Chrome), you just check whether your "this always changes the value" reassignment actually did anything.
A simple test:
const a = 4;
var b = "lol";
isConst('a'); // -> true
isConst('b'); // -> false
And if you declare the consts in different context, pass that context in to force resolution on the correct object.
downside: this won't work on vars declared outside of object scopes. upside: it makes absolutely no sense to declare them anywhere else. For instance, declaring them in function scope makes the const keyword mostly useless:
function add(a) {
return ++a;
}
function test() {
const a = 4;
console.log(add(a));
}
test(); // -> 5
Even though a is constant inside test(), if you pass it to anything else, it's passed as a regular mutable value because it's now just "a thing" in the arguments list.
In addition, the only reason to have a const is because it does not change. As such, constantly recreating it because you're calling a function that makes use of it more than once, means your const should live outside the function instead, so again, we're forced to put the variable in an object scope.
The question refers to incompliant behaviour in earlier ES6 implementations, notably V8 (Node.js 4 and legacy Chrome versions). The problem doesn't exist in modern ES6 implementations, both in strict and sloppy modes. const reassignment should always result in TypeError, it can be caught with try..catch.
There can't be isConstant function because const variable cannot be identified as such by its value.
It's preferable to run a script in strict mode and thus avoid problems that are specific to sloppy mode.
Even if a variable was defined in sloppy mode, it's possible to enable strict mode in nested function scope:
const foo = 1;
// ...
let isConst = false;
(() => {
'use strict';
try {
const oldValue = foo;
foo = 'new value';
foo = oldValue;
} catch (err) {
isConst = true;
}
})();
It's beneficial to use UPPERCASE_CONSTANT convention which is used in JavaScript and other languages. It allows to unambiguously identify a variable as a constant without aid from IDE and avoid most problems with accidental reassignments.

Modifying Array.forEach to Automatically Set the Context to be the Caller

Is it possible to create an alternate of Array.forEach that automatically sets the context "this" to be the same context as when the method was invoked?
For example (not working, not sure why):
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
this.myVar = 'myVar';
[1,2,3].each(function() {
console.log(this.myVar); // logs 'myVar'
});
}
Array.forEach already takes a context argument as the optional last parameter,
(function() {
this.myvar = "myvar";
[1,2,3,4].forEach(function(v) {
console.log("v:"+v);
console.log("myvar="+this.myvar);
}, this);
})();
See MDN forEach
Also, the above examples (if we're not dealing with methods on instances regarding this) work without using bind or the optional context argument for forEach, the following also works correctly:
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
});
}
myFunction();
Because javascript is functionally scoped, so the anonymous function can access the parent function's scope using this and it logs correctly. this only really becomes problematic as a context when dealing with instance methods.
The answer is no, a JavaScript function cannot determine the value of this in the caller.
You can bind the function passed with the current object, like this
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
}.bind(this));
}
In ECMA Script 6, you can use an Arrow function, like this
[1,2,3].forEach(() => {
console.log(this.myVar); // logs 'myVar'
});
An alternative to messing with the this variable when passing around callbacks, you could always just assign this to a new variable so child scoped functions can access it:
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
var me = this;
me.myVar = 'myVar';
[1,2,3].each(function() {
console.log(me.myVar); // logs 'myVar'
});
}
now you don't have to remember to pass this as a second parameter
Firstly, it must be pointed out that myFunction is a constructor. Yet, the first letter in the identifier is not capitalized. Please call it MyFunction.
If a constructor is called without the new operator, this is bound to the global object, i.e. window in browsers. This makes the capitalization convention our only way of spotting such mishaps.
The following lines of code demonstrate this:
// After the original code...
myFunction();
console.log(window.myVar); // logs "myVar"
Secondly, to be able to apply functions on any array, instead of changing Array.prototype, consider the following:
var utils = {array: {}}; // utils.array is a container for array utilities.
utils.array.each = function (array, func) {
var i;
for (i = 0; i < array.length; i += 1) { func(array[i]); }
};
utils.write = function (s) {
console.log(s); // Alternatively, document.write(s);
};
utils.array.each([1, 2, 3], utils.write); // prints 1 2 and 3 (on separate lines)
Notice that we didn't use this and new. They make JavaScript look like Java, apart from that, they rarely serve a useful purpose.
While libraries may modify Object.prototype and Array.prototype, end-developers shouldn't.
Also, we should (ideally) be able to do something like:
utils.array.each([1, 2, 3], console.log); or
utils.array.each([1, 2, 3], document.write);.
But most browsers won't allow it.
Hope this helped.
If I understand your requirement correctly, then you are trying to override the "this".
I think this can help you.

Getting rid of eval

I have a name of a method as a string in javascript variable and I would like to get a result of its call to variable:
var myMethod = "methodToBeCalled";
var result;
eval("result = "+myMethod+"();")
This works and there are no problems. But this code is inacceptable for Google Closure Compiler. How can I modify it to work with it? Thanks!
EDIT:
It seems the proposed solutions does not work when the name of the method is inside of some object, for instance:
var myFunction = function () { return "foo!" }
var myObject = {
itsMethod: function() { return "foo!" }
};
...
var fstMethodToCall = "myFunction"
var sndMethodToCall = "myObject.itsMethod";
...
window[fstMethodToCall](); // foo!
window[sndMethodToCall](); // undefined
Assuming you are not in a nested scope of some kind, try:
var result = window['methodToBeCalled']();
or
var myMethod = 'methodToBeCalled';
var result = window[myMethod]();
To execute an arbitrary function of arbitrary depth based on a string specification, while not executing eval:
var SomeObject = {
level1: {
level2: {
someFunc: function () {
console.log('hello');
}
}
}
};
var target = 'SomeObject.level1.level2.someFunc';
var obj;
var split = target.split('.');
for (var i = 0; i < split.length; i++) {
obj = (obj || window)[split[i]];
}
obj();
You can use indexer notation:
result = window[myMethod]();
The Closure Compiler doesn't prohibit 'eval', you can continue to use it if you find it convenient but you have to understand that the compiler doesn't try to understand what is going on in your eval statement and assumes your eval is "safe":
function f(x, y) {
alert(eval("y")); // fails: hidden reference to "y"
alert(eval('"'+x+'"')); // might be valid
}
f('me', 'you');
When the compiler optimizes this function it tries to remove "y" and renamed the remain parameter. This will the first eval to fail as "y" no longer exists. The second eval would correct display the alert "me".
So with SIMPLE optimizations, you can use eval to reference global variables and object properties as these are not renamed or removed (but not local ones).
With ADVANCED optimizations, it is a little trickier, as the compiler tries to remove and rename global as well as local variables. So you need to export the values you need to have preserved. This is also true if you use a string to try to reference a name by other means:
var methodName = "myMethod";
(window[methodName])()
or
var methodName = "myMethod";
eval(methodName+"()")
the compiler simply doesn't try to determine if "methodName" is a reference to a function. Here is a simply example of an ADVANCED mode export:
window['myMethod'] = myMethod;
The assignment does two things: it preserves the myMethod function if it would otherwise be removed and it gives it a fixed name by assigning it to a property using a string. If you do need to reference local values, you need to be a little trickier and use a Function constructor. A definition of "f" from my first example, that can eval locals:
var f = new Function("x", "y", "alert(eval('y')); alert(eval('\"' + x + '\"'));");
You may find this page useful:
https://developers.google.com/closure/compiler/docs/limitations

Binding "this" when passing an object's member function

I had a "class" defined and was making only one instance of it. The instance possessed a member function that would end up being passed around (it's a mouse handler, but that's not important). Since I would only ever make one instance of my "class", I decided to rewrite it as a singleton by using an object literal.
So I have
var mySingleton = {
theObjects : [];
}
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}());
mySingleton.addObject = function(newObj) {
this.theObjects.push(newObj);
}
However, when I try to use this code (after adding a few objects), I keep getting an that.theObjects is undefined error. It's referring to the line in the for loop.
Update for 2015 – Use Function.bind() to specify the value of this within the function. Then, instead of using that, you can use this.
mySingleton.mouseHandler = function (e) {
for (var indx = 0; indx < this.theObjects.length; indx++) {
// do something to this.theObjects[indx];
}
}.bind(mySingleton);
This doesn't work if you want mouseHandler to have the context of the 'moused' element. For that, use my original answer below.
If you need to support IE8 or (heaven forbid) earlier, you'll need to use a polyfill.
Since you are calling the function that creates mouseHandler immediately, it is run in the context of window, not mySingleton. So that refers to window. Instead of calling it immediately, just change it to a method so that it runs in the context of mySingleton:
mySingleton.getMouseHandler = function() {
var that = this;
return function() { ... };
};
myElement.onclick = mySingleton.getMouseHandler();
Of course, since you are already using a singleton, you can just reference it directly. In your click handler, instead of checking that.theObjects, check mySingleton.theObjects. Or, in mouseHandler change var that = this to var that = mySingleton.
Edit: Or, pass the context to your anonymous function when you call it:
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}).call(mySingleton);
There are a few popular ways to do this. First, super-simple solution is just reference mySingleton directly and bypass the confusion associated with this. Instead of that.theObjects just do mySingleton.theObjects and move on with your life and things will work fine.
However, there is a common pattern to do this binding. Here's how underscore.js does it
Check out the annoted source to underscore, where you will find this
_.bind = function(func, obj) {
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
};
};
The other answers here so far are also correct. Providing my viewpoint here in case it helps.
The key to understanding why the code doesn't behave as you expect requires understanding how this works in JavaScript. The problem is that this depends on how the function is called.
First, if you call the function in the method style, this is what you'd expect:
mySingleton.mouseHandler(); // this === mySingleton
If you attach the function to something esle, that works too.
var anotherSingleton = {};
anotherSingleton.foo = mySingleton.mouseHandler;
anotherSingleton.foo(); // this === anotherSingleton
If you detach the function, this becomes the global scope object (window)
var foo = mySingleton.mouseHandler;
foo(); // this === window
And finally, you can force this to be something else using call or apply:
var randomThingy = {};
mySingleton.mouseHandler.call(randomThingy); // this === randomThingy
The takeaway is that this is determined at runtime based on the context of how the function was called. Often, frameworks that allow you to make "classes" abstract these details from you by implicitly applying the bind pattern on your behalf. This is why it used to work, and no longer does.
As others have mentioned, you can change your handler to reference the variable by its scoped name (mySingleton) or otherwise bind it as discussed.
Here's an article I wrote on the subject a few years ago that goes into more detail: http://trephine.org/t/index.php?title=Understanding_JavaScript%27s_this_keyword
Hope this helps!

Categories

Resources