I just learned this way of initializing a variable in javascript:
var MyGlobalVar = {
Property1 : 1,
Property2 : "Two"
}
Which is pretty neat because is a lot like a static object. But is there any way I can run initialization code inside it, kinda like a static constructor would do?
How about using eval, such as Property1 : eval("[code to run here...]");?
I just don't want to put any initialization or part of my object's definition outside the object itself (outside the brackets).
Edit: My initialization code would actually return a filled up array, so Property2 would be this array. But I don't want to recreate this array every time is needed.
If I understood what you want:
var MyGlobalVar = {
Property1 : 1,
Property2 : (function(){ var arr=["this", "is", "an", "array"];return arr; })()
}
Property2 will be an array...you can have any code after that, and whatever you return will be its value.
EDIT: I changed the above code to return an array.
If you want a constructor, why not use a constructor?
var MyGlobalVar = new function() {
// run whatever code you want in here
// The new object being constructed is referenced via "this"
this.Property1 = 1;
this.Property2 = "Two";
};
This code uses an anonymous function as the constructor. You can run whatever code you want inside. The new object is referenced by this, and it is returned automatically, so MyGlobalVar will look like:
{
Property1: 1,
Property2: "Two"
}
Another approach, and one that is perhaps more common than using an anonymous constructor, is to use a module pattern. It is very similar, but it doesn't use the function as a constructor by calling it with new, and it just returns an object literal.
The above code would be rewritten like this:
var MyGlobalVar = (function() {
// run whatever code you want in here
// The new object is an object literal that we create and return
var _new_obj = {
Property1: 1,
Property2: "Two"
};
return _new_obj;
})();
Just like the first example, it gives you an enclosed environment where you can run whatever code you need in creating the values to be referenced by your object.
The end result is practically identical. The only real difference is that the prototype chain of the object in the first example looks like:
_new_obj ---> {} ---> Object.prototype ---> null
whereas the prototype chain in the new version looks like:
_new_obj ---> Object.prototype ---> null
So there's a slightly shorter chain. It won't make such a difference that you should base any decision on it.
Rather than use eval, you could run an immediate function:
var v = {
prop1: function() {
// whatever
return aResult;
}()
}
Or a previously-defined function:
function foo() {
// whatever
return aResult;
}
var v = {
prop1: foo(),
}
Best to avoid eval if not strictly needed.
If you really want everything inside the object, you can run a function which you also define inside the object literal, which does the following:
runs initialization stuff
returns the value that the property should have
Something like:
var data = {
prop: (function() {
// init
return "foo";
})(),
prop2: (function() {
// init
return "bar";
})()
};
Related
I can't seem to find an example of what I'm trying to achieve, although I'm sure it has been done many times before...
I want to create an object which will have a set of properties and member functions but that I can also call directly. In the same way the jQuery object allows you to call $("selector") or $.method(...)
Here's a slimmed down version of what I'm trying to achieve :
var foobar = function(param) {
return "FOO : " + this.lookup(param);
}
foobar.vals = {
1: "one",
2: "two"
};
foobar.lookup = function (param) {
return "BAR : " + this.vals[param];
}
foobar.lookup("1")
// returns "BAR : one"
foobar("1")
// returns error since 'this' points to global scope
// I'd want it to return "FOO : BAR : one"
I've also tried various approaches with function prototype but can't seem to find a method which gives me everything I want...
var foobar = function(param) {
return "FOO : " + foobar.lookup(param);
}
will return you what you want
To understand this, maybe you should take a look at the basics of JavaScript. What are functions how to instanciate an object and what are objects...
To get something like JQuery this is not very difficult, the JQuery main object is simply a function which also has "static" functions.
to declare a variable as function you do
var myFunc = function(){};
to use the variable and extend it with static stuff you simply assign it via
myFunc.staticFunc = function(){};
this doesn't mean that myFunc.staticFunc can be accessed with this in any instance of myFucn because you didn't add the function to the prototype...
To define a class like object which can be instanciated you also define it as function and then extend the prototype. Prototype is your class definition which is used to construct the object's instance:
myFunc = function(){
// ctor
this.lala = "blub";
} ;
myFunc.prototype.objectFunc = function() {
return this.lala;
}
now the object myFunc has a function objectFunc. I have to initialize it with new...
alert(new myFunc().objectFunc());
instances can access itself with this...
To do something like jquery you'll have to do some tricks. Your global variable must be a function which returns an instance of your "real" object, which can implement whatever...
Then you can call your variable as if it is a function, e.g. myFunc()...
Hope the following example makes it more clear how this works: (can be found on jsfiddle)
(function ($) {
var myRealObj = function (outId, printText) {
this.text = printText;
$("#" + outId).append("<li>" + this.text + "</li>");
};
myRealObj.prototype.objectFunc = function () {
return this.lala
};
var myFunc = function (out, txt) {
return new myRealObj(out, txt);
};
myFunc.someFunc = function () {
myFunc("out", "myFunc.someFunc got called");
};
myFunc.static = {};
myFunc.static.someFunc = function () {
myFunc("out", "myFunc.static.someFunc got called");
};
window.$$ = myFunc;
})($);
$$("out", "test obj function");
$$.someFunc();
$$.static.someFunc();
You could add:
foobar = foobar.bind(foobar);
to make the variable refer to a bound version of the function. Any call to the (updated) "foobar" would have this bound to the original function object. You'd also have to mirror the properties if you wanted to get at them directly, which is sort-of a mess.
In the jQuery implementation, there's a separate internal function that handles the basic routing of the master $() function.
Note also that the "global" $.whatever() functions don't really have much to do with the set of methods supported by jQuery instances (objects returned from the $() function). The $ object just serves as a namespace so that those global utilities don't pollute the global (window) namespace.
you declare var foobar = function(param) {... in the global scope so this will always be a window
With respect to JS, what's the difference between the two? I know methods are associated with objects, but am confused what's the purpose of functions? How does the syntax of each of them differ?
Also, what's the difference between these 2 syntax'es:
var myFirstFunc = function(param) {
//Do something
};
and
function myFirstFunc(param) {
//Do something
};
Also, I saw somewhere that we need to do something like this before using a function:
obj.myFirstFunc = myFirstFunc;
obj.myFirstFunc("param");
Why is the first line required, and what does it do?
Sorry if these are basic questions, but I'm starting with JS and am confused.
EDIT: For the last bit of code, this is what I'm talking about:
// here we define our method using "this", before we even introduce bob
var setAge = function (newAge) {
this.age = newAge;
};
// now we make bob
var bob = new Object();
bob.age = 30;
// and down here we just use the method we already made
bob.setAge = setAge;
To answer your title question as to what is the difference between a 'function' and a 'method'.
It's semantics and has to do with what you are trying to express.
In JavaScript every function is an object. An object is a collection of key:value pairs. If a value is a primitive (number, string, boolean), or another object, the value is considered a property. If a value is a function, it is called a 'method'.
Within the scope of an object, a function is referred to as a method of that object. It is invoked from the object namespace MyObj.theMethod(). Since we said that a function is an object, a function within a function can be considered a method of that function.
You could say things like “I am going to use the save method of my object.” And "This save method accepts a function as a parameter.” But you generally wouldn't say that a function accepts a method as a parameter.
Btw, the book JavaScript Patterns by Stoyan Stefanov covers your questions in detail, and I highly recommend it if you really want to understand the language. Here's a quote from the book on this subject:
So it could happen that a function A, being an object, has properties and methods, one of which happens to be another function B. Then B can accept a function C as an argument and, when executed, can return another function D.
There is a slight difference -
Method : Method is a function when object is associated with it.
var obj = {
name : "John snow",
work : function someFun(paramA, paramB) {
// some code..
}
Function : When no object is associated with it , it comes to function.
function fun(param1, param2){
// some code...
}
Many answers are saying something along the lines that a method is what a function is called when it is defined on an object.
While this is often true in the way the word is used when people talk about JavaScript or object oriented programming in general (see here), it is worth noting that in ES6 the term method has taken on a very specific meaning (see section 14.3 Method Definitions of the specs).
Method Definitions
A method (in the strict sense) is a function that was defined through the concise method syntax in an object literal or as a class method in a class declaration / expression:
// In object literals:
const obj = {
method() {}
};
// In class declarations:
class MyClass {
method() {}
}
Method Specificities
This answer gives a good overview about the specificities of methods (in the strict sense), namely:
methods get assigned an internal [[HomeObject]] property which allows them to use super.
methods are not created with a prototype property and they don't have an internal [[Construct]] method which means that they cannot be called with new.
the name of a method does not become a binding in the method's scope.
Below are some examples illustrating how methods (in the strict sense) differ from functions defined on objects through function expressions:
Example 1
const obj = {
method() {
super.test; // All good!
},
ordinaryFunction: function ordinaryFunction() {
super.test; // SyntaxError: 'super' keyword unexpected here
}
};
Example 2
const obj = {
method() {},
ordinaryFunction: function ordinaryFunction() {}
};
console.log( obj.ordinaryFunction.hasOwnProperty( 'prototype' ) ); // true
console.log( obj.method.hasOwnProperty( 'prototype' ) ); // false
new obj.ordinaryFunction(); // All good !
new obj.method(); // TypeError: obj.method is not a constructor
Example 3
const obj = {
method() {
console.log( method );
},
ordinaryFunction: function ordinaryFunction() {
console.log( ordinaryFunction );
}
};
obj.ordinaryFunction() // All good!
obj.method() // ReferenceError: method is not defined
A method is a property of an object whose value is a function. Methods are called on objects in the following format: object.method().
//this is an object named developer
const developer = {
name: 'Andrew',
sayHello: function () {
console.log('Hi there!');
},
favoriteLanguage: function (language) {
console.log(`My favorite programming language is ${language}`);
}
};
// favoriteLanguage: and sayHello: and name: all of them are proprieties in the object named developer
now lets say you needed to call favoriteLanguage propriety witch is a function inside the object..
you call it this way
developer.favoriteLanguage('JavaScript');
// My favorite programming language is JavaScript'
so what we name this: developer.favoriteLanguage('JavaScript');
its not a function its not an object? what it is? its a method
Your first line, is creating an object that references a function. You would reference it like this:
myFirstFunc(param);
But you can pass it to another function since it will return the function like so:
function mySecondFunction(func_param){}
mySecondFunction(myFirstFunc);
The second line just creates a function called myFirstFunc which would be referenced like this:
myFirstFunc(param);
And is limited in scope depending on where it is declared, if it is declared outside of any other function it belongs to the global scope. However you can declare a function inside another function. The scope of that function is then limited to the function its declared inside of.
function functionOne(){
function functionTwo(){}; //only accessed via the functionOne scope!
}
Your final examples are creating instances of functions that are then referenced though an object parameter. So this:
function myFirstFunc(param){};
obj.myFirst = myFirstFunc(); //not right!
obj.myFirst = new myFirstFunc(); //right!
obj.myFirst('something here'); //now calling the function
Says that you have an object that references an instance of a function. The key here is that if the function changes the reference you stored in obj.myFirst will not be changed.
While #kevin is basically right there is only functions in JS you can create functions that are much more like methods then functions, take this for example:
function player(){
this.stats = {
health: 0,
mana: 0,
get : function(){
return this;
},
set : function( stats ){
this.health = stats.health;
this.mana = stats.mana;
}
}
You could then call player.stats.get() and it would return to you the value of heath, and mana. So I would consider get and set in this instance to be methods of the player.stats object.
A function executes a list of statements example:
function add() {
var a = 2;
var b = 3;
var c = a + b;
return c;
}
1) A method is a function that is applied to an object example:
var message = "Hello world!";
var x = message.toUpperCase(); // .toUpperCase() is a built in function
2) Creating a method using an object constructor. Once the method belongs to the object you can apply it to that object. example:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
this.name = function() {return this.firstName + " " + this.lastName;};
}
document.getElementById("demo").innerHTML = person.fullName(); // using the
method
Definition of a method: A method is a property of an object that is a function. Methods are defined the way normal functions are defined, except that they have to be assigned as the property of an object.
var myFirstFunc = function(param) {
//Do something
};
and
function myFirstFunc(param) {
//Do something
};
are (almost) identical. The second is (usually) just shorthand. However, as this jsfiddle (http://jsfiddle.net/cu2Sy/) shows, function myFirstFunc will cause the function to be defined as soon as the enclosing scope is entered, whereas myFirstFunc = function will only create it once execution reaches that line.
As for methods, they have a this argument, which is the current object, so:
var obj = {};
obj.func = function( ) {
// here, "this" is obj
this.test = 2;
}
console.log( obj.test ); // undefined
obj.func( );
console.log( obj.test ); // 2
The exact syntax you showed is because you can also do this:
function abc( ) {
this.test = 2;
}
var obj = {};
obj.func = abc;
obj.func( ); // sets obj.test to 2
but you shouldn't without good reason.
ecma document
4.3.31method :
function that is the value of a property
NOTE When a function is called as a method of an object, the object is
passed to the function as its this value.
It is very clear: when you call a function if it implicitly has a this (to point an object) and if you can't call the function without an object, the function deserves to name as method.
What's the difference between these two method of defining a 'class' in JavaScript?
Method One
Define method within the constructor:
function MyClass()
{
this.foo = function() { console.log('hello world!'); };
}
Method Two
Define method on the prototype:
function MyClass()
{}
MyClass.prototype.foo = function() { console.log('hello world!'); };
The first will create a new function object on each instantiation of your object, the second will assign a reference to a prototype method to each instance. In short: the second is more efficient, because all instances will share a single function object.
That's just the logic of a prototype chain, you can try and access anything via any object:
var objLiteral = {foo:'bar'};
When accessing objLiteral.foo JS will first look at the properties that the object itself has defined, and return the value if it is found. If JS can't find the property on the object itself, it'll check the object's prototype, hence:
objLiteral.valueOf();//method defined #Object.prototype
objLiteral.valueOf === Object.prototype.valueOf //true
But when you use your first method:
function SomeConstructor()
{
this.methd = function()
{
return true;
}
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//FALSE!
That shows that we're dealing with 2 separate function objects. Move the function definition to the prototype and f.methd === g.methd; will be true:
function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//true!
In response to your comment:
Defining a method on a prototype-level allows you to change a method for a specific task, and then "reset" it back to it's default behaviour. Suppose you're in a function that's creating an AJAX request:
someObject.toString = function(){ return JSON.stringify(this);}
//when concatinating this object you'll get its json string
//do a lot of stuff
delete (someObject.toString);
Again JS will check if the object has the toString property defined on itself, which it has. So JS will delete the function you've assigned to the toString property. Next time the toString will be invoked, JS will start scanning the prototype chain all over again, and use the first occurance of the method (in the prototype). Let's clarify:
function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd = function(){return false;};
g.methd();//returns true, still <-- method is gotten from the prototype
f.methd();//returns false <-- method is defined # instance level
delete (f.methd);
f.methd();//returns true, f doesn't have the method, but the prototype still does, so JS uses that.
Or even better, you can even replace an instance's method by a method from another prototype:
f.methd = Object.prototype.valueOf;//for as long as you need
the last example is pointless, because f has the valueOf method already: its inheritance chain looks like this: var f ---> SomeConstructor ---> Object, giving you access to all Object.prototype methods, too! Neat, isn't it?
These are just dummy examples, but I hope you see this is one of those features that make JS an incredibly flexible (sometimes too flexible, I must admit) and expressive language.
In first case the function will be created for each instance and set to the foo property in the object. In second case it is shared function. When you call obj.prop then it looks for it in object itself, if it is not there, then it looks for it in proto object and so on, it is called chain of prototypes.
For example this code provides foo:
function MyClass() {
this.foo = function () {};
}
var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);
But this not:
function MyClass() {
}
MyClass.prototype.foo = function () {};
var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);
How do I call class methods from functions within the class? My code is:
var myExtension = {
init: function() {
// Call onPageLoad
},
onPageLoad: function() {
// Do something
},
}
I've tried ...
onPageLoad();
... from within the init method but it's saying it's not defined.
I'm not having much luck with google because I don't understand the syntax used. All the JS OOP examples I find online are in a different format. I'm using the format Mozilla use for extension development.
The object the current method was invoked on is available via the special variable this. Any time you call a method on an object, this will refer, within the method, to the object.
var myExtension = {
init: function() {
this.onPageLoad();
},
onPageLoad: function() {
// Do something
},
};
this always refers to the calling object rather than the object the function is defined on or is a property of.
value = 'global';
var ob0 = {
value: 'foo',
val: function() {
return this.value;
},
},
ob1 = {value: 'bar'},
ob2 = {value: 'baz'};
ob0.val(); // 'foo'
ob1.val = ob0.foo;
ob1.val(); // 'bar'
ob0.val.call(ob2); // 'baz'
var val = ob0.val;
val(); // 'global'
In the last case, val is executed as a free function (a function that isn't bound to an object, i.e. not a method), in which case this takes on the value of the global object (which is window in web browsers) within the execution of val. Global variables are actually properties of the global object, hence val() returns 'global' (the value of the global variable named value). Since global variables are actually properties of the global object, you can view free functions as actually being methods of the global object. From this viewpoint, the last two lines (when executed in global scope) are equivalent to:
window.val = ob0.val;
window.val();
This viewpoint doesn't exactly match the reality of scoping, though you'll only notice the difference within functions. In a function, window.val = ... will create a global while var val won't.
value = 'global';
var ob0 = {
value: 'foo',
val: function() {
return this.value;
},
};
function lcl() {
var val = ob0.val; // doesn't set a global named `val`
return val(); // 'global'
}
lcl(); // 'global'
val(); // error; nothing named 'val'
function glbl() {
window.val = ob0.val; // sets a global named `val`
return window.val(); // 'global'
}
glbl(); // 'global'
val(); // 'global'
See MDN's reference page for more on the call method used above. For more on the this variable, see "JavaScript “this” keyword" and "How does “this” keyword work within a JavaScript object literal?"
Assuming that you have called init like this:
myExtension.init();
then it should be:
init: function() {
// before
this.onPageLoad();
// after
}
But in Javascript functions are not actually bound to objects and you can call any function on any other object, like this:
myExtension.init.call(anotherObject); // or
myExtension.init.apply(anotherObject);
In this example this within init would be anotherObject, which doesn't have onPageLoad defined. If you want to support this kind of usage you'll have to manually reference the initial object:
init: function() {
// before
myExtension.onPageLoad();
// after
}
In Javascript you need to explicitly mention the this
this.onPageLoad()
The same is also true for other member variables (remember that in Javascript methods are just member variables that happen to be functions)
this.memberVariable
Have you considered a closure, instead?
For example:
var myExtension = ( function() {
var me = {};
var private_thingy = "abcDEFG123";
var onPageLoad = function() {
// do page loading business
alert( private_thingy );
}
me.onPageLoad = onPageLoad;
var init = function() {
onPageLoad();
}
me.init = init;
return me;
})();
///////////////
myExtension.private_thingy = "DIDDLED!";
// will NOT modify the private_thingy declared within the closure
myExtension.init(); // will work fine.
Anything you define within the closure is available within the closure at all times, and when implemented carefully will yield private members not accessible to users of the object. Only members that you explicitly export - e.g., the me.xxx = xxx lines - are publicly available.
Thus, when onPageLoad executes, "abcDEFG123" will be displayed in the alert, not "DIDDLED!". Users of the object can modify properties using the dot operator until the cows come home; what's not made public by the closure, however, can never be modified: even if the user reassigns a function on the public interface, calls to the private function from within the closure will always point to the function defined within the closure.
The important part: it unties you from the constant use of this (unless you really want to use it; save your fingers for more important typing!).
Give it a shot. And have a look at Javascript: The Good Parts by Crockford.
When making objects I assumed that this would return the object's instance - instead it seems it's something else. Why is this?
var Obj = {
foo : 'value',
bar : function() { return this.foo; } // Error
bar : function() { return Obj.foo; } // Works
}
Update: I must be missing something because in some cases using this inside objects doesn't work. How come this only references the object instance sometimes?
It does. You have a syntax issue.
Use commas to delimit object members
var Obj = {
foo : 'value',
bar : function() { return this.foo; },
}
within member functions this refers to a reference to the object that the function is called on.
jsFiddle Example
Within a JavaScript function this is set depending on how the function was called.
With your example Obj, assuming you correct the syntax error and use commas between properties:
var Obj = {
foo : 'value', // needs comma, not semicolon
bar : function() { return this.foo; }
}
If you use the "dot" syntax on Obj to call the bar function then this will be automatically set to Obj:
Obj.bar(); // this will be Obj
That's an easy way to ensure this ends up set the way you want. But if you call the function in some other way this could be set to something else:
var nonObjBar = Obj.bar; // get a reference to the function
nonObjBar(); // this will (probably) be `window`, but depends if
// in strict mode or inside some other function, etc
var Obj2 = { foo: "other foo" };
Obj.bar.call(Obj2); // the .call() method sets this to Obj2
// so bar will return Obj2's foo, "other foo"
That last example uses the .call() method on Obj.bar to invoke the function in a way that allows you to set this to anything you like (strict versus non-strict mode affects the way this works for some cases).
It might seem strange if you're coming from languages like Java, but JavaScript functions don't belong to any given object. This behaviour is pretty well defined and on purpose.
After fixing the semi-colon after 'value', this seems to work:
var Obj = {
foo : 'value',
bar : function() { return this.foo; } // Error
};
alert(Obj.bar()); // alerts 'value'
See working jsFiddle here: http://jsfiddle.net/jfriend00/UFPFf/.
When you call a method on an object, the javascript engine sets the this pointer to point to the object for the duration of the method call.
You shouldn't have a semicolon after foo.
Actually when you call Obj.bar you will have this referring to Obj.
See http://jsfiddle.net/AAkbR/
var Obj = {
foo : 'value',
bar : function () { return this.foo; }
};
alert(Obj.bar() === Obj.foo);
Alerts true.