Having a getter and a function with the same name in javascript - javascript

I need to make a change but continue providing backwards-compatibility for some time, but I can't figure out how to accomplish this.
I have an Object like this:
MyObject = (function() {
// vars here and there
var myVar
// a bunch of code
return {
get myVar() { return myVar },
myVar: function() { return myVar }
}
}())
This doesn't work. I want to be able to get myVar both with
MyObject.myVar
and
MyObject.myVar()
Is it possible? Even better, is there any possibility to accomplish that and make it cross-browser compatible? (Right now I know the get notation is not supported by Internet Explorer)
Thanks.
UPDATE:
Because it seems not possible, is there any way to make what I have now, get myVar() browser-compatible with Internet Explorer?
So all browsers can access MyObject.myVar
As long as I can continue providing a getter to myVar and it's compatible with Internet Explorer, there is no need to move to myVar() but I couldn't find a feasible solution to make the current way (MyObject.myVar) compatible other than moving to a function-like getter.

No, this is not possible. In javascript, there is no concept of fields and methods, only property of an object, no matter the property is a value or a function (function is also an object.)
If MyObject.myVar is not a function, then MyObject.myVar() will produce an error.
The only thing you could do is have two properties.
MyObject.myVar
And
MyObject.getMyVar()

It IS possible, though your code will look rather nasty. Since functions are objects, they have a valueOf property, too. Exploit that by overriding it with a reference to the method itself, and you're there:
var foo = (function()
{
var bar = 'foobar';
var r = {
bar:function()
{
return bar;
}
};
r.bar.toString = r.bar.valueOf = r.bar;//valueOf && toString invoke the method
return r;
})();
Be advised, its type will be an object all the same, so strict comparisons won't work:
foo.bar =='foobar'//true
foo.bar === 'foobar'//false
alert(foo.bar+'');//alerts foobar
alert(foo.bar);//alerts foobar now, setting toString to reference the method, too
console.log(foo.bar());//foobar <= still works, and here strict comparisons do work
This can cause lots of nasty bugs that could leave you scratching your hair for up to the point there's no hair left to scratch. Not to mention other people that might end up maintaining your code!

This is not possible because it would be ambiguous. MyObject.myVar does invoke the getter, if followed by () the object as returned by the getter is executed. Therefore because MyObject.myVar() has a meaning when a getter is present it is not possible to decide for the interpreter that you want to call your function instead.

I guess this works:
function test() {
var myVar = 5;
return {
/*#cc_on
/*#if (#_jscript_version)
myVar: function() { return myVar }
#else #*/
get myVar() { return myVar }
/*#end
#*/
};
}
var a = test();
var b = a.myVar/*#cc_on () #*/
alert(b) // alerts 5
http://jsfiddle.net/XS7fU/2/

Related

Override JS method i Java style [duplicate]

