Javascript 'this' inside an object literal [duplicate] - javascript

This question already has answers here:
Javascript: Do I need to put this.var for every variable in an object?
(6 answers)
Closed 9 years ago.
I am new to javascript. I was doing some hands on "object literals". Below is the code i was trying. BodyLoaded is the event handler for onload event of body tag.
//works - getName returns "bingo"
function BodyLoaded()
{
var dog = {
name: "defaultname",
getName: function () {
return name;
},
setName: function (n) {
name = n;
}
};
dog.setName("bingo");
console.log(dog.getName());
}
//works too - getName returns "bingo"
function BodyLoaded()
{
var dog = {
name: "defaultname",
getName: function () {
return this.name;
},
setName: function (n) {
this.name = n;
}
};
dog.setName("bingo");
console.log(dog.getName());
}
//doesnt work - getName returns ""
function BodyLoaded()
{
var dog = {
name: "defaultname",
getName: function () {
return this.name;
},
setName: function (n) {
name = n;
}
};
dog.setName("bingo");
console.log(dog.getName());
}
The above code returns expected result when calling getName ("bingo"). But if I return this.name in the getName function, it returns and empty string. The strange part is, if i use this.name in both the functions (setName and getName) the code works fine and returns the expected value("bingo"). Trying to understand this behavior.

When you return name from the method, it actually returns the window.name because there is not context involved.
When you call this.name, this points to the dog object which has a name property so it returns that.

If you don't specify this when setting the name value the actual variable that gets set will be window.name. But when you use this.name the actual value that gets set will be dog.name. Just modify the code as given below and see.
function BodyLoaded()
{
var dog = {
name: "defaultname",
getName: function () {
return this.name;
},
setName: function (n) {
this.name = n;
}
};
dog.setName("bingo");
console.log(dog.getName());
}
But as per your given code I couldn't understand the reason for getting an empty string. If should actually output value defaultname.

function Dog() {
var self = this;
this.name = "defaultname";
this.getName = function () {
return this.name;
// same as
// return self.name
}
}
var myDog = new Dog();
myDog.getName(); // defaultname

Related

Why i can console property inside prototype while invoking a function

hi i am very beginner in javascript i write a simple code to learn javascript prototype inheritance
var Person = function(name) {
this.name = name;
};
Person.prototype.isPerson = true;
var person = new Person('Smith');
// DOT(person,'name') should return Smith
// DOT(person,'isPerson') should true;
var DOT = function(obj, pro) {
if (obj.hasOwnProperty(pro)) {
console.log(obj[pro]);
} else {
// return DOT(obj.__proto__,pro)
}
};
console.log(person['isPerson']);
DOT(person, 'name');
DOT(person, 'isPerson');
in this code I have one doubt in the last line DOT function invoked will not return true but I can able to return true while console console.log(person['isPerson']) why is that..?

JavaScript - why must we return a function from a self-invoking function?

This code has a runtime error:
var person = (function(){
var Person = {
init: function() {
},
};
return new Person();
/*return function(){
new Person();
}*/
})();
console.log(person);
it says I have to return a function instead of a plain Object.
Why is that I can't return an object from the self-invoking/anonymous outer function? Why must I return a function?
likewise, this altered code also gives me a similar error:
var person = function(){
var Person = {
init: function() {
},
};
return new Person();
/*return function(){
new Person();
}*/
};
console.log(person());
Why is that I can't return an object from the self-invoking/anonymous outer function?
You can return an object, that is not what's wrong with your code.
The problem with your code is that Person is an object, not a function. Calling new Person() is invalid.
var person = (function () {
return {
name: 'bob'
};
}());
console.log(person.name);
The problem here is that you have declared Person as an object, and you can't use new Person() with an object. To create a "class" in ES5 you create a function instead.
var person = (function(){
var Person = function() {
this.init = function() {
console.log('Initing!')
}
};
return new Person();
})();
console.log(person);
http://jsfiddle.net/758zL8v3/
The alternative is the following Object constructor:
var person = function(){
var Person = function(){
this.init = function() {
};
};
return new Person();
};
You can read more about Object Oriented programming here.
Why must I return a function?
Because the new operator creates an instance of a Javascript Object. And to create it, it needs a constructor function. And that is that function you're asking about.
It's almost like calling a typical function
function add() {
return 1 + 1;
}
add();
// 2
but when you call it with the new operator, you create a new instance of this function object (functions are objects too, in Javascript).
function myAdder() {
this.a = 1;
this.b = 1;
this.add = function () {
return this.a + this.b;
};
return this;
}
myObject = new myAdder();
myObject.b = 2;
myObject.add();
// 3
And the object notation of myAdder would be:
function myAdder() {
return {
a: 1,
b: 1,
add: function () {
return this.a + this.b;
}
};
}

