Confusing JavaScript statement: "var x = new this();" - javascript

I thought I understood the concept of the JavaScript prototype object, as well as [[proto]] until I saw a few posts regarding class inheritance.
Firstly, "JavaScript OOP - the smart way" at http://amix.dk/blog/viewEntry/19038
See the implementation section:
var parent = new this('no_init');
And also "Simple JavaScript Inheritance" on John Resig's great blog.
var prototype = new this();
What does new this(); actually mean?
This statement makes no sense to me because my understand has been that this points to an object and not a constructor function. I've also tried testing statements in Firebug to figure this one out and all I receive is syntax errors.
My head has gone off into a complete spin.
Could someone please explain this in detail?

In a javascript static function, you can call new this() like so,
var Class = function(){}; // constructor
Class.foo = function(){return this;} // will return the Class function which is also an object
Therefore,
Class.foo = function(){ return new this();} // Will invoke the global Class func as a constructor
This way you get a static factory method. The moral of the story is, not to forget functions are just like any other objects when you are not calling them.

What is confusing you, I think, is just where "this" is really coming from. So bear with me-- here is a very brief explanation that I hope will make it quite clear.
In JavaScript, what "this" refers to within a function is always determined at the time the function is called. When you do:
jimmy.nap();
The nap function (method) runs and receives jimmy as "this".
What objects have references to nap is irrelevant. For example:
var jimmy = {}, billy = {};
jimmy.nap = function(){ alert("zzz"); };
var jimmy_nap = jimmy.nap;
jimmy_nap(); // during this function's execution, this is *NOT* jimmy!
// it is the global object ("window" in browsers), which is given as the
// context ("this") to all functions which are not given another context.
billy.sleep = jimmy.nap;
billy.sleep(); // during this function's excution, this is billy, *NOT* jimmy
jimmy.nap(); //okay, this time, this is jimmy!
In other words, whenever you have:
var some_func = function(arg1, arg2){ /*....*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(2, 3);
other_obj.some_meth(2, 3);
What it's getting "translated" into (not literally-- this is pedagogical, not about how javascript interpreters actually work at all) is something like:
var some_func = function(this, arg1, arg2){ /* ...*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(obj, 2, 3);
other_obj.some_meth(other_obj, 2, 3);
So, notice how extend is used in the example on that page:
UniversityPerson = Person.extend({ /* ... */ });
Pop quiz: When extend runs, what does it think "this" refers to?
Answer: That's right. "Person".
So the puzzling code above really is the same as (in that particular case):
var prototype = new Person('no_init');
Not so mysterious anymore, eh? This is possible because unlike in some languages,
a JavaScript variable-- including "this"-- can hold any value, including a function such as Person.
(There is nothing that makes Person specifically a constructor. Any function can be invoked with the new keyword. If I recall the exact semantics, I think they are that when a function is called with the new keyword, it is automatically given an empty object ({}) as its context ("this") and when the function returns, the return value is that same object unless (maybe?) the function returns something else)
This is a cool question because it speaks to a pretty essential part of JavaScript's neatness or oddness (depending on how you see it).
Does that answer your question? I can clarify if necessary.

AJS.Class effectively* translates this:
var Person = new AJS.Class({
init: function(name) {
this.name = name;
Person.count++;
},
getName: function() {
return this.name;
}
});
Person.count = 0;
into this:
var Person = function (name) {
this.name = name;
Person.count++;
};
Person.prototype = {
getName: function() {
return this.name;
}
};
Person.extend = AJS.Class.prototype.extend;
Person.implement = AJS.Class.prototype.implement;
Person.count = 0;
Therefore, in this case, this in AJS.Class.prototype.extend refers to Person, because:
Person.extend(...);
// is the same as
Person.extend.call(Person, ...);
// is the same as
AJS.Class.prototype.extend.call(Person, ...);
* There are a lot of cases I don't go over; this rewrite is for simplicity in understanding the problem.

Imagine the following situation :
var inner = function () {
var obj = new this;
console.log(obj.myProperty);
};
var f1 = function () {
this.myProperty = "my Property"
}
f1.f2 = inner;
f1.f2();
Here the calling object is itself a function, so this will return a function, and we can instantiate it.
In order to use this()(not this) the outer function(the context) must itself return smth that can be instantiated(another function):
var inner = function () {
var obj = new this();
console.log(obj.myProperty);
};
var f1 = function () {
var func = function () {};
func.myProperty = 'my property';
return func;
};
f1.f2 = inner;
f1.f2();