I would like to override a Javascript built-in function with a new version that calls the original (similarly to overriding a method on a class with a version that calls super in many languages). How can I do this?
For example...
window.alert = function(str) {
//do something additional
if(console) console.log(str);
//super.alert(str) // How do I do this bit?
}
Store a reference to the original function in a variable:
(function() {
var _alert = window.alert; // <-- Reference
window.alert = function(str) {
// do something additional
if(console) console.log(str);
//return _alert.apply(this, arguments); // <-- The universal method
_alert(str); // Suits for this case
};
})();
The universal way is <original_func_reference>.apply(this, arguments) - To preserve context and pass all arguments. Usually, the return value of the original method should also be returned.
However, it's known that alert is a void function, takes only one argument, and does not use the this object. So, _alert(str) is sufficient in this case.
Note: IE <= 8 throws an error if you try to overwrite alert, so make sure that you're using window.alert = ... instead of alert = ....
There is no "super". Anyway, create a closure to "keep" around the original function-object.
Note the "self invoking function" that returns a new function-object (that is assigned to the window.alert property). The new function-object returned creates a closure around the variable original which evaluates to the original value of window.alert that was passed in to the "self invoking function".
window.alert = (function (original) {
return function (str) {
//do something additional
if(console) {
console.log(str)
}
original(str)
}
})(window.alert)
However, I believe some browsers may prevent alert and other built-ins from being modified...
Happy coding.
I'm assuming your question is how do you overwrite a built-in and still be able to call it. First off as a disclaimer, you should never overwrite built ins unless you have a good reason for doing it since it will make it impossible to debug/test.
This is how you would do it:
window._alert = window.alert;
window.alert = function(str) {
if(console) console.log(str);
window._alert(str);
}
How to do simple classical inheritance in Javascript:
SuperClass.call(this) // inherit from SuperClass (multiple inheritance yes)
How to override functions:
this.myFunction = this.myFunction.override(
function(){
this.superFunction(); // call the overridden function
}
);
The override function is created like this:
Function.prototype.override = function(func)
{
var superFunction = this;
return function()
{
this.superFunction = superFunction;
return func.apply(this,arguments);
};
};
Works with multiple arguments.
Fails when trying to override undefined or nonfunctions.
Makes "superFunction" a "reserved" word :-)
JavaScript does not use a classical inheritance model. There is a nice article here which describes a way to write your classes so that a similar syntax can be used, but it's not natively supported.
By using proxy object you can do this.
window.alert = new Proxy(window.alert , {
apply: function(target,that,args){
console && console.log(args.join('\n'));
target.apply(that,args)
}})

Why does javascript concatenate function names in multiple assignment to properties?

This is an edge case and probably bad practice, but it made me curious about some js internals. Can anyone explain why chrome dev tools tells me that I have created a function named a.a.b.b here?
Note that this does not happen unless you are assigning to a property. Otherwise both a and b appear to refer to a function object named 'b':
By the way, I originally encountered this here when trying to answer my own question about dat.gui.js .
This has nothing to do with the language spec.
It's a DevTools enhancement for debugging convenience, which is ported recently in Chrome.
Remember what we used to do?
function F() {}
// notice it's a NAMED function expression
F.prototype.asdf = function _asdf() { debugger; };
var f = new F();
f.asdf();
Then in breakpoint debugging, we can find the method by its name _asdf from function call stack. Otherwise it's the pain in the ass to do that from a list of (anonymous function).
In latest Chrome, when you assign an anonymous function as an object property, an alias will be attached to it.
var a = {}, b = {};
a.a = b.b = function() { debugger; };
a.b = b.a = function _abba() { debugger; };
Remember, it's just a DevTools enhancement, the method remains anonymous:
a.a.name; // ""
a.b.name; // "_abba"
But it's very helpful in breakpoint debugging:
a.a();
a.b();
EDIT:
I'm not very sure why the alias is generated as a.a.b.b, it looks very easy but kind of... stupid. However, in practice we seldom do a.a = b.b = func... thing (lucky). Instead, we define a method in one place, and do inheritence when necessary, rather than copy reference directly.
So in a good programming practice, the alias should and would exactly reflect where you define the method. For example, alias Dog.bark in breakpoint clearly maps to Dog.prototype.bark in source code, even if it's called on a Puppy instance, and we don't have to do old school named function expression.
function Dog() {}
Dog.prototype.bark = function() { alert("Woof!") }; // anonymous function expression here
function Puppy() {}
Puppy.prototype = new Dog();
(new Puppy()).bark(); // break point alias -> Dog.bark
One more thing, when I discovered this feature, I can't stop thinking of it - does it imply that Chrome will implement ES6 class very soon? How exciting!

How to organise my code in 'modules'?

