How is JavaScript's strict mode implemented - javascript

Update:
Perhaps the way the function is called is to blame, so here's to it:
2 JS files Main.js: self invoking (non-strict) function that adds an event listener for the '(on)load' event. The callback calls a loader function, that parses the location.pathname, and calls an init function, and detaches/removes the '(on)load' listener & returns null (explicitly).
PageSpecific.js: contains the _init function, adds a couple of event listeners to the body.
One of these listeners' callback (also returned from a closure) calls the strict function that uses argument.callee as a reference for recursion. The closure that returns the event handler may -depending on the browser- or may not bind and unbind other events, but I think that's irrelevant here, as this is to imitate an onchange event in IE <9
I hope this is reasonably clear, so its: anon. F => eventlistener => handler (named but declared in anon F) => pageloader => init => eventListener binding function returned by closure => calls strict function
Incidentally: Here's a trimmed down version of the _init function that is called, that I'm actually using. More specifically: the closure that binds the event Listener and - handler together. Its another one of my length questions, to which nobody seems to know the answer... hint ;-)
I'm debugging some fairly large (and complex) JavaScripts. In doing this, I noticed that I have a function, using strict mode that works fine but should, if I'm not mistaken, throw errors. Since the scripts are fairly sizeable and complex (event delegation, stacked closures etc), here's a simple example:
function withCalleeRecursion(foo)
{
'use strict';//strict throws typeError on arguments.callee
foo = foo.replace(/(a|b)+/gi, function (p1,p2)
{
if (p1.match(/(a|b){2,}/i))
{
return p1.replace(/(a|b)/gi,arguments.callee);//no errors
}
return (p2.match(/a/i) ? 'X':'Y');
});
return foo;
}
(function()
{//not strict
alert(withCalleeRecursion('Abba makes me barf'));
})();
In my actual script, this works perfectly fine. When I pasted this both in Firebug and chrome console, an error is thrown, though. I've tried this code here, so IE should throw errors, too, but when I run the code in IE's debugger, it works just fine. As far as I can work out, changing the doctype (tried html5 and html4) makes no difference.
Am I right in thinking that (most) browsers aren't as strict with the 'use strict'; directive as it's name suggests? It would seem that the browsers choose to ignore it when a possible error is detected when parsing the script. Is this true?
Meanwhile, I have made a slight change to the function, just out of precaution. Since I've seen quite a few questions here of people wondering how to get the callee reference in strict mode, I'm pasting it here, too:
function withCalleeRecursion(foo)
{
'use strict';
foo = foo.replace(/(a|b)+/gi, function abR(p1,p2)
{
if (p1.match(/(a|b){2,}/i))
{
return p1.replace(/(a|b)/gi,abR);
}
return (p2.match(/a/i) ? 'X':'Y');
});
return foo;
}
Name the callback, that's all.

It's probably because browser consoles use eval(), which changes things. Although putting "use strict"; at the start of a string of code that is passed to eval() works as expected, it's possible that console implementations prepend code to the string you've typed into the console, meaning that "use strict"; is no longer the first statement executed and is therefore ignored.
There's a reference to this and a suggested workaround in the following article:
http://javascriptweblog.wordpress.com/2011/05/03/javascript-strict-mode/
The suggested workaround is to wrap code in the console within a function that is immediately executed:
(function() {
"use strict";
nonExistentVariable = 1; // Error is now thrown
})();

Maybe this article can help you to understand more. Anyway the solution is the one you mention, the error is because access to arguments.caller and arguments.callee throw an exception in strict mode. Thus any anonymous functions that you want to reference will need to be named.

Related

JavaScript - addEventListener is not defined