Javascript revealing module pattern and variables

My question is precisely the same as this one Javascript revealing module pattern, public properties
In that thread, the answer was given but not the "why". Here's the same question restated with my own example:
myApp.User = function () {
var firstName = 'Default',
lastName = 'Default';
function setFirstName(name) {
firstName = name;
}
function setLastName(name) {
lastName = name;
}
function getFirstName() {
return firstName;
}
function getLastName() {
return lastName;
}
return {
getLastName: getLastName,
**getFirstName: getFirstName**,
setLastName: setLastName,
setFirstName: firstName
};
};
In this scenario, User().getFirstName always evals to "Default" -- even if I change it to some other value via the setFirstName function.
If I replace with setFirstName like:
return {
getLastName: getLastName,
**getFirstName: getFirstName**,
setLastName: setLastName,
setFirstName: firstName
};
I am able to access the changed value. I understand that the var firstName is passed by value which is why the updated values are not reflected. I don't understand what is special about the function. Where is the pointer to the value within the function living? Why do all the functions "magically" get access to the update(s)?
Where is the pointer to the value within the function living?
In the scope of the function - which contains all the variables it has access to. This access makes the function a closure actually.
Why do all the functions "magically" get access to the update(s)?
Because all the functions share the variables declared in a higher scope.
They don't "magically" get access to the update. They are inside myApp.User that's why they can access the variable location.
When you do myApp.User().getFirstName(), because getFirstName is inside the function (scope), it will be able to access variables declared both inside this function and outside this function.
function a(){
var b = "hello";
return {
setB: function(c){ b = c; },
getB: function(){ return b; }
};
}
var obj = new a();
obj.getB(); //hello
obj.setB("new");
obj.getB(); //new
In the example above, getB and setB both live inside your object, and they can access all variables inside the a() scope.
look at what you did here in your first example
setFirstName: firstName
setFirstName is not a reference to the function "setFirstName" but rather the variable 'firstName'... you don't have access to the function 'setFirstName'. That function is still unavailable to you, so you can't modify firstName, like you want.
It is out of scope - you didn't return it, so that it is available to the outside world, so to speak. It is not available "outside" of the scope of the function. Return the function (), and apply the "setFirstName", as shown below.
try this;
myApp.User = function () {
var firstName = 'Default',
lastName = 'Default';
function setFirstName(name) {
firstName = name;
}
function setLastName(name) {
lastName = name;
}
function getFirstName() {
return firstName;
}
function getLastName() {
return lastName;
}
return {
getLastName: getLastName,
getFirstName: getFirstName,
setLastName: setLastName,
setFirstName: setFirstName
};
}();
myApp.User.setFirstName('bill');
myApp.User.getFirstName();
var User = function () {
var firstName = 'Default',
lastName = 'Default';
return {
getLastName: function() { return lastName; },
getFirstName: function() { return firstName; },
setLastName: function(name) { lastName = name; },
setFirstName: function(name) { firstName = name; },
getName: function() { return firstName + ' ' + lastName; }
};
};
var u = User(),
v = User();
console.log( u.getName() + ' - ' + v.getName() );
// Outputs: 'Default Default - Default Default'
u.setFirstName( 'Alice' );
u.setLastName( 'Bob' );
console.log( u.getName() + ' - ' + v.getName() );
// Outputs: 'Alice Bob - Default Default'

