Adding a dynamic function to an object - javascript

I'm trying to get this to work, but it doesn't:
var i;
i.test = function() {
alert("hello");
}
i.test();
I expect the code to alert 'hello', but instead, the Firefox error console shows:
missing } in XML expression
alert("hello");
---------------^
How do I fix this...

Your i isn't assigned to anything so it's not an object. It is, in fact, pointing to the global undefined object which happens to be read-only in Firefox (as it should be). You need:
var i = {}; //init to empty object
then all will be fine.

You can't add a function to an undefined value, you need to create an actual object:
var i = {};
Although not required, you should have a semicolon at the end of the statement to avoid ambiguity:
i.test = function() {
alert("hello");
};

var i = {};
i.test = function() {
alert("hello");
};
You had two separate issues. You were not initializing i (as noted by slebetman), and you were missing a semi-colon, forcing the interpreter to use semi-colon replacement.

Related

Anonymous functions inside an object

I have a Javascript snippet like this:
var a = {ac: 10, function(){console.log("hi")}}
The browser is not throwing an error for this. So it may be valid.
But when I use
var a = {ac: 10, function hi(){console.log("hi")}}
The browser throws error:
Uncaught SyntaxError: Unexpected identifier
Can anybody tell me how can I make use of the first code in any scenario in Javascript
Thanks in Advance
What's happening here is that ES6 allows you to have a shorthand syntax for function definitions. This: const obj = { method() {} } basically translates to this const obj = { method: function() {} }.
So, when you use this snippet var a = {ac: 10, function(){console.log("hi")}} you're telling the browser that function is not a reserved word for you inside that object, rather the name of the property that you want to use, so you end up with an object that has a method called function.
Btw, you should avoid this in the future, do not use reserved keywords for another purpose.
In the second snippet var a = {ac: 10, function hi(){console.log("hi")}} what's happening is that you're trying to have a function declaration (function hi(){console.log("hi")}) inside an object, and that's a syntax error. By giving the function a name, you changed from a shorthand syntax for methods declarations inside the object to a function definition. If you use a proper naming (avoiding reserved words) for this shorthand syntax, or declare the function outside and reference it inside the object, you shouldn't have problems.
What you are doing in your first example is called shorthand method names, and is a newer way of initialising functions in js objects. What is actually happening in your example, is it is taking the name of the object key (and the function name) to befunction. But 'function' can be replaced with any key/name. For example:
var a = {
ac: 10,
other() { console.log('inside other') }
}
You can read more about the different ways to initialise an object here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
The reason why your second example fails, is simply because it is invalid syntax. If you remove the word function from your second example, it will work as I think you were originally expecting it to.
You could try structuring it like this:
var obj = {
ac: 10,
hello: function(){
console.log("Goodbye");
}
}
console.log(obj.ac);
console.log(obj.hello());

Show function name inside the function itself [duplicate]

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

variable is already defined

sometime i need to replace a variable value to another
so i use this method
var $$test = "First",
$$test = "Second";
the code work fine but i use jsfiddle JSHint button to check any error on JavaScript (it helped me a lot)
but i got this error '$$test' is already defined
so what is the ideal method to re define any variable
Thank you :)
You're getting that error because you're declaring the same variable twice.
var a = foo, a = bar;
Is the same as:
var a = foo;
var a = bar;
Just break your code in two lines, and you won't get that warning. Like this:
var a = foo;
a = bar;
Also notice that if you declare a variable with a value, and then right after that you change its value, the first line is a noop.
Don't use a comma. You should redefine it as a new statement:
var $$test = 'First';
$$test = 'Second';
this code is trying to define two variable s called $$test. They need to have uniuque names.
Try using $$test1 and $$test2
updated for you http://jsfiddle.net/9CdJN/2/
(function($){
var $$test = "First";
$$test = "Second";
console.log($$test);
})(jQuery);
The problem is that you have a comma , at the end of the first line instead of a semi-colon ;.
Each Javascript statement ends with a semi-colon. You can define multiple variables with a single var by separating them all with a comma.
var var1=1, var2=2, var3=3;
is the same as
var var1=1,
var2=2,
var3=3;
Because you had a comma in the first line, the browser believes you are declaring two different variables with the same name. To fix it, just change it to this:
var $$test = "First";
$$test = "Second";

Putting arrays into custom objects