I am creating a chrome extension for blocking ads. Everything worked pretty fine so far. My goal is to:
Disable WebSocket
Disable console.log
Disable alert
Disable popups (window.open)
Disable onbeforeunload
Of course, it is supposed to block these functions only on specified websites. I searched on how to block a function. What I found is that the only way to disable a function using extension is to
In manifest.json add a content script init.js which will run at document_start (this will prevent any other code from being executed before my extension's code, so nobody can steal and save reference to these functions before I disable them)
From init.js inject code in webpage, so that my extension can access non-sandboxed environment
Override blacklisted functions
I did everything, but the problem was how to override functions. I found on EcmaScript7 specification that there is no way to detect if a function is proxy instance or not. So, I proxyfied every of these functions and it works as expected. Websites couldn't notice that I've overriden all of these functions.
However, it works for all functions expect addEventListener. In order to block onbeforeunload, I should add a proxy handler to it and track calls to check if listener name is onbeforeunload. I wrote the following script:
addEventListener = new Proxy(addEventListener, {
apply: (f, t, args) => {
if(args[0] !== 'onbeforeunload'){
f.apply(t, args);
}
}
});
This should filter calls and allow only calls which doesn't set onbeforeunload event. However, it throws ReferenceError: addEventListener is not defined. It surprised me a lot. I supposed that it is maybe because addEventListener is not yet initialized at document_start, but console.log(typeof addEventListener) logs function to console. How is that even possible?
I couldn't explain it. However, I tried to put it in a function and then to requestAnimationFrame to that function until addEventListener become accessible (I ecapsulated the above code in try...catch too). But, it turns out that modifying addEventListener always throws ReferenceError, while just accessing it never throws error.
I also tried to access it from developer console and from javascript:... method, but it behaves normally, I can modify it without any errors.
Edit
For sure, the problem isn't like this one, becuase I properly injected script into non-sandboxed (real) page environment and I have access to real window object.
addEventListener isn't a global Actually, it is, indirectly. It's a property of EventTarget.prototype (at least in Chrome). window has EventTarget.prototype in its prototype chain, which makes addEventListener a global.
So you'd need to proxy that instead, roughly (without your event name check, just for demonstration):
const save = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = new Proxy(save, {
apply: function(target, thisArg, args) {
console.log("Foo!");
return save.apply(thisArg, args);
}
});
document.body.addEventListener("click", function() {
console.log("Clicked");
});
<p>....</p>
Other notes:
The event name is beforeunload, not onbeforeunload.
You'll need to redefine the window.onbeforeunload property to prevent assignments to it, probably via Object.defineProperty.

Can a "=>" Function Lose Context?

I have an ES6 "arrow" function which is used as a (Knockout) subscription handler:
this.foo = 'test'
callback = () => console.log(this.foo)
bar.subscribe(callback);
According to MDN:
Arrow functions capture the this value of the enclosing context
So I would expect that when the callback gets called, it would log 'test'. It doesn't though. When I put a debugger in, I can see that this is actually a ko.subscription (which of course doesn't have a foo property).
I can fix things by manually binding the callback:
callback = callback.bind(this)
but as I understood things that shouldn't be necessary because my this should have been bound before callback ever got to subscribe.
Can someone please explain what I'm not understanding about the new => operator, and when it does/doesn't preserve context?
First off, thanks everyone for your help. It turns out this is just some sort of screwy Chrome developer tools bug.
Here's my original (not simpified) code:
this.snapshot_profile = ko.observable('1');
this.foo = 5;
this.snapshot_profile.subscribe((value) => {
console.log(this.foo);
debugger
// rest of the method
});
As it turns out, the console.log will correctly return 5. However, if you pause on the debugger line and hover over this, you will see that it is not an instance of my class, but rather a ko.subscription. If I "inspect" this in the console, it will look like this:
callback: (value)
dispose: ()
disposeCallback: ()
target: observable()
__proto__: ko.subscription
not like an instance of my class. However (strangely) the console.log line will correctly log 5.
All of the above can be "fixed" by binding the function, either directly or through Knockout's binding mechanism. This is what confused me: in the debugger binding/not binding the arrow function actually did change things!
But, it looks like it really didn't change anything meaningful; it just exposed a bug in Chrome's debugger.

Unattached anonymous functions and doubly named methods in javascript?