JS: OOP private functions / private fields [duplicate]

This question already has answers here:
A way to encapsulte ( add privacy ) to models in the MVC?
(2 answers)
JavaScript private methods
(34 answers)
Closed 8 years ago.
Systemname =
{
Question :
{
send: function()
{
console.log("send");
},
read: function()
{
console.log("read");
},
delete: function()
{
console.log("delete");
}
},
Answer :
{
send: function()
{
console.log("Answer sent");
}
},
Person :
{
foo: 'foo',
bar: 'bar',
add: function(name)
{
console.log('person "' + name + '" added');
},
remove: function(id)
{
console.log('person with id "' + id + '" removed');
}
}
}
i'm learning how oop works in js and i'm a bit confused now about private methods and fields. i'd like to have some private member in the person section such as 'personCount' or 'lastAddedPerson'. if i add them like this:
Person:
{
personCount: 0,
lastAddedPerson: '',
...
}
at the beginning of the person section, the fields are public and can be called with Systemane.Person.Field.... how can i set them private? and the same for a method.
thx for your help.
Here is one way.
function Person(n) {
var name = n;
this.getName = function() {
return name;
}
this.setName = function(newName) {
name = newName;
}
}
var person = new Person('roman');
You can't have private properties or methods when you create objects using literals. In fact, there are no private properties in JavaScript, but you can achieve that in practice by using a constructor function, and declaring the private properties and methods as variables:
function Person() {
var privteProperty = 1;
var privateMethod = function(){}
this.publicProperty = 2;
this.publicMethod = function(){}
}
Then you can create an instance with:
var john = new Person();
I like using a sort of factory pattern instead of new:
var Person = (function() {
return {
create: function(name) {
return (function(n) {
var name = n;
function getName() {
return name;
}
function setName(newName) {
name = newName;
}
return {
getName: getName,
setName: setName
};
}(name));
}
};
})();
Then:
var person = Person.create("Bob");
person.getName(); //returns Bob
person.setName("Jimbo");
person.getName(); //returns Jimo
Seems complex, but is pretty simple.
Person is essentially assigned the return value of an anonymous self-invoked function. This return value has a single property called create, which is a reference to another function, which more-or-less acts like a constructor. This function also returns the return value of another anonymous self-invoked function. However, this return value is the actual instance of the object that you want. Inside this anonymous self-invoked function, you can see that I have a variable called name. This variable is private to that anonymous self-invoked function and lexically bound to the scope in which it is defined. What this means is that the value of name is preserved inside that function. Basically it hangs around even after the function is done executing. The only way you can access or modify that variable is through the getName and setName functions.

How to access a superclass instance variable from the subclass?

