Why does window.location.reload need to be wrapped in a function(){}? - javascript

I've written some code to add a button to the page:
var myButt = document.createElement('button');
myButt.onclick = window.location.reload;
myButt.innerText = 'Reload';
document.body.appendChild(myButt);
But it throws an error:
TypeError: Type error
Wrapping it in a function fixes the problem:
myButt.onclick = function(){ window.location.reload(); };
But my question is why the former doesn't work?
Executing air.trace(typeof(window.location.reload)); outputs function.
An answer from a high-rep user suggests that it should be possible. It's definitely more succinct.
I am running Adobe AIR 3.6 (which runs Webkit), if that makes a difference.

The this value is incorrect when using it like that.
this turns out to be myButt when you need it to be window.location.
To fix this (hehe), either wrap it as you've done, or bind a new this value to it:
myButt.onclick = window.location.reload.bind(window.location);
I just tested that, and it works on Firefox 23.0.1.
For future reference, he was using the Function.prototype.bind compatibility code found here.
With my code above, he was getting the error
TypeError: instanceof called on an object with an invalid prototype
property
To fix this, I changed line 18 of that compatibility code to the following:
fNOP.prototype = this.prototype || {};
This is so that the prototype gets set to a blank object, because window.location.reload doesn't have a prototype naturally.

Related

console.log() called on object other than console

I remember that always when I wanted to pass console.log as a callback parameter to some function, it didn't work unless I used the bind() method to bind console to it.
For example:
const callWithTest = callback => callback('test');
callWithTest(console.log); // That didn't use to work.
callWithTest(console.log.bind(console)); // That worked (and works) fine.
See Uncaught TypeError: Illegal invocation in javascript.
However, recently I noticed that console.log() works fine even when called on object other than console. For example:
console.log.call(null, 'test');
logs 'test'.
When and why did it change? Does the specification say anything about it?
Editor's Draft of Console API used to say:
Logging APIs SHOULD all be callable functions allowing them to be passed as arguments to error handling callbacks, forEach methods, etc.
This is no longer included in the current version of the specification.
I thought that Chrome and Node.js changed it to work like in the specification, but it seems that it worked like that even before it.
I'm still curious when did it change and what was the reason of that.
I don't know when the change was made, but I have an idea about why it didn't work.
Consider the following code
callWithTest = callback => callback('test');
var Demo = function () {this.str = 'demo';}
Demo.prototype.getStr = function () { return this.str;}
demo = new Demo ();
demo.getStr(); // returns 'demo'
callWithTest(demo.getStr); // returns undefined
window.str = 'window';
callWithTest(demo.getStr); // returns 'window'
If you trace the code, you will see that when demo.getStr gets called through another function, this refers to window, and sine str is not defined within window, it returns undefined. If you called it directly or bind with demo, this refers to demo and thus it returns 'demo'.
In nodeJS (v6.6.0), there exists a class called Console within the console module which user can explicitly pipe logs into a file (or whatever stream a user like). According to Node.js v6.6.0 api specification,
console = new Console(process.stdout, process.stderr);
Console does not exist in browser as it isn't necessary. The output of console only exists in a canvas used for debugging, and there are exactly one instance of it. User can't, and should not be able to, pipe output of console to any other places as it will become a serious security issue. Because of this, developers can do something within the log function like var x = this.x || console.x as there is exactly one instance of the console object.

Get Javascript function name

