Preferences = {
XDPI:90,
YDPI:90,
*:function(missing_name) {"Tell Joe he forgot to implement " + missing_name+ " property or func"}
}
Say I got an old/undocumented/minified/uglified class I want to replace with my own implementation.
How could I catch all the old properties that could be missing from within my new "object" ?.
(Say there are a lot of client script (macros) used by non-technical users. I want to ease the report of missing func)
E.g if a script call Preferences.CurrentPrinter I want the Preferences object to diagnose it lacks a CurrentPrinter property without the user having to look at the console
Sixth edition of ECMAScript specification introduces Proxy objects for that purpose:
http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-objects
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
But this is not widely supported yet. At the moment of writting this, only Edge and Firefox browsers do that:
http://caniuse.com/#feat=proxy
P.S. Lucky you if you read that in future and all browsers already support that :)
You probably don't want to do something like that, having an object return undefined for properties that don't exist is something that gets relied on a lot.
What you probably should do is just check to see if your Preferences.member is undefined when you want that functionality instead of changing the way accessors work on your object.
If you insist, though what you could do is implement a method called get() that gets the property based on the string passed in and do all calls that way.
Preferences = {
varX=90;
varY=90;
get = function(arg) {
if(typeof this[arg] != 'undefined') {
return this[arg];
}
Console.log("{0} not found in Preferences".format(arg));
};
}
And then instead of doing Preferences.varX you do Preferences.get(varX).
For methods you can use noSuchMethod, but it only works in Firefox
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/noSuchMethod
You can get more informations from this post:
Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?
Related
I can't reconcile the following with any of the JavaScript documentation I've read. Can somebody please shed some light?
The following snippet is taken from file panelUI.js in the Mozilla repository.
const PanelUI = {
/** Panel events that we listen for. **/
get kEvents() ["popupshowing", "popupshown", "popuphiding", "popuphidden"],
// more properties...
_addEventListeners: function() {
for (let event of this.kEvents) {
this.panel.addEventListener(event, this);
}
// more code...
},
// more properties...
Everything I've read about JS defines a getter as essentially a function (or "a method that gets the value of a specific property" and "The get syntax binds an object property to a function that will be called when that property is looked up"), so I'm a bit baffled to see an array literal where I would expect to find the body of function kEvents().
What does it mean in JS to have a function name followed by an array literal (in general or as part of a get definition)?
How would you write code that is functionally equivalent to the above, but does not use this somehow odd syntax?
I assume this is a consequence of SpiderMonkey's non-standard and deprecated support for expression closures.
this isn't valid JavaScript in any way... unless Firefox is allowing it as an alternative syntax for some reason.
but if you tried to run this or similar code in a browser like chrome, or even trying to compile it using Babel and ES6, it fails.
How would you write code that is functionally equivalent to the above, but does not use this somehow odd syntax?
An "equivalent" syntax appears to be to wrap the data in curly braces and return it:
get kEvents() {
return ["popupshowing", "popupshown", "popuphiding", "popuphidden"];
},
I would guess that the example code returns the same array instance every time, whereas my code is going to generate a new array every time it's called.
I imagine that the listed line is a non-standard syntax that mozilla has implemented but that is not associated with any current spec. Oftentimes with these sorts of features the browser development community pushes a browser to implement a new feature to see if it's worthwhile for standardization. It could have been a proposed syntax that was later dropped as well
That all said, this is speculative, as I've never seen a standard with that syntax in it.
I'm using the library handsontable and I'd like to get my application running in IE8-IE9 (even though it's not IE < 10 compatible...). When my code use the minify version I get an error in the JS console : "';' expected".
Here is the code.
, {
get DEFAULT_WIDTH() {
return 50;
}
}
I just don't know this syntax. What does "get DEFAULT_WIDTH()" do ?
MDN has documentation for get, including a list of supporting browsers. What get does is invoke a function when the property is looked up. See Defining getters and setters for a more general explanation.
The get syntax binds an object property to a function that will be called when that property is looked up.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
The more general and exhausting explanation can be found here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters
Basically, it allows you to define what happens when a certain object property is read by code. In an analogous fashion, you can also define what should happen when code writes to that property with a set definition. In both cases you overwrite the standard behaviour for that object property.
This is all part of ECMAScript 5.1, and thus, not available in IE < 9.
What does your example code do?
In your example code, you can see that whenever the property DEFAULT_WIDTH is read, a constant value will be returned. I guess the intention of this is to make sure DEFAULT_WIDTH cannot be redefined as some other value (which it in fact can, but reading it will still return 50).
Defining a getter on existing objects using defineProperty
To append a getter to an existing object later at any time, use Object.defineProperty().
var o = { a:0 }
Object.defineProperty(o, "b", { get: function () { return this.a + 1; } });
console.log(o.b) // Runs the getter, which yields a + 1 (which is 1)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Defining_a_getter_on_existing_objects_using_defineProperty
Hello Javascript ninjas ! I have a pretty tough issue to solve and did not find any satisfying solution.
For a very specific Javascript framework I am developping, I need to be able to set the __proto__ property of a dynamically created function. I have some kind of generic function factory and need to have common definitions for the created functions.
I'd like not to argue wether or not this is a good practice as I really need to achieve this for perfectly valid reasons.
Here is a small QUnit sample that runs perfectly on Chrome latest version that shows what I need :
var oCommonFunctionProto = {};
var fnCreateFunction = function () {
var fnResult = function () {};
fnResult.__proto__ = oCommonFunctionProto; // DOES NOT WORK WITH IE9 OR IE10
return fnResult;
};
var fn1 = fnCreateFunction();
oCommonFunctionProto.randomMethod = function() { return 10; };
equal(fn1.randomMethod(), 10, "__proto__ has been set properly");
var oInstance = new fn1(); // fn1 is instantiable
As you can see on this code, anything added to oCommonFunctionProto will be available directly on any function returned by fnCreateFunction method. This allows to build prototype chain on Function objects (like it's often done on prototype chains for objects.
Here is the problem : __proto__ property is immutable in IE9 and IE10 and sadly, I really need to be compatible with those browsers.
Moreover :
I cannot use any third party. I need a fully functional code that do not depend on anything else.
As you can see, the randomMethod was added after the creation of the function. I really need the prototype chaining as in my scenarios, this objects will me modified after function creations. Simply duplicating oCommonFunctionProto properties on the function prototype will not work.
I'm perfectly okay with suboptimal code as long as it does the job. This will be a compatibility hack just for IE9/IE10. AS long as it does the job, I'll be happy.
It could be okay to set the __proto__ at function creation. It's better if I can do it afterwards, but if I have no choice, this can be acceptable.
I tried every hack I could but did not find any way to bypass this limitation on IE9/IE10.
TL;DR : I have to be able to set __proto__ on a javascript function without the help of any third party in IE9 and IE10.
Based on other answers and discussions, it appears this is just not possible for IE<11.
I finally dropped prototype chains, be it for Objects or Functions, in favor of flattened prototype and notification when a logical "parent" prototype changes to update "child" prototype accordingly.
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.
It's possible to set the individual elements of a function arguments property (what Mozilla calls an 'array-like' property), however Mozilla reports it is not possible to add elements to this property in SpiderMonkey 1.5 though this is fixed in 1.6 (ref. the note on SpiderMonkey here... https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments).
This is a useful property, chaining constructors from subclasses, creating a list of arguments to pass to a function (e.g., myclassmethod.apply(this, arguments)), etc.
However I've found V8 will not extend the length in the same way Mozilla reports of SpiderMonkey 1.5. (Not sure what the status is with other JavaScript engines, Opera, Rhino, etc.).
Is this actually an ECMA feature? Has Mozilla got it wrong in considering this a bug, or does V8 have a bug to fix?
[Update] I've found using V8 that the arguments.length property can be assigned to, and so effectively arguments can be extended (or set to whatever length you require otherwise). However JSLint does complain this is a bad assignment.
[Update] Some test code if anyone wants to try this in Opera, FF etc., create an instance of a subclass calling the constructor with one arg while adding an element to arguments in the subclass constructor and calling the superclass constructor, the superclass should report two arguments:
function MyClass() {
if (arguments.length) {
console.log("arguments.length === " + arguments.length);
console.log("arguments[0] === " + arguments[0]);
console.log("arguments[1] === " + arguments[1]);
}
}
function MySubClass() {
console.log(arguments.length);
//arguments.length = 2; // uncomment to test extending `length' property works
arguments[1] = 2;
MyClass.apply(this, arguments);
}
MySubClass.prototype = new MyClass();
new MySubClass(1);
[Update] JSLint actually complains when you make any kind of assignment to arguments by the looks (e.g., arguments[0] = "foo"). So maybe JSLint has some work to do here also.
Not sure if this is what you are looking for, but you can make the arguments object into a standard array:
var args = [].slice.call(arguments, 0);
[EDIT] so you could do:
myclassmethod.apply(this, [].slice.call(arguments, 0).push(newValue));
ECMA-262 10.1.8 says that the prototype of the arguments object is the Object prototype and that the arguments object is initialized in a certain way, using the phrase "initial value". So, it would seem like you could assign any of its properties to whatever you want. I'm not sure if that's the correct interpretation though.
OK, I think we can conclude on this one.
Running the above example code on FF, Comodo Dragon, Opera and IE (all current version, Windoze) they will all accept a change of the arguments.length property to resize the (as Mozilla phrases this, 'array-like') arguemnts object. None will increase the size by assigning a value as is usual for an array (i.e., arguments[arguments.length] = "new arg").
It seems the consensus of the javascript engines is that as an 'array-like' object arguments behaves like an array, but is otherwise inclined to throw a few surprises ;) Either way the interpretation of the ECMA standard appears to be on the face of it at least consistent across the board, and so the semantics are not really an issue (the whys and wherefores being the only remaining question but of historical interest only).
Neither MSDN nor Mozilla seem to have this documented (not sure where V8 or Opera hide their JS docs) - in a nutshell to conclude some documentation would definitely not go amiss. At which point I will bow out, however if someone could opportunistically drop the hint to the relevant parties at some point it is a useful technique to use once in a while.
Thanks for all who have taken the time to look at this question.
[Update] BishopZ has pointed out above that .apply will take an array of arguments anyway (this has slipped my mind since I last used it many years ago, and which solves my problem). However the 'array-like' arguments can still be used, and might even be preferable in some situations (easier for example to pop a value onto, or just to pass on arguments to a superclass). Thanks again for looking at the issue.