everybody!
Suppose that I have this class in JavaScript:
function Animal()
{
this.name = "name";
}
Animal.prototype.someMethod =
function ()
{
}
and this subclass:
function Cat()
{
Animal.call(this);
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
Cat.prototype.someMethod =
function ()
{
// I want to access the superclass "name" instance variable here
}
What's the syntax to access the superclass "name" instance variable from the overriden method in the Cat class?
Thank you.
Marcos
UPDATED: Well, if you want to see the real code, here it is. The problem is with the abc variable (just a test variable that I was using).
var pesquisaAcervo;
$(
function ()
{
carregadoBase();
if ($("#form\\:tipoPesquisa").val() == "SIMPLES")
{
pesquisaAcervo = new PesquisaAcervoSimples();
}
else
{
pesquisaAcervo = new PesquisaAcervoAvancada();
}
pesquisaAcervo.paginaCarregada();
}
);
// --- PesquisaAcervo ----------------------------------------------------------
function PesquisaAcervo()
{
$("*:visible[id^='form:materiaisPesquisa']").
change(this.materialMudado).keyup(this.materialMudado);
this.abc = 10;
}
PesquisaAcervo.prototype.paginaCarregada =
function ()
{
$("#cabecalhoPesquisa a").click(this.exibirDicasPesquisa);
$("#cabecalhoPesquisa select").
change(function () {$("#form").submit();}).
keyup(function () {$(this).change();});
$("*:visible[class*='foco']").focus().select();
};
PesquisaAcervo.prototype.materialMudado =
function ()
{
};
PesquisaAcervo.prototype.exibirDicasPesquisa =
function ()
{
};
// --- PesquisaAcervoSimples ---------------------------------------------------
function PesquisaAcervoSimples()
{
PesquisaAcervo.call(this);
$("#form\\:campos").change(
function ()
{
$("#textoCampo").text($("#form\\:campos :selected").text() + ":");
}
).keyup(function () {$(this).change();}).change();
$("#pesquisaSimples a").click(
function ()
{
pesquisaAcervo = new PesquisaAcervoAvancada();
$("#pesquisaSimples").parent().hide();
$("#pesquisaAvancada").parent().show();
$("#form\\:tipoPesquisa").val("AVANCADO");
}
);
}
PesquisaAcervoSimples.prototype = new PesquisaAcervo();
PesquisaAcervoSimples.prototype.constructor = PesquisaAcervoSimples;
PesquisaAcervoSimples.prototype.materialMudado =
function ()
{
alert(this.abc); // "undefined" here
};
// --- PesquisaAcervoAvancada --------------------------------------------------
function PesquisaAcervoAvancada()
{
PesquisaAcervo.call(this);
}
PesquisaAcervoAvancada.prototype = new PesquisaAcervo();
PesquisaAcervoAvancada.prototype.constructor = PesquisaAcervoAvancada;
Your actual code reveals the problem. The issue is with how you're calling materialMudado. It's being invoked as the callback for an event. The keyword this inside the callback will refer to the target of the event (which has no abc property), not to the object that the function "belongs" to.
Here's a simple demonstration:
function Test() {};
Test.prototype.callback = function() {
alert(this);
}
var t = new Test();
$(document).click(t.callback);
Output (after clicking page):
[object HTMLDocument]
Compare to this:
function Test() {};
Test.prototype.callback = function() {
alert(this);
}
var t = new Test();
$(document).click(function() {
t.callback();
});
Output:
[object Object]
In this second example we close over the variable t, retaining a reference to it.
Applying this to your example produces something like this:
function PesquisaAcervo() {
var that = this;
var callback = function() {
that.materialMudado();
};
$("*:visible[id^='form:materiaisPesquisa']").
change(callback).keyup(callback);
this.abc = 10;
}
this.name should work. I don't see you overriding the name property in your Cat function so you should be able to just do this.name and the protopical chain will do the work to find the first instance of this property which should be Animal.name.
There is no such thing as an override for an instance variable. An instance variable is just a property on the this object. You can read it with:
var x = this.name;
or assign to it with:
this.name = "foo";
this.name will access the name whether you have an instance of an Animal object or an instance of a Cat object.
If you want to assign to the name property in the Cat constructor, you can just do so with
this.name = "Cat";
Once you have a working instance of an object, properties are just properties and there is no distinction for whether a property was created by a superclass or a subclass. They're just properties of the object at that point and you access all of them the same way with the this.propertyName syntax.
Just use the this keyword:
function Animal()
{
this.name = "name";
}
Animal.prototype.someMethod2 =
function ()
{
}
function Cat()
{
Animal.call(this);
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
Cat.prototype.someMethod =
function ()
{
alert(this.name);// I want to access the superclass "name" instance variable here
}
var c = new Cat();
c.someMethod();
Add this code to the bottom, I've just added an alert to your someMethod method...
In your example, Cat derives everything from Animal, so it has access to the name variable

Categories

Resources