I am attempting to build my first custom object and it looks something like this:
function URLObject()
{
this.syllables = new Array();
etc...
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
}
var myobj = new URLObject();
myobj.AdtoSyllables("text");
The execution of the above code results in the JS engine printing out the following:
This is Sylcount: NAN
-or-
This is SylCount: undefined.
I have looked at information in Head First Javascript, in the Javascript bible, and on various JS websites. All of them cover in exhaustive detail the use of arrays of objects, but none of them discuss arrays within objects.
And yet I am doing something wrong here and I do not know what. Can anyone help?
Here you go:
function URLObject()
{
this.syllables = [];
etc...
}
URLObject.prototype.addToSyllables = function(aWord) {
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
var myobj = new URLObject();
myobj.adtoSyllables("text");
.prototype adds the function declared after it to every object constructed by the constructor function. (in your case every object that was instantiated by new URLObject())
Firstly, the code as posted actually works for me on Chrome and Firefox; so this must depend on the JavaScript engine, or else there's something funky going on.
Update: I suspect what may be confusing you is some separate call to AddtoSyllables (in code you haven't shown us) where suddenly this.syllables is no longer defined. This is where the behavior of this can get confusing. I've created a jsFiddle to hopefully explain how it works a bit better for you.
http://jsfiddle.net/J3tUb/
That said, it is often very possible to write code like this without having to use this (or the prototype) at all. For instance:
function createURLObject() {
// Use closed-over locals instead of attaching properties.
var syllables = new Array();
function AddToSyllables(AWord) {
// Since syllables is closed over, it is accessible here
// (but WON'T be accessible outside this scope).
syllables.push(AWord);
return syllables.length;
}
// Expose whatever functionality you want to be "public"
// in the returned object.
return {
AddToSyllables: AddToSyllables
};
}
var myObj = createURLObject();
myObj.AddToSyllables("text");
It is, of course, valuable to understand JavaScript's quirky (and surprising, to most developers coming from other languages) behavior with respect to this. That said, once you do understand it, I suspect you will find that it can often be avoided altogether.
you need to do this :
function URLObject()
{
var that = this;
that.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
etc...
Like this you can add method and attributes to one object.
The issue you are having is that the function AddtoSyllables is not a member function or method of the URLObject. It is just a nested function with no object attachments, so all usages of this will result in returning the dom window object. The correct way of declaring the AddtoSyllables function is this:
function URLObject()
{
//...
}
URLObject.prototype.AddtoSyllables = function (AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
To explain the reasons of the behavior in the question, I'd like to clarify that objects in javascript are treated like a map, dictionary or a key-value pair (use the term what suits you best). Using the syntax x.y = value; is equivalent putting the value value into the map x with key y. Having the code:
this.AddtoSyllables = AddtoSyllables;
function AddtoSyllables(AWord)
{
var SylCount = this.syllables.length;
alert("This is SylCount: " + SylCount);
}
adds the AddtoSyllables function as an entry to the object this points to.
The code
myobj.AdtoSyllables(...)
is equivalent to
myobj["AdtoSyllables"](...) // now a retreiaval operation
or even
var fn = myobj["AdtoSyllables"];
fn (...);
Inside the AdtoSyllables function, this is used. Against common expectations, it is not a pointer to the myobj.
The cause of this is that AddtoSyllables is treated as a static method of the URLObject class (as OOP guys would understand it), or even a loose static function (like in C). To make JS treat it like a member of the URLObject object (an instance method to OOP guys), JS must be told to do so. This is achieved through the URLObject.prototype.AddtoSyllables = .... which equivalents to declaration of an instance method.
From an alternative point of view:
function foo() { /* some code using `this` */ }
var bar = {};
var baz = {};
bar.foo = foo; // same as bar["foo"] = foo;
baz.foo = foo; // same az baz["foo"] = foo;
In the above code, this usages inside foo will neither point to bar, nor baz. At the same time bar.foo will point to the very same instance as baz.foo, for foo is also an object.

"this" in JavaScript

I'm trying to understand the syntax of how to put together a JavaScript function as an object.
Q: Is this the right way to do it?
The reason why I ask is because I'm looking at it in Firebug and I was hoping to be able to drill down and see the value of myVar and myVariable, but instead Firebug only says that "this" is an object Object.
var myObject = {
init: function() {
var myVar = 1;
myObject.myVariable = 2;
console.log('"this" when called as an object: ' + this);
}
}
myObject.init();
Also, what's the funny little syntax to call it directly upon declaration? Something about (), but when I remove the last line and put () at the end of the declaration, I get a syntax error.
This will create a string:
'"this" when called as an object: ' + this
But this is not a string, so its toString() prototype gets called. That's why you only see [object Object].
If you want to have Firebug display the actual object, do a simple console.log(this) or to see the contents directly use console.dir(this).
The "funny little syntax" doesn't really apply here, because you're not really creating a "function object" — that's just an object with a property whose value is a reference to a function object.
However, though it's been done to death on Stackoverflow, you're probably talking about something like this:
var myobject = (function() {
var something = { whatever: "for example" };
return {
init: function() {
this.foo = "hello";
// initialize
},
getSomething: function() { return something.whatever; }
};
})();
Now "myobject" is initialized by a call to an anonymous function, which will be thrown away right after that statement. The closure formed by the function invocation, however, remains alive.
Here is a nice reference for JavaScript object creation

Categories

Resources