I'm trying to wrap my head around organising my code. I have several modules within my project, which I'd like to organise.
The point is that all what has come to my mind doesn't work out. I'm currently thinking of four ideas:
Simple object - Is not useful due to scoping issues. Using this.a would work, but this has a different meaning depending on who called it so it's not reliable. For example, I once assigned a function to a WebSocket class, but all of a sudden this referred to the WebSocket instance when the function was called by a WebSocket event. I could use bind(foo) each time I call the function, but there must be another way I guess.
var foo = {
a: 3,
s: function() {
alert(a); // a doesn't exist in this scope
alert(this.a); // 'this' isn't always foo
alert(foo.a); // I would have to put 'foo.' before each variable
// reference, but I'm sure that's not the way to do it
}
};
Instance - a is not defined. Again, this isn't reliable.
var foo = function() {
this.a = 3;
this.s = function() {
alert(a);
};
};
var foo_instance = new foo();
foo_instance.a = 4;
foo_instance.s(); // Error: a is not defined
Closure with instance - Doesn't return anything; it stays undefined.
var foo = (function() {
this.a = 3;
this.s = function() {
alert(a);
};
})();
// foo === undefined
Closure with getter/setter - Works beautifully on Chrome, however IE doesn't support getters/setters.
var foo = (function() {
var a = 3;
return {
get a() { return a; },
set a(v) { a = v; },
s: function() {
alert(a); // Doesn't work in IE as getters/setters are
// not supported
}
};
})();
How would I effectively organise my modules, so that I can access the properties safely and in a cross-browser way?
Thanks.
3 is undefined because you are not returning anything. instead of assigning properties and methods to 'this', try this:
var foo = (function() {
var self = {};
self.someProperty = someValue;
self.someFunction = function () {
}
return self;
}());
foo will now return an object with the properties and methods defined. doing it this way you never have to wonder what 'this' is actually referring to.
It seems to me that you have no real understand of how this and closures work in JavaScript.
Please read up on both of these topics and also have a look at namespaces.
There are a ton of different ways how one could realize modules, but it doesn't make much sense to talk about it here unless you understand the basics, so please refer to my links for a in-depth explanation.
Your first code snippet uses a closure, and corresponds to a pattern that was made popular by the yui library. The second pattern corresponds to the notion of private, public and privileged members of an object.
I recommend that you read this staple article about javascript private members by Douglas Crockford, and go either with the first option or the second. They are semantically equivalent.
(The third and the forth snippets seem overly complex to me in comparison to the first two)

Changing the behavior of JavaScript's with statement to prevent assignment from modifying the global object