Is there a way to obtain function's name from outside of it?
Lets say there is a js script on web page that we cannot modificate, just read. The script contains object, which contains objects and functions. Lets say that we want to find function named "HelloWorld".
With firebug, we loop through these objects and methods with a script, which looks something like this
// Parameter is target object.
function getFunctionNames(obj) {
// For each objects / functions
for (var id in obj) {
// Focus only on functions
if (typeof(obj[id]) == "function") {
// Get name of the function.
// console.log("Function: " + obj[id].toString());
// Code above returns a block of code without the name. Example output:
// Function: function(name) { alert("Hello World! Hello " + name + "!"); }
//
// Expected output would be
// Function: HelloWorld
}
}
}
obj[id].toString() returns a block of code instead of a name.
obj[id].name returns an empty string. Anonymous function(?).
I cannot use arguments.callee.name because I cannot modify the target code.
I could just browse objects and functions in firebug or just read source code, but I'm looking a way to do it with Javascript.
Edit
For real world example, head to Youtube and try to get the name of function "setMsg()" from "yt" object via Javascript.
Edit2
Accepting Simon's answer for being kinda closest what I was looking for. It appears that I was seeking variable name, rather than function name. While answer didn't help me on original problem, it surely answered to original question. Paul Draper's comments helped me to right direction.
Thanks!
Use obj.name
Note that arguments.callee returns a function. name is property on every function (though it's empty for anonymous functions), so that's why arguments.callee.name works.
This works for webkit (Chrome and Safari), Firefox, and possibly others. It does not work for IE: function.name not supported in IE.
As mentioned, the function doesn't have any intrinsic name other than the "" it gets from being an anonymous function. Some browsers (Firefox, probably Chrome, maybe others) do however perform some limited form of static analysis to figure out names of declared functions, to help with error stack traces. You can get to it in an relatively cross-browser way by getting setMsg to throw an exception and then parse exc.stack:
// cheat with .% in Firebug; there might be other ways of doing this, I dunno:
yt.setMsg.%m.za.__defineSetter__('a', function() { throw new Error(); });
try { yt.setMsg('a', 'a'); }
catch(e) { alert(e.stack.split('\n')[2].split('#')[0]); }
... On the other hand, this is a pretty terrible hack and dependent on the actual function involved (and if you know the function, you probably know its name already). It does work a bit more reliably when done from inside the function.
If you restrict yourself to just Firefox and are doing this for debug purposes, there are better ways of getting to it. Set devtools.chrome.enabled to true in about:config, open a Scratchpad (Shift+F4), set it to environment: browser, and run the following:
Components.utils.import("resource://gre/modules/jsdebugger.jsm");
window.addDebuggerToGlobal(window);
dbg = new Debugger();
dw = dbg.addDebuggee(content);
f = content.wrappedJSObject.yt.setMsg;
name = dw.makeDebuggeeValue(f).displayName;
dbg.removeDebuggee(content);
alert(name);
In both cases, you will note that it alerts "m.ya" instead of "setMsg", and indeed this is because the function was originally declared as m.ya = function() { ...; }. There is no reason why "setMsg" would be a preferable name, from the point of the browser.

Why does iterating over the properties of the window object causes an error in IE?

I experiences this problem very often and finally thought that it might be worth a question here.
Running the following code in IE, results in the output frameElement, which means, that the property frameElement was found but if you try to access it via window["frameElement"] it throws an error.
for (var i in window){
try {
var c = window[i]
} catch(e) {
console.log(i);
}
}
FIDDLE
I originally realized this problem when i tried to simply access every property of window, but always ended up with an error.
Does anyone know the reason for this? How can it be, that there is a property but that it is not accessible?
This can happen on any browser. Properties on any object, including Window, can be getters methods that can have side-effects including throwing exceptions.

Is there a way to have Javascript throw an error when a new property is added to a given object?

Object.preventExtensions and Object.seal prevent unknown properties from being added to an object, but those attributions silently fail instead of throwing an error. Is there a way to force them to be errors?
var myObj = Object.seal({});
try{
myObj.someProp = 17;
console.log("I don't want to reach this message");
}catch(err){
console.log("I want an error to occur instead.")
console.log("Or at least get a warning somewhere.");
}
I tested this in Chrome 19 and Firefox 9. I wouldn't mind browser-specific solutions either, since I would only need this during development.
If strict mode is an option, Object.seal seems to do the trick (at least in Firefox):
Attempting to delete or add properties to a sealed object, or to convert a data property to accessor or vice versa, will fail, either silently or by throwing a TypeError (most commonly, although not exclusively, when in strict mode code).
Works pretty good: http://jsfiddle.net/yVWr6/
(btw: works the same for preventExtensions())
According to the MDN documentation for Object.seal() (and Object.freeze()) if you enable strict mode then a TypeError will be thrown when attempting to modify a sealed object:
function go() {
'use strict';
var x = {};
Object.seal(x);
x.foo = 123;
}
go(); // => TypeError: Can't add property foo, object is not extensible

JavaScript Call and Apply in internet explorer 8 (and 7) for window.print

OK, I looked a lot for this on the web but cannot find an answer.
I can expect CSS differences between browsers but there are JavaScript differences too?
So why this works in IE8:
window.print(); // works
but when I pass window.print to a function and call it, it don't work in IE8 (works in IE9):
function callIt(f){
f.call();
};
callIt(window.print);
Is it a known issue?
EDIT
OK it does not work means it will simply ignore it, no javascript error or anything.
Sorry it gives this error:
Object doesn't support this property or method
EDIT 2
I need to use call or apply since I need to pass the context. I am trying to create a class which I can pass functions and it can call it with the possibility of passing context or arguments. Do not tell me to use f() that is not an answer since it does not fix my problem. The question is on call and apply.
It seems window.* functions are separate types than user-created functions in IE < 9. Thus, they don't get any of the Function.prototype.*. You'll see that
typeof alert === 'object'
function a(){}
typeof a === 'function'
This would happen for any of the window.* functions. Only for IE < 9. WTG Miscrosoft.
However you can try
Function.prototype.call.call(window.print)
See if that works for you.
function callIt(f) {
if (f) f();
}
callIt(window.print);
Done, no?
Update
per the poster's request that I answer the question, not recommend a solution that works, here she goes:
If you view typeof(window.print) in IE, you'll see that it reports itself as type object. Type object has no apply or call method. In my opinion, your design is wrong for the task. HOWEVER, if what you want is a rabbit hole to follow, here's the top:
var p = window.print;
window.print = function() { p(); }
function callIt(f){
f.call();
}
callIt(window.print);
I have no idea what will happen in any other browser or how many procedural exceptions you'll have to make to account for it everywhere you'll need to.
You almost certainly should not be using .call() here. f() will call the method, while f.call() will call it with an unset this. Under es3 (but not es5 strict,) an undefined value for this will be coerced to window. I suspect that IE9 properly handles this, while IE8 does not, but that's just a guess based on behavior.
If print cares about the value of this, you should call it as window.print() in order for this to be set correctly. In that case, you may have to wrap it in an anonymous function so that print doesn't get "sliced off" of window. callIt(function() { window.print();});

Categories