I'm debugging an app that uses .NET's scriptmanager.
It may be a glitch in firebug, but when I read through the code there are a lot of lines like the following:
// anonymous functions not attached as handlers and not called immediately
function () {
//code
}
// named functions added as methods
myObj = {
myMethod: function myFunctionName() {
//code
}
}
Are these lines valid and, if so, what do they do and what possible reason would there be for coding like this (and I won't accept "It's microsoft - what d'you expect" as an answer)?
This might be worth a read: How does an anonymous function in JavaScript work?
They are there because some busy programmer was intending to do something and ran out of time, but left the stub as a reminder of work to be done. They do nothing as of yet.
or to watermark the code for checks that are done elsewhere in the logic
or simply put there to obfuscate...

Global error logging for event handlers javascript

I want to log all errors in my browser side JavaScript code. I saw a lot of discussions here and on the net about window.onerror and it is clear it does not work cross browser. So, I plan to wrap top level entry functions with try - catch. Trouble is, a lot of my code is event handlers. I have not tested it yet, but I am pretty sure that no matter where the event handler function is defined, a thrown error will fire out directly to the browser implementation that calls it, not to event function declaring code. My only choice is to declare throw, catch and error log calls in every error handler even the tiniest anonymous one. I don't like that one bit.
A possible solution:
I use one method to cross browser register events. I can modify it to do something like this:
function registerEventHandler(object, handlerRef) {
var wrapperFunction = function(evt) {
try {
handlerRef(evt);
} catch {
logError(error);
}
registerEvent(object, wrapperFunction);
}
There is one major problem with that implementation. I often keep references to event handler function in order to deregister them later. This will not work as the function registered as the handler will be the wrapper, not the original one. The answer to this is to implement a wrapper -> wrapped mapping object and use it on unregister.
The question:
I dare you JavaScript magicians to come up with more clever solution than that. Maybe it could be done by somehow augmenting the event handler function before registration? This is a far as my JavaScript knowledge goes. What about yours?
I often keep references to event
handler function in order to
deregister them later. This will not
work as the function registered as the
handler will be the wrapper, not the
original one.
Why is this a problem? once the function is wrapped in the error handling, you dont really care about the original function anymore. The wrapper keeps a reference to your original function, and the wrapper is what is registered, and the wrapper is what needs to be unregistered.
Just keep a reference to your wrapper function you generate because its the only one that matters.
Also making it it's own function will make this pattern far more reusable
var protectErrors = function(fn) {
var that = this;
return function() {
try {
fn.apply(that, arguments);
} catch(error) {
logError(error);
}
};
};
var registerEventHandler = function(object, handlerRef) {
var wrapperFunction = protectErrors(handlerRef);
registerEvent(object, wrapperFunction);
};
protectErrors(fn) will return a function that runs the original in whatever context it was called in, and forwarding any number of arguments.

Can dynamically loaded JavaScript be unloaded?

I am writing a web application that has a static outer "shell" and a dynamic content section. The dynamic content section has many updates as users navigate the system. When a new content block is loaded, it may also optionally load another JavaScript file. In the name of good housekeeping, I remove script blocks from the DOM that apply to old content blocks, since that JavaScript is no longer needed.
The problem comes next, when I realized that although I have removed the <script> element from the DOM, the JavaScript that was previously evaluated is still available for execution. That makes sense of course, but I'm worried that it may cause a memory leak if the users navigate to a lot of different sections.
The question then, is should I be worried about this situation? If so, is there a way to force the browser to cleanup stale JavaScript?
<theory>You could go with a more object-oriented approach, and build the model in a way that each block of javascript blocks come in as their own objects, with their own methods. Upon unloading it, you simply set that object to null.</theory>
(This is fairly off-the-cuff.)
Memory use is indeed an issue you need to be concerned with in the current browser state of the art, although unless we're talking about quite a lot of code, I don't know that code size is the issue (it's usually DOM size, and leftover event handlers).
You could use a pattern for your loadable modules that would make it much easier to unload them en mass -- or at least, to let the browser know it can unload them.
Consider:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function MyModule() {
function foo() {
bar();
}
function bar() {
}
}
return MyModule;
})();
That defines a closure that contains the functions foo and bar, which can call each other in the normal way. Note that code outside functions runs immediately.
Provided you don't pass out any references to what's inside the closure to anything outside it, then window.MyModule will be the only reference to that closure and its execution context. To unload it:
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
That tells the JavaScript environment you're not using that property anymore, and makes anything it references available for garbage collection. When and whether that collection happens is obviously implementation-dependent.
Note that it will be important if you hook event handlers within the module to unhook them before unloading. You could do that by returning a reference to a destructor function instead of the main closure:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function foo() {
bar();
}
function bar() {
}
function destructor() {
// Unhook event handlers here
}
return destructor;
})();
Unhooking is then:
if (window.MyModule) {
try {
window.MyModule();
}
catch (e) {
}
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
}
If you save the evaluated code in namespaces, such as:
var MYAPP = {
myFunc: function(a) { ... }
}
"Freeing" the whole thing should be as simple as setting MYPP to some random value, ala
MYAPP = 1
This does depend on there being no other means of referencing the variable, which isn't trivial
How about loading the JS files into an iframe? Then (in theory, never tested it myself) you can remove the iframe from the DOM and remove the "memory" it's using.
I think... or I hope...
If you are worried about memory leaks then you will want to make certain that there is no event handlers in the code you want removed referring to the still existing dom tree.
It may be that you need to keep a list of all event handlers your code added, and before unloading, go through and remove the event handlers.
I have never done it that way, I always worry about when I remove nodes that there is still a reference.
Here is a good article on javascript memory leaks:
http://javascript.crockford.com/memory/leak.html
JavaScript interpreters have garbage collectors. In other words, if you don't reference anything, it won't be keeping them around.
One of the reasons why it is good to use JSON with a callback function (JSONP).
example, if you HTTP response for each JS is:
callback({status: '1', resp: [resp here..]});
And if callback() does not create a reference to the JSON object passed in as an argument, it will be garbage collected after the function completes.
If you really need to make a reference, then you probably need that data around for some reason - otherwise you would/should NOT have referenced it in the first place.
The methods mentioned to namespace objects just creates a reference that will be persisted until the reference count comes to 0. In other words, you have to track every reference and delete it later, which can be hard when you have closures and references from DOM lying around. Just one reference will keep the object in memory, and some simple operations may create references without you realizing it.
Nice discussion. Clears up a lot of things. I have another worry, though.
If I bind window.MyModule.bar() to an event, what happens if the event accidentally gets triggered after window.MyModule is deleted? For me, the whole point of namespacing and separating js into dynamically loaded modules is to avoid triggering event handlers cross-module by mistake.
For example, if I do (excuse my jQuery):
$('.some-class').click(window.MyModule.bar);
What happens if I delete window.MyModule, load another module, and click on an element which accidentally has a class called some-class?

Categories