A simpler code explaination:
class User {
constructor() {
this.name = '';
this.age = '';
}
static getInfo() {
let user = new this();
console.log(user);
}
}
User.getInfo()
Output:
Object {
age: "",
name: ""
}

see this link http://www.quirksmode.org/js/this.html It will tell you about the this keyword, but I am not sure what this() is, may be its some kind of user defined function...... that you are not aware of...

"this" means the context of the function currently running.
The code you are posting surely appears in a function that act as a method for an object.
So the object is the context of the function.
"new this()" will return a clone of the current object after running its constructor function with the passed arguments.

this() refers to the the function that the code is in, but this() would have to be within that function. Calling new this(); within a function would create a never ending loop. Calling it outside of a function would be redundant because there is no function/class set as this().

Related

Constructor function - in simple namespace - Javascript

In want to define a function-constructor inside a namespace. The way in which I defined the constructor till now was a simple constructor function without NS, combined with prototypal inheritance.
The code looked kind of like:
function mySuperObject() {
var self = this;
self.p1 = "";
self.p2 = "jkejie";
// and others
}
mySuperObject.prototype.func1 = function(){...}
// and others
Introducing namespace:
After reading many articles I decided to start up with a very simple way to define a namespace, maybe the most simplest.
Basically it is just about defining a variable which points to an object-literal and the content is the object (the "mySuperObject" in the code-snippet above). The constructor function is following: mySuperObjectInNS.
The code of the object:
var MYNAMESPACE = {
//some variable outside the object
file : "ConstructorInNamespace_obj.js: ",
//Defining contructor function inside a namespace
mySuperObjectInNS : function(propOne, propTwo){
var self = this;
self.objectName = "mySuperObject";
self.propertyOne = propOne;
self.propertyTwo = propTwo;
self.doSomething = function(){
console.log(file + " doSomething called - function of object");
};
///many more functions and attributes
}
}
MYNAMESPACE.mySuperObjectInNS.prototype.specialFunction = function(){
console.log(file + " specialFunction called - prototypical inheritance defined in file of object, outside of namespace");
};
///many more functions and attributes
In another file it is possible to intantiate the object, as follows:
...
var objOne = new MYNAMESPACE.mySuperObjectInNS("param11", "40");
//following line works just fine
objOne.doSomething();
....
Questions:
It seems to me that this all is about defining an Object-Literal and
I will come into trouble the latest I am trying to define "private"
properties of that object. Is this correct?
Is that mySuperObjectInNS still a constructor function? (For me it
seems it is something else,even if I can intantiate objects from it.
Is is a very bad very bad way of namespacing or is kind of ok?
It seems to me that this all is about defining an Object-Literal and I will come into trouble the latest I am trying to define "private" properties of that object. Is this correct?
"Private properties" have nothing to do with using an object for namespacing. In fact, originally when answering this question, I read that as "private functions" because that would be relevant.
There are lots of ways to do private and semi-private properties in JavaScript, but they relate to how you create the constructor function and the methods it gives the object, not how you expose the constructor function. "Namespace" objects are about how you expose the constructor.
One common pattern for creating "private" properties is to define methods that need to access them within the constructor, and make the "properties" local variables within the constructor (so they aren't really properties at all), like this:
function SuperObject() {
var privateInformation;
this.method = function() {
// This can access `privateInformation`, which is completely
// hidden from outside the constructor
};
}
It doesn't matter at all if you do that within a "namespacing" pattern or on its own.
Private functions, on the other hand, affect the pattern. I'll show both below.
A fairly common variant that provides for private functions is to use a function to create the object, which also gives you the opportunity to create private functions:
var TheNamespace = function() {
function privateFunction() {
}
function SuperObject() {
var privateInformation;
this.method = function() {
// This can access `privateInformation`, which is completely
// hidden from outside the constructor
};
}
SuperObject.prototype.otherMethod = function() {
// Can't access `privateInformation`, but has the advantage
// that the function is shared between instances
};
return {
SuperObject: SuperObject
};
}();
// usage
var s = new TheNamespace.SuperObject();
Is that mySuperObjectInNS still a constructor function? (For me it seems it is something else,even if I can intantiate objects from it.
Yes. A constructor function is any function that expect you to use new with it.
Is is a very bad very bad way of namespacing or is kind of ok?
Using objects as pseudo-namespaces is common practice. You might also consider various asynchronous module definition (AMD) technologies, which largely make "namespace" objects largely unnecessary.
Re your comment:
You defined a self-invoking function....which returns an an object?
It's not a self-invoking function, it's an inline-invoked function, but yes, it's a function that returns an object.
(if so I think parantheses are missing)
No, we don't need any parens that aren't there because the only reason for the outer parens other places you've seen this are to tell the parser that the word function starts an expression rather than declaration; we don't need that in the above because we're already on the right-hand side of an assignment, so there's no ambiguity when function is encountered.
Due to you proposed this way, is it a better way to define the ns?
"Better" is a subjective term. It gives you a scope in which you can define private functions, which you'd asked about.
Whereas I often also saw the option: var = {} | someNSName; What is this all about?
If you have several files that will add things to the "namespace" (as is common), then you frequently see this in each of them:
var TheNamespace = TheNamespace || {};
What that does is declare the variable if it hasn't been declared before, and assign an empty object to it if it doesn't already have one. In the first file that gets loaded, this happens:
The var is processed and creates a new variable, TheNamespace, with the value undefined.
The TheNameSpace = TheNameSpace || {} assignment is processed: Since undefined is falsey, the curiously-powerful || operator results in the new {}, which gets assigned to TheNamespace.
When the next file loads, this happens:
The var is a no-op, because the variable already exists.
The TheNameSpace = TheNameSpace || {} assignment is processed: Since TheNamespace has a non-null object reference, it's truthy, and the curiously-powerful || operator results in a reference to the object TheNamespace refers to.
That is, it has no effect at all.
This is used so you can load the files in any order, or load just one file in isolation.
Here's an example:
thingy.js:
var TheNamespace = TheNamespace || {};
TheNamespace.Nifty = function() {
function privateFunction() {
}
function Nifty() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Nifty.prototype.otherMethod = function() {
// ...
};
return Nifty;
}();
thingy.js:
var TheNamespace = TheNamespace || {};
TheNamespace.Thingy = function() {
function privateFunction() {
}
function Thingy() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Thingy.prototype.otherMethod = function() {
// ...
};
return Thingy;
}();
There are lots of variations on that basic pattern, particularly if one file may add multiple things to TheNamespace. Here's one that supports doing so fairly concisely:
var TheNamespace = function(exports) {
function privateFunction() {
}
function Nifty() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Nifty.prototype.otherMethod = function() {
// ...
};
exports.Nifty = Nifty;
function Thingy() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Thingy.prototype.otherMethod = function() {
// ...
};
exports.Thingy = Thingy;
}(TheNamespace || {});

How to access properties of object created and returned from a function

var steve = function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
}
window["steve"]["WayCoolTest"]
running this in chrome console, my test app, anywhere results with undefined. I do not understand why, can someone explain why this does not work and help me fix it. Thank you very much!!
Using window is usually redundant - let me demonstrate:
var foo = '123';
alert(foo); //123
alert(window.foo) //123
alert(window['foo']) //123
It is evident which is more convenient. There is a circumstance in which the use of window makes sense, but that circumstance is almost always because of poor architecture. Using window allows us to access a variable global variable - funny wording :) This should clear it up:
var foo = '123';
var bar = 'abc';
var prop;
if (blah) { //some condition here
prop = 'foo';
}
else {
prop = 'bar';
}
Now...how can we use prop to get the value of a corresponding variable?
console.log(window[prop]); //123 or abc - bracket notation lets us use variable property names
This sort of thing is very common within objects, but not with window. The reason is that we should be avoiding global variables (properties of window) as much as possible. Therefore, any logic that needs a variable property name should be inside of an object, dealing with objects - NOT window. Now window can be out of the picture.
It is usually bad practice to create functions inside of other functions. That would mean that each time you call function A, you recreate function B. Most of the time, people do that because they don't know better, not because they need to.
It appears to me that you intended to give steve a property called WayCoolTest, both being functions. That can be done.
var steve = function() {
console.log("I'm Steve!");
}
steve.WayCoolTest = function() {
console.log("I'm a Way Cool Test!");
}
steve(); //I'm Steve!
steve.WayCoolTest(); //I'm a Way Cool Test!
This works because functions are objects in javascript. Therefore, you can add properties to them.
Let's step it up!
To emphasize good practices, I'm going to wrap this example in an object testApp (it acts like a namespace..we're using that instead of window).
I will create a property of testApp called steve, which will be a function.
Rather than creating steve directly as a function, I will use an IIFE (immediately invoked function expression), which is a function that will return something to be set as steve.
Inside the IIFE, I will create the function for steve and also attach WayCoolTest to it, as demonstrated in the previous example, then that function is returned and assigned to steve.
var testApp = {
steve : (function() {
var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
console.log("I'm Steve!");
}
steve.WayCoolTest = function() {
console.log("I'm a Way Cool Test!");
}
return steve;
}());
};
testApp.steve(); //I'm Steve;
testApp.steve.WayCoolTest(); //I'm a Way Cool Test!
Now, let's consider another variation.
var testApp = {
steve : (function() {
var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
console.log("I'm Steve!");
WayCoolTest(); //Steve can use this, but nothing else can! Encapsulation.
}
var WayCoolTest = function() { //THIS PART!! No longer a property of "steve"
console.log("I'm a Way Cool Test!");
}
return steve;
}());
};
testApp.steve(); //I'm Steve! I'm a Way Cool Test
testApp.steve.WayCoolTest(); //undefined, of course
That is very useful if for example steve is a complicated function and you want to break it up into some other small functions that only steve will know about.
To complement the other answers, your code would work this way:
var steve = function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
}
window["steve"]()["WayCoolTest"]();
or
var steve = (function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
})();
window["steve"]["WayCoolTest"]();
or, the dirtiest way...
steve=(function() {
var bob = {};
bob.__defineGetter__("WayCoolTest", function () {console.log('done deal');});
return bob;
})();
window["steve"]["WayCoolTest"];
Assuming steve is in the global scope and you dont seem to use steve as a constructor you can use immediate function and return the new object that you have created inside of it.
var steve = (function () {
var bob = {};
bob.WayCoolTest = function () {
console.log('done deal');
};
return bob;
})();
window["steve"]["WayCoolTest"]();
If it is in a closure then you would have to either remove var for hoisting to happen so it becomes a part of window or set it to the window object as a property.
window.steve = (function () {
var bob = {};
bob.WayCoolTest = function () {
console.log('done deal');
};
return bob;
})();
If you declare using var it doesn't get associated with the global window scope. It's instead a local variable. Also bob is not a property on the steve object they way you have it set up