The with statement in JavaScript first checks if the requested property of the object exists before it decides if it should set the property of the given object or the property of the global object.
Example:
var x = {a:5};
with(x){
a = 6; //x.a is now 6
b = 7; //window.b is now 7, x.b still does not exist
}
I want to change the behavior of with, so that when it checks for the presence of a property on the object I'm working with it will always treat it as though it exists, preventing assignments within the block from accidentally modifying the global object.
Could this be accomplished by overloading the function that checks whether the property of the object exists or not? For example something like this:
Object.prototype.__hasOwnProperty__ = function(p){
return true;
}
var x = {a:5};
with(x){
a = 6; //x.a is now 6
b = 7; //x.b should now be 7
}
My code runs on node.js & V8, so it doesn't matter if the solutions only work with this.
Hope someone has an ide how I realize this.
Thanks for your help!
You're trying to fundamentally change how the with statement works in JavaScript. This isn't possible, because you have no guarantee that the interpreter is using hasOwnProperty (or any other construct you have access to) to check for the presence of a property on the object you're working with.
You're joining a nice tradition of wishing that with worked differently, but it doesn't. It works how it does and it's best avoided.
Two things:
Don't modify the Object.prototype. It's considered bad practice and will cause unexpected result everywhere, plus other JS frameworks won't even run if it's been modified.
Please don't use with. It is being deprecated from javascript because it can't be determined how it should best function when there is local variable with the same name as a property.
If you need to iterate over the properties of an object, just do this:
for (var i in myObject) {
if (myObject.hasOwnProperty(i)) {
// processing logic here
}
}
You mentioned code that would help you achieve overriding that setting logic. https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects has information on using defineSetter to override the setting portion, but it is highly recommended, on not even possible from JavaScript 1.8.1 and after. I would recommend another approach.
To keep variables out of the global scope, you can use an anonymous function; since JavaScript has functional scoping, all variables defined in a function are local in scope. It requires you to declare variables properly, though, but I would highly suggest that under any circumstance.
(function () {
var a = 1;
alert("a is... " + a);
// do more stuff here
}());
alert(typeof a); // should be undefined
Example: http://jsfiddle.net/AWDzV/
This doesn't specifically deal with your with statement, but it is probably the best way to accomplish what you're looking for. Then, all you have to do to emulate the behavior of the with statement is to use a variable:
(function () {
var a = 1,
some_very_long_object_name = {a: 1, b: 2, c: 3},
obj = some_very_long_object_name;
obj.a = 2;
obj.b = 3;
obj.c = 4;
}());
alert(typeof a); // should be undefined
Not the best code in the world, but it does demonstrate that using a short variable name to replace a long object name works perfectly. All-in-all, I feel this is probably the best solution.
Of course, any variable not declared properly will "leak" into the global scope:
(function () {
a = 1; // notice the lack of "var" keyword
}());
alert(a); // should be 1
Example: http://jsfiddle.net/AWDzV/1/
But you can use JSLint to help catch that particular error. Running it on the above code yields the following error message:
Error: Implied global: a 2,4, alert 4
I've found a way to totally isolate a skript. It's not good code, but it works.
X = 5;
function ExecuteIsolated(code){
var vars = [];
(function(){
for(var v in window){
vars.push(v);
}
eval("var "+vars.join(",")+";");
//Totally isolated code here:
eval(code);
//End of totally isolated code
})();
var i = 0;
for(var v in window){
if(vars[i++] != v){
delete window[v];
i--;
}
}
}
ExecuteIsolated("X = 8");
console.log(X);
Maybe its useful for someone else ;)

How to get the function name from within that function?

