How can I return a built-in function as a object property?
This code works, in some cases. If it returns console.log
then the call to p.out
functions just fine.
function Notice(mode) {
this.debug = mode;
this.out = (function() {
if(mode) {
if(window.console) {
return console.log;
} else {
return alert;
}
} else {
return Notice.doNothing;
}
})(mode);
}
var p = new Notice('1');
p.out('Kool-aid, OH YEAH!');
However, when it returns alert (or window.alert) I get an error:
Error: uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: 开发者_StackOverflow社区http:// .. :: <TOP_LEVEL> :: line 22" data: no]
And as a simple test, this works:
out = (function() { return alert; })();
out('hello dolly');
How can I get obj.out to function properly when its being set to alert?
The problem is that in some implementations, alert is actually a proper method of the window object. That is, alert expects this
to be the window object. This illustrates the problem in the simplest form:
var foo = {alert : alert};
/* this fails because the value of 'this' is foo:
*/
foo.alert('hello');
/* but this works because we re-point 'this to the
* correct object, that is the window object:
*/
foo.alert.call(window,'hello');
So, a solution to your problem is to either return a function that directly call alert or bind window to alert in a closure. Either something like this:
function Notice (mode) {
this.out = function(message) {
if(mode) {
if(window.console) {
console.log(message);
} else {
alert(message);
}
}
};
}
or this:
function Notice (mode) {
this.out = (function() {
if(mode) {
if(window.console) {
return console.log;
} else {
return function (message) {alert(message)};
}
}
})();
}
Why not return an anonymous function that in return calls the build-in function?
Something like
return function(msg) { alert(msg); }
I suspect the problem you're having isn't because of how you're setting it, but because of the functions involved. console.log
calls the log
function with the context (the this
value) set to console
. If you do
var f = console.log;
f("Hi there");
...note that log
is called with a different context (in this case, the global object, which is window
in browsers), this
is no longer the console
object.
If you do this:
var obj = {};
obj.f = console.log;
obj.f();
...then log
will be called with obj
as this
.
Some functions will care, because some functions use this
in their implementation. Some functions won't care because they don't. It may be that alert
didn't care because it just so happens that it's expecting this
to be window
-- and that's exactly what it is when you call the function raw (e.g., not via dotted notation or in the other ways that explicitly set this
), because (again) window
is the global object in browsers.
As a separate note: In most implementations, the built-in functions you see are proper JavaScript function objects and have all of their features. In some implementations, though (Internet Explorer is one), they aren't proper JavaScript functions at all and they lack some of the features of proper functions, such as the apply
and call
properties. When in doubt, wrap.
精彩评论