JavaScript function currying does not work on instance method

I am learning function currying in JavaScript by reading online and writing some simple code. I got following example in online article
function toArray(obj) {
return Array.prototype.slice.call(obj);
}
Function.prototype.curry = function() {
if (arguments.length<1) {
return this; //nothing to curry with - return function
}
var __method = this;
var args = toArray(arguments);
return function() {
return __method.apply(this, args.concat(toArray(arguments)));
}
}
var add = function(a,b) {
return a + b;
}
var addTen = add.curry(10); //create function that returns 10 + argument
alert(addTen(20)); //alerts 30 correctly
Then I tried to try it on the method of an instantiated function. So I tried following. But it gave me error "Unable to get property 'prototype' of undefined or null reference" on the second last line. I know this error is nothing to do with currying but I am messing up with some basics of JS functions concept. So where I am going wrong.
function Person()
{
this.age = 15;
}
Person.ageAfter = function (years) {
return this.age + years;
}
var personObj = new Person();
var ageAfterFiveYears = personObj.ageAfter.prototype.curry(5); //**Error**
alert(ageAfterFiveYears());
You have two issues:
The ageAfter function is not an instance method - you've added it to the "class" (i.e. it's kind of like a static method). It should be added to the prototype.
When you curry the function you lose your object's context, so you either need to rebind the context
e.g:
var ageAfterFiveYears = Person.prototype.ageAfter.curry(5).bind(personObj);
giving you a function that only works on the current instance, or better yet, as #Pointy suggests in the comments, you should just put the curried function back onto the prototype:
Person.prototype.ageAfterFiveYears = Person.prototype.ageAfter.curry(5);
which then adds the .ageAfterFiveYears method to every Person object.
You shouldn't include the prototype in your call:
var ageAfterFiveYears = personObj.ageAfter.curry(5);
The "ageAfter" property has a function for its value, so that function will have access to your "curry" function just like the function in your first example.
When you call it on the prototype, the value of this inside your function will be the prototype object, not the "ageAfter" function.
Also as a comment points out, you need to put "ageAfter" on the prototype:
Person.prototype.ageAfter = function(years) { ... }
edit — the binding issue that Alnitak points out is also important. (When I say "important", what I mean is "necessary to make your code work".)
Curry will not work for your use case. You need to bind the context so this is your personObj.
function Person() {
this.age = 15;
}
Person.prototype.ageAfter = function (years) {
return this.age + years;
}
var personObj = new Person();
var ageAfterFiveYears = personObj.ageAfter.bind(personObj, 5);
alert(ageAfterFiveYears());