How can I access a function name from inside that function?
// parasitic inheritance
var ns.parent.child = function() {
var parent = new ns.parent();
parent.newFunc = function() {
}
return parent;
}
var ns.parent = function() {
// at this point, i want to know who the child is that called the parent
// ie
}
var obj = new ns.parent.child();
In ES6, you can just use myFunction.name.
Note: Beware that some JS minifiers might throw away function names, to compress better; you may need to tweak their settings to avoid that.
In ES5, the best thing to do is:
function functionName(fun) {
var ret = fun.toString();
ret = ret.substr('function '.length);
ret = ret.substr(0, ret.indexOf('('));
return ret;
}
Using Function.caller is non-standard. Function.caller and arguments.callee are both forbidden in strict mode.
Edit: nus's regex based answer below achieves the same thing, but has better performance!
ES6 (inspired by sendy halim's answer below):
myFunction.name
Explanation on MDN. As of 2015 works in nodejs and all major browsers except IE.
Note: On bound functions this will give "bound <originalName>". You will have to strip the "bound " if you want to get the original name.
ES5 (inspired by Vlad's answer):
If you have a reference to the function, you can do:
function functionName( func )
{
// Match:
// - ^ the beginning of the string
// - function the word 'function'
// - \s+ at least some white space
// - ([\w\$]+) capture one or more valid JavaScript identifier characters
// - \s* optionally followed by white space (in theory there won't be any here,
// so if performance is an issue this can be omitted[1]
// - \( followed by an opening brace
//
var result = /^function\s+([\w\$]+)\s*\(/.exec( func.toString() )
return result ? result[ 1 ] : '' // for an anonymous function there won't be a match
}
I have not run unit tests on this, or verified implementation
differences, but in principle it should work, if not leave a comment.
Note: won't work on bound functions
Note: that caller and callee are considered deprecated.
[1] I include it here because it is legal and often enough syntax highlighting tools fail to take into account the white space between function name and parenthesis. On the other hand, I'm not aware of any implementation of .toString() that will include white space here, so that's why you can omit it.
As an answer to the original question, I would drop parasitic inheritance and go for some more traditional OOP design patterns. I wrote a TidBits.OoJs to comfortably write OOP code in JavaScript with a feature set mimicking C++ (not yet complete, but mostly).
I see from the comments that you would like to avoid passing information parent needs to it's constructor. I must admit that traditional design patterns won't save you from that one though, since it is generally a considered a good thing to make your dependencies obvious and enforced.
I would also suggest to steer away from anonymous functions. They only make debugging and profiling a PITA because everything just shows up as "anonymous function", and there is no benefit to them that I'm aware of.
what you're doing is assigning unnamed function to a variable. you probably need named function expression instead ( http://kangax.github.com/nfe/ ).
var x = function x() {
console.log( arguments.callee.name );
}
x();
however I'm not sure how much cross-browser that is; there's an issue with IE6 that makes you function's name leak to the outer scope. also, arguments.callee is kind of deprecated and will result in error if you're using strict mode.
It looks like the most stupid thing, that I wrote in my life, but it's funny :D
function getName(d){
const error = new Error();
const firefoxMatch = (error.stack.split('\n')[0 + d].match(/^.*(?=#)/) || [])[0];
const chromeMatch = ((((error.stack.split('at ') || [])[1 + d] || '').match(/(^|\.| <| )(.*[^(<])( \()/) || [])[2] || '').split('.').pop();
const safariMatch = error.stack.split('\n')[0 + d];
// firefoxMatch ? console.log('firefoxMatch', firefoxMatch) : void 0;
// chromeMatch ? console.log('chromeMatch', chromeMatch) : void 0;
// safariMatch ? console.log('safariMatch', safariMatch) : void 0;
return firefoxMatch || chromeMatch || safariMatch;
}
d - depth of stack. 0 - return this function name, 1 - parent, etc.;
[0 + d] - just for understanding - what happens;
firefoxMatch - works for safari, but I had really a little time for testing, because mac's owner had returned after smoking, and drove me away :'(
Testing:
function limbo(){
for(let i = 0; i < 4; i++){
console.log(getName(i));
}
}
function lust(){
limbo();
}
function gluttony(){
lust();
}
gluttony();
Result:
Chrome:
Fitefox:
This solution was creating only just for fun! Don't use it for real projects. It does not depend on ES specification, it depends only on browser realization. After the next chrome/firefox/safari update it may be broken.
More than that there is no error (ha) processing - if d will be more than stack length - you will get an error;
For other browsers error's message pattern - you will get an error;
It must work for ES6 classes (.split('.').pop()), but you sill can get an error;
Any constructor exposes a property name, which is the function name. You access the constructor via an instance (using new) or a prototype:
function Person() {
console.log(this.constructor.name); //Person
}
var p = new Person();
console.log(p.constructor.name); //Person
console.log(Person.prototype.constructor.name); //Person
This might work for you:
function foo() { bar(); }
function bar() { console.log(bar.caller.name); }
running foo() will output "foo" or undefined if you call from an anonymous function.
It works with constructors too, in which case it would output the name of the calling constructor (eg "Foo").
More info here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller
They claim it's non-standard, but also that it's supported by all major browsers: Firefox, Safari, Chrome, Opera and IE.
You can't. Functions don't have names according to the standard (though mozilla has such an attribute) - they can only be assigned to variables with names.
Also your comment:
// access fully qualified name (ie "my.namespace.myFunc")
is inside the function my.namespace.myFunc.getFn
What you can do is return the constructor of an object created by new
So you could say
var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
You could use this, for browsers that support Error.stack (not nearly all, probably)
function WriteSomeShitOut(){
var a = new Error().stack.match(/at (.*?) /);
console.log(a[1]);
}
WriteSomeShitOut();
of course this is for the current function, but you get the idea.
happy drooling while you code
You could use Function.name:
In most implementations of JavaScript, once you have your constructor's reference in scope, you can get its string name from its name property (e.g. Function.name, or Object.constructor.name
You could use Function.callee:
The native arguments.caller method has been deprecated, but most browsers support Function.caller, which will return the actual invoking object (its body of code):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller
You could create a source map:
If what you need is the literal function signature (the "name" of it) and not the object itself, you might have to resort to something a little more customized, like creating an array reference of the API string values you'll need to access frequently. You can map them together using Object.keys() and your array of strings
You can use name property to get the function name, unless you're using an anonymous function
For example:
var Person = function Person () {
this.someMethod = function () {};
};
Person.prototype.getSomeMethodName = function () {
return this.someMethod.name;
};
var p = new Person();
// will return "", because someMethod is assigned with anonymous function
console.log(p.getSomeMethodName());
now let's try with named function
var Person = function Person () {
this.someMethod = function someMethod() {};
};
now you can use
// will return "someMethod"
p.getSomeMethodName()
You can use constructor name like:
{your_function}.prototype.constructor.name
this code simply return name of a method.
as part as ECMAScript 6 you can use Function.name method
function doSomething() {}
alert(doSomething.name); // alerts "doSomething"
I know this is a old question but lately I've been facing some similar issue while trying to decorate some React Component's methods, for debugging purposes. As people already said, arguments.caller and arguments.callee are forbidden in strict mode which is probably enabled by default in your React transpiling. You can either disable it, or I've been able to come up with another hack, because in React all class functions are named, you can actually do this:
Component.prototype.componentWillMount = function componentWillMount() {
console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}
This worked for me.
function AbstractDomainClass() {
this.className = function() {
if (!this.$className) {
var className = this.constructor.toString();
className = className.substr('function '.length);
className = className.substr(0, className.indexOf('('));
this.$className = className;
}
return this.$className;
}
}
Test code:
var obj = new AbstractDomainClass();
expect(obj.className()).toBe('AbstractDomainClass');
I had a similar problem and I solved it as follows:
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace( "function ", "" );
}
This code implements, in a more comfortable fashion, one response I already read here at the top of this discussion.
Now I have a member function retrieving the name of any function object.
Here's the full script ...
<script language="javascript" TYPE="text/javascript">
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace("function ", "" );
}
function call_this( _fn ) { document.write( _fn.myname() ); }
function _yeaaahhh() { /* do something */ }
call_this( _yeaaahhh );
</script>
If I understood what you wanted to do, this is what I do inside a function constructor.
if (!(this instanceof arguments.callee)) {
throw "ReferenceError: " + arguments.callee.name + " is not defined";
}
This will work in ES5, ES6, all browsers and strict mode functions.
Here's how it looks with a named function.
(function myName() {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at myName (<anonymous>:2:15)
Here's how it looks with an anonymous function.
(() => {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at <anonymous>:2:15
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables.
{
function parent() {
console.log(a.name);
}; let a = parent
}
{
function child() {
console.log(a.name)
}; let a = child
};
parent();//logs parent
child();//logs child
Note: Nested functions cease to be source elements, and are hence not hoisted.
Also, this technique cannot work with anonymous functions.
Just try Function.name
const func1 = function() {};
const object = {
func2: function() {}
};
console.log(func1.name);
// expected output: "func1"
console.log(object.func2.name);
// expected output: "func2"
look here: http://www.tek-tips.com/viewthread.cfm?qid=1209619
arguments.callee.toString();
seems to be right for your needs.
Easy way to get function name from within fuction you are running.
function x(){alert(this.name)};x()
you can use Error.stack to trace the function name and exact position of where you are in it.
See stacktrace.js

Categories