From sololearn
function mathCalc (height, weight) {
this.height = height;
this.weight = weight;
// this.sampleCalc = ; (taken out)
}
Why do I need to do:
this.height = height;
this.weight = weight;
What is the reason behind it?
this is a keyword for the function's caller for function expressions and function declarations. For constructor functions (which I will demonstrate below) and object methods, this refers to the object itself. Here are examples of the types mentioned:
function myFunc() { return this; } //function declaration
const myVar = function() { return this; } //function expression
const obj = {a: 1, whatIsA: function() { return this.a } } //whatIsA is an object method
If you call either of the above functions from the global context (not inside another function), this is the Window object. The browser defaults this to the Window (which when you think about it, is the caller of the function since your browser ran the file).
myFunc(); //outputs "Window" obj
myVar(); //also outputs "Window" obj
For constructor functions instantiated with new, this is bound to the newly created object.
I think the best way to show why this is so useful is to give an example. Examine the following code:
function Dog(name) {
this.name = name;
this.bones = 0;
this.addBone = function(numOfBones) {
this.bones += numOfBones;
return this;
}
}
const clifford = new Dog('Clifford');
We have a constructor function (meaning we're going to be creating new objects from this function) called Dog.
Consider what happens when we create a new Dog named "Clifford". The new keyword creates a brand new object in memory for Clifford, which is an instance of the Dog constructor function. So since we created something that didn't exist before, this refers to the object itself. If we replaced this.name = name with let myName = name what would happen? We wouldn't be able to access myName because myName isn't part of our brand new instance of the Dog object.
Let's give Clifford a few bones.
clifford.addBone(1).addBone(2).addBone(3);
console.log(clifford.bones); //outputs 6
How is it possible we can chain methods as we did above? Because the method returns this!
When a function is called as a method of an object, its this is set to the object the method is called on.
So we're returning the object after adding a bone to Clifford's bones. This gives us back the object itself again.
Arrow functions behave slightly differently. this is inherited from the current lexical scope and not the caller.
height and weight are only parameters for the arguments passed into the function. If you're learning, it might help to use different names.
this refers to the function itself. When treated as an object/class, it will retain the values. Notice in the object output below that h and w are not retained, height and weight are. Also notice that one and two have different values, the same value that was passed into the function when they were initialized.
function mathCalc (h, w) {
this.height = h
this.weight = w
}
let one = new mathCalc(1,3)
let two = new mathCalc(2,4)
console.log('one:',one)
console.log('two:',two)
For a function that only gets called once, it makes complete sense to avoid this. However, for persistent state, this can be useful. Note that this only gets rebound when the new keyword is used.
function Worm() {
this.size = 1;
this.grow = function() {
++this.size;
}
}
const wormy = new Worm();
console.log(wormy.size);
wormy.grow();
console.log(wormy.size);
With ES6 Javascript, there is a much cleaner way to take advantage of this.
class Worm {
constructor() {
this.size = 1;
}
grow() {
++this.size
}
}
In short this is the owner object of the function. If you had two objects or elements that called upon a function - how would you place the appropriate value in the appropriate element that called it? Using this can eliminate the need for duplicate code etc.
Technically you don't HAVE to use it; but it has its uses.
You can read more here or here.
Here's a little click test snippet, where I can have one function for alerting this clicked div id rather than having to write one for each div;
var div = document.getElementsByTagName('div');
var i;
for (i = 0; i < div.length; ++i) {
div[i].onclick = function() {
alert(this.id);
}
}
<div id="test1">Click Test 1</div>
<div id="test2">Click Test 2</div>
<div id="test3">Click Test 3</div>
Mind you, this is easier in jQuery - but I didn't feel the need to include the CDN for this example. However, it would look something like this;
$('div').on('click', function() {
alert(this.id);
})
it's an easier way to write the name of an object, useful for larger programs that have many objects.
Related
In the below code, which one is the right and how these two are different
Using call method
var obj = {
num: 10
};
var add = function(a) {
return this.num + a
}
console.log(add.call(obj,4))
Passing object in parameter
var obj = {
num: 10
};
var add = function(obj,a) {
return obj.num + a
}
console.log(add(obj,4))
Your second code block is just a regular function. The first one however is a bit more tricky. So the question is basically:
When to work with context in javascript?
In javascript, the term context basically means this. It is usually used when you call a method of an object, so that you can refer to the object. That's one of the core concepts of OOP, were we only define a function once inside the prototype, and every object of that class which inherits from it exposes this method, it won't work without context. So that's what this was invented for. However there are some cases, were context is useful without inheritance. E.g. Eventhandlers are usually contextless, as they are not part of any object:
window.addEventListener("load", function(evt){
const el = evt.target;
};
However as it is an Eventhandler of window, wouldn't it make sense that it is executed in the context of window? If you now say "YES", then you (will) probably love JS:
window.addEventListener("load", function(){
this.document.body.innerHTML = "Dynamic context can be cool!";
});
So in JS this is the way of refering to the object, the function refers to. Through Function.prototype.call we can make use of this everywhere. However that does not mean that we should use it everywhere. this should stay in the sense of context, as using it somewhere else will create confusion / uglify your code / make your code buggy.
var add = function(a) {
return this.num + a;
}
In your codesnippet i think its unclear what thisrefers to. So its rather a misuse of this. However it could get a meaning if you make it a method of obj, so its context becomes clear from the code:
const num = {
value:10,
add(a){ return this.value + a }
};
It gets even more beautiful if you use inheritance to make it reusable:
class CustomNumber {
constructor(n = 0){
this.value = n;
}
add(a){ return this.value + a; }
}
const num = new CustomNumber(10);
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
});
So I have a pseudo class with functions and vars inside of it. For example:
function MyClass()
{
this.a = 0;
this.b = function(c)
{
this.a += c;
}
}
Then, when I go to use it later I'll do this:
var myObject = new MyClass();
myObject.b(3);
myObject.b(5);
but when I do this:
console.log("A: " + myObject.a);
I get:
A: 0
What am I doing wrong?
Here's my actual code. It's split into mutiple files but I'll put up the ones that are relevant:
function SongDatabase() {
this.songs = new Array();
this.loadSongs = function () {
};
this.saveSongs = function () {
};
var _Constructor_ = function () {
var mySong = new Song();
this.songs = new Array(mySong);
};
_Constructor_();
}
function LyriX() {
var songDatabase = new SongDatabase();
//var playlistDatabase = new PlaylistDatabase();
songDatabase.loadSongs();
var sourceList = new ScrollableList();
sourceList.setElement($S.getElement("sourceList"));
var accessoryList = new ScrollableList();
accessoryList.setElement($S.getElement("accessoryList"));
var sourceListClick = function (index) {
$S.log("source click: " + index);
if (index == 0) {
displaySongs();
}
};
sourceList.setClickListener(sourceListClick);
var displaySongs = function () {
$S.log("display songs");
// STACK OVERFLOW LOOK HERE!!! thanks :)
// in debug in chrome songDatabase.songs is a zero length array
accessoryList.loadArray(songDatabase.songs);
};
}
$S.addOnLoadListener(function () {
new LyriX();
});
One issue:
> var _Constructor_ = function () {
> var mySong = new Song();
> this.songs = new Array(mySong);
> };
> _Constructor_();
In the above, when _Constructor_ is called as a function, you don't set its this value so it defaults to the global object (in non-strict mode, or undefined in strict mode). So songs becomes a global variable or throws an error in strict mode.
It seems like fairly useless function anyway, consider:
this.songs = [ new mySong() ];
I see someone's taking the "Java" in JavaScript too literally. :)
A couple things you should know about JavaScript:
In JavaScript, arrays don't work like they do in other languages.
They're a lot more like dictionaries then what you would call an array in C or Java;
they're not significantly more memory efficient, or faster;
no preallocation is done;
there's no offeset, etc, in the low-level implementation.
JavaScript arrays are little more than a convenient (but useful!) structure
for holding order-imperative data.
Arrays can be created using the new Array(length) expression,
or the simple literal expression, [].
Generally, you'll want to use the array literal, [].
Using new Array(length) doesn't really do anything useful;
it sets the initial length property of the array, but that's basically it.
All elements remain undefined.
There are no additional constraints or bounds checking.
You can do a[100] = 'whatever' on an array created by calling var a = new Array(5)
and the interpreter won't bat an eye.
JavaScript uses prototypal inheritance which is significantly different then the
classical inheritance model used in languages like C++ and Java.
With these points in mind, lets examine the following code block:
function SongDatabase() {
this.songs = new Array();
this.loadSongs = function () {
// etc.
};
this.saveSongs = function () {
// etc.
};
var _Constructor_ = function () {
var mySong = new Song();
this.songs = new Array(mySong);
};
_Constructor_();
}
This block of code is probably not doing what you think it's doing.
By initializing the SongDatabase methods inside the SongDatabase() function
you're creating new method functions for every instance of songDatabase.
This may not be a big deal when you're dealing with a couple of dozen of instances,
but if you're dealing with hundreds, the extra memory required can become a problem.
You'll want to use the prototype pattern here, instead (see below).
Your _Constructor_ function isn't doing anything.
var mySong = new Song() creates a new mySong object
local to the _Constructor_ function and not accessible outside of it.
When the _Constructor_ invocation returns,
it's mySong variable is garbage collected (like any other local variable would be).
_Constructor_ is a private function and not a method;
I'm not entirely sure what this in that context will reference.
You may end up creating a songs property on the global object
(but I'd want to test that to be sure).
As I mentioned earlier, when you call Array() with the new operator,
it takes an optional argument that sets the initial length of the array.
In this case, the interpreter will try to coerce mySong into a number
(mySong is not added to the array!);
when that fails it will simply return a new array with length = 0.
Instead, you're better off writing SongDatabase() like so:
function SongDatabase() {
this.songs = [];
// etc.
}
SongDatabase.prototype.loadSongs = function () {
// load songs into `this.songs`
};
SongDatabase.prototype.saveSongs = function () {
// save songs loaded into `this.songs`
};
The prototypal pattern may look strange,
but its probably the best way to handle your use case.
You'll still have direct access to then songs array (which may or may not be important),
and by attaching the loadSongs and saveSongs functions to SongDatabase's prototype
you ensure that those functions are shared.
function MyClass()
{
this.a = 0;
this.b = function(c)
{
this.a += c;
}
}
change a+=c into this.a+=c;
Variables are not bound to "classes", as in other languages. Think of it as an object with properties. A single a just references a variable "a" (not declared with var in the function, so even global in here). You want to update the property "a" of the this object, use this.a instead (the dot operator to access the property). You also may want to read Working with objects.
After your edit (you say you'd been using this.a), it works for me: http://jsfiddle.net/WKuZe/
After you provided us your real code, I noticed this odd structure:
function SongDatabase() {
this.songs = new Array();
// some methods
var _Constructor_ = function () {
var mySong = new Song();
this.songs = new Array(mySong);
};
_Constructor_();
}
A constructor like SongDatabase is (with the new keyword) called with the new instance as this. A normal function is usually called on nothing, i.e. this is undefined or the global object in non-strict mode. See documentation for the this keyword on MDN.
In here, you first initialisize the songDatabases' songs property with an empty array. Then, in the _Constructor_ function, you create an other array with one song but assign it to window.songs, because the function is not called on the songDatabase instance. The same problems may occur in your loadSongs() method. Apart from calling and binding the usual method to provide a "static" reference to the instance object is a scoped variable:
function SongDatabase() {
var that = this; // <== always points to the instance
// some methods
function _Constructor_ () {
var mySong = new Song();
that.songs = new Array(mySong);
// ^^^^
};
_Constructor_();
}
If your _Constructor_ is not a local function, but maybe a interface-adding global function, you might provide the instance (this) as an argument or use _Constructor_.call(this), which allows the use of the this keyword as if _Constructor_ were a "class".
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().
Here is the textbook standard way of describing a 'class' or constructor function in JavaScript, straight from the Definitive Guide to JavaScript:
function Rectangle(w,h) {
this.width = w;
this.height = h;
}
Rectangle.prototype.area = function() {
return this.width * this.height;
};
I don't like the dangling prototype manipulation here, so I was trying to think of a way to encapsulate the function definition for area inside the constructor. I came up with this, which I did not expect to work:
function Rectangle(w,h) {
this.width = w;
this.height = h;
this.constructor.prototype.area = function() {
return this.width * this.height;
};
}
I didn't expect this to work because the this reference inside the area function should be pointing to the area function itself, so I wouldn't have access to width and height from this. But it turns out I do!
var rect = new Rectangle(2,3);
var area = rect.area(); // great scott! it is 6
Some further testing confirmed that the this reference inside the area function actually was a reference to the object under construction, not the area function itself.
function Rectangle(w,h) {
this.width = w;
this.height = h;
var me = this;
this.constructor.prototype.whatever = function() {
if (this === me) { alert ('this is not what you think');}
};
}
Turns out the alert pops up, and this is exactly the object under construction. So what is going on here? Why is this not the this I expect it to be?
I think the right answer is that you should not do this because as kennebec said in the comment:
If you have a hundred rectangles, you
are going to redeclare that prototype
method a hundred times.
I thought that 'this' always referred to the object against which the function was called.
The meaning of this depends how the function was called:
this usually refers to the object the function is called from at runtime, e.g. when called as ob.foo(), this in foo will refer to ob.
If a function is called in a no-object-provided way, e.g. just foo(), this refers to the global variable (the top object that contains all other global variables in your js program).
And in .call() and .apply(), the object that this refers to is supplied.
Now, if you wanted a way to point to the object for the function that your function was created in (i.e., the 2nd level this at the time of creation), then you would have to rename the deeper this to make it shine through the currently-visible one. If that's clear as mud, this should help clarify a bit:
function outside() {
// Here, 'this' refers to the object outside() is called with.
// Let's "rename" this, to make it visible to inside functions.
var that = this,
private = 42;
return {
inside: function {
// here, 'this' refers to the object inside() is called with,
// it is hiding outside's this.
// Also, 'that' refers to the object outside() was called with,
// *at the time* outside was called and inside was created.
// Notice that you can see 'private'
// (but nobody outside of 'outside()) can!
return private;
}
}
}
This pattern above is useful to create object with public methods that can access private members. See Crockford for probably better explanations.
What 'this' points to, is determined when the code is run.
Here's an easy way to figure out what 'this' should be.
If you use '.' to reference a function, 'this' will be a reference to whatever is on the left side of the '.'
(This doesn't account for .call and .apply)
var myFn = function () {
return this.name + ' called me';
};
var me = {
name : 'oatkiller',
shoutOut : myFn
};
var you = {
name : 'Matthew',
shoutOut : myFn
};
// im on the left of the dot, so this points to me
me.shoutOut(); // 'oatkiller called me'
// youre on the left of the dot, so this points to you
you.shoutOut(); // 'Matthew called me'
I think you're really close with the final example. How about using a privileged method:
function Rectangle(w,h) {
this.width = w;
this.height = h;
var that = this;
this.area = function() {
return that.width * that.height;
}
}
var rect = new Rectangle(2,3);
console.log(rect.area());
See Crockford's "Private Members in JavaScript" for more info.