function setName(obj){
obj.name = "Obama";
obj = {name:"Clinton"};
}
var president = {name:"Bush"};
setName(president);
console.log(president.name);
When I change “obj.name = "Obama";” to “this.name = "Obama";”
function setName(obj){
this.name = "Obama";
obj = {name:"Clinton"};
}
var president = {name:"Bush"};
setName(president);
console.log(president.name);
The output becomes "Bush".
this is not the obj.
You can try this to understand:
function setName(obj){
console.log(this.name);
}
It will not give you obj.
Well if you really think bad about using the obj word try this:
function setName(obj){
setName.arguments[0].name = "Obama";
obj = {name:"Clinton"}; // I don't touch this.
}
I added some comments to help understand what is happening.
function setName(obj){
// change obj's name property to Obama
obj.name = "Obama";
// change the reference to obj to a new object inside setName.
// this does not affect the original object being passed in.
obj = {name:"Clinton"};
}
var president = {name:"Bush"};
setName(president);
console.log(president.name);
function setName2(obj){
// change this's name property to Obama. this is set to window/global, not obj.
this.name = "Obama";
// change the reference to obj to a new object inside setName.
// this does not affect the original object being passed in.
obj = {name:"Clinton"};
}
var president2 = {name:"Bush"};
setName2(president2);
console.log(president2.name);
You are replacing the local variable obj, the scope of which is inside the function. It is no more than a reference to the object. Thus the update obj = { name: "Clinton" }; does not affect any state outside the function.
But changing the object's name affects its contents. This is why you are getting "Obama".
this.name = "Obama" has no relevant effect on president, since this is not the president.
You are modifying an object reference and not the object itself.
This line is modifying the initial object. Obj is currently pointing to the initial object which is the same as the Object that president is pointing to.
obj.name = "Obama";
The next line assigns the variable to a new object reference. It no longer refers to the initial object. The variable president is still pointing at the initial object and thus you get "Obama" and not "Bush"
obj = {name:"Clinton"};
In the first case:
When invoking setName with the president object, it first sets the name of the object to Obama. Since you passed an object as a parameter, all properties that change, will be changed to the initial object as well. When overriding the entire object obj = {name:"Clinton"};, you lose the reference and you don't return the object, so nothing happens with it. The name is set to Obama in the first step and it will stay Obama.
In the second case:
Same as above and the this-context is related to the setName scope. You're not using setName as an Object or it's not part of an Object, so there's not really a usable this-context here. You could attach one by using call:
setName.call(president, null);
The first argument is the this-context and the other arguments are the parameters of the method. However, I would not recommend doing that for this scenario.
setName used on an Object:
To use a method setName on an object, you could do this for example:
function President(name) {
this.name = name;
}
President.prototype.setName = function(name) {
this.name = name;
}
var president = new President('Clinton');
president.setName('Obama');
Since you're using new, you create a new this-context and set the name property to Clinton while creating the Object.
Also, this could work:
function President(name) {
var presidentName = name;
return {
getName: function() {
return presidentName;
},
setName: function(name) {
presidentName = name;
}
};
}
Related
I'm trying to learn JavaScript, but got stuck with a problem (more with misunderstanding "this" keyword) that doesn't give me move on.
I've watched a lot of content about it and barely understood it, but still have some troubles.
I have some code:
function Person (name, age) {
this.name = name;
this.age = age;
this.changeName = function (name) {
this.name = name;
}
}
What do we use "this" here for?
As I understood we use "this" to create variable inside function constructor and give it value of our "name" parameter that we could refer to it. Am I right?
Then I have this code:
var p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1.name);
As I sorted out here, we call method that overwrites our variable that we created to refer to. But it doesn't change actual parameter. So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
The whole code is from teaching app!
So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
No, there's no need to do that in this example. changeName changes the property on the object that was created by new Person.
It's true that that example code is a bit odd, because it creates the changeName function in the constructor but doesn't do the kinds of things you'd normally do when you create the function in the constructor. I'd expect that code to either be this, which puts the changeName on the prototype:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.changeName = function(name) {
this.name = name;
};
(or the class equivalent) or this:
function Person(name, age) {
this.getName = function() {
return name;
};
this.changeName = function(newName) {
name = newName;
};
this.getAge = function() {
return age;
};
}
That code does update the parameter (which has no effect at all on the code calling Person). It doesn't create name and age properties at all; instead, it just makes their values accessible via getName and getAge. There's also a function to change name (changeName); but there's no function to change age. People write code like that so that age cannot be changed from outside code created within the Person constructor.
I guess you may misunderstand which parameter you actually change, so I rewrite it like so, holp this helps.
function Person (argument_name, argument_age) {
this.name = argument_name;
this.age = argument_age;
this.changeName = function (argument_change_name) {
this.name = argument_change_name;
}
}
let p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1);
The this keyword is used to create and assign values to variables in the class. It is again used to create functions, either getters or setters. So in your code this.changeName is a function that when passed a value will change the name of the person.
eg.
var a = 5; // a is an integer
var b = "Han"; //b is a string
var c = function(name){
//code here
} // then c is also a function;
Object with method created by Object Constructor:
function objectexample(name) {
this.name = name;
this.create = function(){
var obj = document.createElement('div');
obj.id = this.name;
parent = document.getElementsByTagName("body")[0];
parent.appendChild(obj);
}
this.showalert = function(){
alert("alert");
}
}
And now I create object:
var obj1 = new objectexample("new1");
How to run method .create for this object, but not using variable obj1, I want to get Object using ID, for example:
document.getElementById("new1").showalert();
Is it possible?
Basically, yes, it is possible
However, you'll need the element to contain a reference to the object that created it.
In the demo below:
When constructing the new obj1, we define 3 properties:
Its name.
A create() method that when called creates an element.
A showAlert() method that when called outputs some data.
When calling showAlert() before calling create(), we get whatever data is available about the object, but nothing about the as yet uncreated element.
When calling create() we create the element, and define creation as a property of the object, with the element as its value.
We then define creator as a property of the element, with the value of this (the object that created the element).
Now the object (creator) has a child element called creation, and the element has a creator and all the properties it has, including its methods.
In other words, if the new object gives birth to an element, the element adopts its creator's properties, and the creator keeps a tight hold of its child's hand.
function ObjectExample( name ) {
this.name = name;
this.create = function() {
this.creation = document.createElement( "div" );
this.creation.id = name;
this.creation.creator = this;
document.body.appendChild( this.creation );
}
this.showAlert = function() {
// alert( "Alert!" ); // simpler for demo to use console
console.log( this.name );
console.log( this.creation );
return this.creation;
}
}
let obj1 = new ObjectExample( "new1" );
if ( !obj1.showAlert() ) {
obj1.create();
}
document.getElementById( "new1" ).creator.showAlert();
What you're talking about is a variable name, not an object id.
document.getElementById has nothing to do with Javascript variable names, but rather is used for selecting elements from an HTML document by their id. However, it is possible to do this in several different ways depending on your use case.
One way could be to use a global/neatly scoped object in which you would modify every time the constructor is called.
let objects = {}; // create your global object
function objectexample(name) {
this.name = name;
// append this to global object
objects[name] = this;
this.create = function(){
var obj = document.createElement('div');
obj.id = this.name;
parent = document.getElementsByTagName("body")[0];
parent.appendChild(obj);
}
this.showalert = function(){
alert("alert");
}
}
new objectexample("new1");
console.log(objects.new1)
console.log(objects["new1"]) // alternatively method
I am new to Javascript sorry if this sounds as an easy question.
If I have following constructor function:
function Person(x,y){
this.name = x;
this.surname = y;
}
I am curious whether properties name and surname are considered own properties of objects of type Person or inherited?
e.g.
var x = new Person("John", "Doe");
I did some tests using hasOwnProperty which suggest they are considered own properties rather than inherited, just wanted to verify.
Yes, they are own properties. When instantiating an object with new Person, an object will be created, your function Person will be called, and this inside Person refers to this new object. You're then explicitly directly setting properties on this object. In essence, no different than this:
function person(obj) {
obj.name = 'Foo';
obj.surname = 'Bar';
}
var o = {};
person(o);
o.name // Foo
The easiest way for you to check this is to just try it and see.
But yes, they are considered own properties. Inside the constructor function, this is a reference to the newly constructed object (when Person is called with new).
It's essentially the same thing as doing
var x = {};
x.name = 'foo'
console.log(x.hasOwnProperty('name')); // true
Compare that to a prototype property:
function Person(name) {
this.name = name;
}
Person.prototype.brain = 'meat-like';
var p = new Person('Bob');
console.log(p.name); // Bob
console.log(p.brain); // meat-like
console.log(p.hasOwnProperty('name')); // true
console.log(p.hasOwnProperty('brain')); // false
Consider having below code
function Employee() {
this.id = "";
this.name = "";
this.gender = "";
}
function Programmer() {
this.expertise = "";
}
Programmer.prototype = new Employee();
And then I want to inherit the Programmer further to JScriptProgrammer with default value of "expertise" set to "JavaScript".
Question:
What is the diference between
function JScriptProgrammer() {
this.expertise = "JavaScript";
}
JScriptProgrammer.prototype = new Programmer();
and
function JScriptProgrammer() {
}
JScriptProgrammer.prototype = new Programmer();
JScriptProgrammer.prototype.expertise = "JavaScript";
You can use prototype for default values of an object and it does save memory. If you don't surely shadow the property later (assign a new value for it on the instance) then all instances share the same pointer to the value.
If however you are surely going to assign a value to it then better define it in the constructor body as this.myval
Here is the tricky part of assigning default values to prototype; you have to re assign a new value to it to make an instance specific change. Object values can be manipulated by invoking functions on them or re assigning properties. When you do that then the default value for all instances change:
var Person=function(){};
Person.prototype.teeth=[0,1,2,3];
Person.prototype.legs={left:1,right:1};
var ben=new Person();
var betty=new Person();
ben.teeth.splice(2,1);//ben looses a tooth
//when ben looses a tooth like that betty looses it too
console.log(betty.teeth);//[1,2,3] poor betty
//now poor betty has an accident
betty.legs.right=0;
//looks like ben looses it too
console.log(ben.legs);//{left:1,right:0}
//I don't feel sorry for ben though because
//he knocked out betty's tooth
It is better not to initiate a new instance for inheritance, you can use Object.create or a helper function to set up inheritance without creating an instance. All about inheritance, prototype, overriding and calling super here:https://stackoverflow.com/a/16063711/1641941
the difference
function JScriptProgrammer() {
this.expertise = "JavaScript";
}
JScriptProgrammer.prototype = new Programmer();
Means when you are using JScriptProgrammer() the expertise value are already been set to "JavaScript"
but when you use
function JScriptProgrammer()
{
}
JScriptProgrammer.prototype = new Programmer();
JScriptProgrammer.prototype.expertise = "JavaScript";
Means you set expertise value after using JScriptProgrammer()
They are the same. Second version saves memory, meaning all the children use the same instance of the function/variable.
See following example which shows why this might be required
function JScriptProgrammer() {
var tmp = "Hello";
//accessing private variables
this.sayHello = function() {
alert(tmp + " "+ this.expertise + "er");
}
}
JScriptProgrammer.prototype = new Programmer();
JScriptProgrammer.prototype.expertise = "JavaScript";
More reading
Use of 'prototype' vs. 'this' in JavaScript?
Declaring javascript object method in constructor function vs. in prototype
How to set the prototype of a JavaScript object that has already been instantiated?
In resumen:
prototype is use to inherit of existing object. For example. If you want to add a new method to Array object you can do this
Array.prototype.MyNewMethod = function()
{
alert("im bellow to array object")
}
Which means that you can to this
var array = [1,2,3];
array.MyNewMethod();//prints im bellow to array object
(read this post for more reference)
Which means that your code is doing this:
function JScriptProgrammer() {
}
function Programmer(){
this.name = "hello world";
}
JScriptProgrammer.prototype = new Programmer();// inhering from Programmers object(or lets say class)
JScriptProgrammer.prototype.expertise = "JavaScript"; // assigning a value to expertise property that belows to JScriptProgrammer class
console.log(new JScriptProgrammer())//JScriptProgrammer {name: "hello world", expertise: "JavaScript"} notice that property name that bellow to Programmer
object now is in JScriptProgrammer object as well.
here test http://jsbin.com/IgOFimi/1/edit
I AM trying to understand js prototype property: my sample code
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
Container.prototype.stamp = function (string) {
return this.member + string;
}
document.write(newc.stamp('def'));
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
var b = new Box();
document.write(newc.test);
here the last line is undefined - even though Container's prototype is a Box and Box's prototype has a property test, why is the newc which refers to test in Box doesnt work? can any one please explain how the 'Prototype' works in my above context.
Thanks...
You are setting Container prototype to Box() after the newc instance was already created.
Reorder the statements as follows:
function Container(param) {
this.member = param;
}
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
Container.prototype.stamp = function (string) {
return this.member + string;
}
//Here the containers prototype setup is complete.
var newc = new Container('abc');
document.write(newc.stamp('def'));
document.write(newc.test);
If sounds like you want to know WHY it is behaving the way it is, and not just "fix" the code. So here's what's going on.
As you saw, if you change the prototype of "Container", you will actually change the properties for new objects AND objects already instantiated. So:
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
// setting a new property of the prototype, after newc instantiated.
Container.prototype.stamp = function (string) {
return this.member + string;
}
// This already-instantiated object can access the stamp function
document.write(newc.stamp('123')); // output: abc123
So there's no problem with the above, as long as you don't call the new method before it's defined. Now the next point. Add this to the above:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
var newd = new Container('fgh');
document.write(newd.stamp('456')); // output: ERROR
Error! But that makes sense, right? You totally wiped out the "Container" prototype and replaced it with the one from "Box", which has no "stamp" function.
I am going to assume you want "Box" to inherit from "Container". That would be logical from the naming convention. If you want to do that, replace the previous section with this:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
// This inherits from Container. Note that we can
// do this before or after we declare "Box"
Box.prototype = new Container();
Box.prototype.test = "Whatever";
var b = new Box("jkl"); // note: "jkl" is ignored because "Box" sets "member" to "why"
document.write(b.test); // output: Whatever
document.write("<br>");
document.write(b.stamp("345")); // output: why345
So now we have a "Box" that can call its own methods and parameters, and also call them from its parent "Container".
So the big picture is that an object will look at its own prototype for a method or something, and if it doesn't find it there it will look in the prototype of the thing it inherited from, and so on. The other big point is that setting something in the prototype makes it immediately available in all future AND current instances of that object.
An object does not contain a reference to its constructor which it uses to get at the prototype. If it did, then the code would work as you expected.
Instead, an object contains a reference to its prototype that is set when it is created.
From the language spec section 4.2.1:
Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.