Method vs Functions, and other questions

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.

Local Instance Reference

In javascript say I have:
var Person = (function () {
function Person(data) {
data = $.extend({
name: "",
age: 0
}, data);
this.name = data.name;
this.age = data.age;
}
return Person;
})();
Person.prototype.getName = function () {
return this.name;
};
...if I understand the 'this' keyword correctly in javascript, it can refer to pretty much anything from the window object to itself to anything in-between (e.g. callers of the object). My question is how the heck do I write methods like .getName() so that I know I'll always have a reference to the value stored in the person object's name property if I never can be sure what 'this' will refer to in that method? Say that .getName() is called and 'this' references the window object - how the do I get the value I need then?
I'm asking because I've inherited some code using pretty heavy prototyping and I'm running into all kinds of issues trying to reference properties and methods on objects from within themselves. Seems like I'm missing something but I've been looking into scope, closures, and other patterns all day and I can't get around this.
The value of this is set by the language according to how a function/method is called.
If you have an object with a method and you do:
obj.method()
Then, this will be set to point to the object inside of the method() function.
But, if you just get that method by itself like this:
var p = obj.method;
p();
Then, because there is no object reference in the actual function call, this will be set to either window or undefined depending upon whether you are in strict mode or not.
Additionally, the caller can specify exactly what they want this to be set to using obj.method.call() or obj.method.apply() or even p.call() or p.apply() from the previous example. You can look these methods up on MDN to see more details about how they work.
So, in your previous code, this should work:
function Person(data) {
data = $.extend({
name: "",
age: 0
}, data);
this.name = data.name;
this.age = data.age;
}
Person.prototype.getName = function () {
return this.name;
};
var p = new Person({name:"John"});
var n = p.getName(); // will return "John"
Working demo: http://jsfiddle.net/jfriend00/a7MkP/
If you needed to pass getName() to a third party library that won't call it with the object context, then there are a few options like this:
Anonymous function:
var myPerson = new Person("John");
callThirdParty(function() {
// callback that calls getName with the right object context
return myPerson.getName();
});
Using .bind() (not suported in some older browsers):
var myPerson = new Person("John");
var boundFn = myPerson.getName.bind(myPerson);
callThirdParty(boundFn);
From your own method:
var self = this;
callThirdParty(function() {
// callback that calls getName with the right object context
return self.getName();
});
FYI, there really is no reason for the self-executing function you have surrounding your Person constructor function. It just makes the code more complicated and adds no value in this case.
Yes, you are understanding the this keyword correctly.
how the heck do I write methods like .getName() so that I know I'll always have a reference to the value stored in the person object's name property
You can only do so by not using this, and in not using prototyping. Give each object a unique function that always refers to the original object:
function Person(data) {
data = $.extend({
name: "",
age: 0
}, data);
this.name = data.name;
this.age = data.age;
var that = this; // a reference variable always pointing to this instance
this.getName = function() {
// using the variable from the constructor closure
return that.name; // a quite useless getter
};
}
var john = new Person({name:"John"}),
getter = john.getName;
getter(); // "John"
I'm running into all kinds of issues trying to reference properties and methods on objects from within themselves
So with the above you can solve it by making all methods instance-specific. However, that undoes all the advantages of prototyping, and should not be used.
Instead, the one who calls a function (or a method) should be responsible to call it in the correct context:
john.getName();
If you really have to pass a function to someone which ignores that (like addEventListener), you can use magic stuff like .bind() or just apply the above pattern:
// from
addEventListener("click", john.sayHello); // will call the function in context of the DOM
// to
addEventListener("click", function() {
john.sayHello(); // correct thisValue
});

Categories