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
Related
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;
}
};
}
In this related question, the answer for setting a constructor is like so:
function OldClass() {
alert("old class with incomplete constructor")
}
function ChangedClass(){
alert('new class with same prototype and more complete constructor');
}
ChangedClass.prototype = OldClass.prototype;
var theClassIWant = new ChangedClass();
This is not really setting the constructor, it's making a new object and inheriting the prototype. How can I set the constructor of an Object without changing to a new Object? Is it possible?
P.S. I want something like this:
//non working code
var Foo = function() {}
Foo.prototype.constructor = function(bar_val) {
this.bar = bar_val;
}
var fez = new Foo("cat")
console.log(fez.bar); // outputs: cat;
constructor is a property of the constructor function's prototype, which points to the function itself by default.
When you modify Foo.prototype.constructor, this property points to another function. However, the constructor function Foo remains. So when you create an object, you are still instantiate the constructor function Foo, not the one Foo.prototype.constructor points to.
This is why your code doesn't work. Then let's talk why we need to change the constructor and how to.
In ES5 and before, we take advantage of prototype to simulate a class inheritance mechanism. Which looks like this:
// parent class
function Person(name) {
this.name = name
}
// define parent method
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent properties
this.job = 'Coding'
this.major = major
}
// inherits properties and methods from parent prototype
Coder.prototype = new Person()
// define child method
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
// instantiate a child object
var me = new Coder('Leo', 'JavaScript')
console.log(me) // {name: "Leo", job: "Coding", major: "JavaScript"}
Everything looks perfect, but there a problem:
console.log(me.constructor) // Person
What? Isn't me constructed with Coder? Why?
Go back to the first line of this answer, read it again: constructor is a property of the constructor function's prototype.
Originally Coder.prototype.constructor is Coder itself. But with this line: Coder.prototype = new Person(), it got changed. Coder.prototype.constructor now equals Person.prototype.constructor, which is Person.
Well, some would say, try instanceof. Yes, that works:
me instanceof Coder // true
But it's also true for Person, because Coder is a sub class of it:
me instanceof Person // true
This doesn't make sense so we need to fix the constructor problem. That's why we use Coder.prototype.constructor = Coder after Coder.prototype = new Person(), to get back the original constructor.
Full code looks like this:
// parent class
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent class
this.job = 'Coding'
this.major = major
}
Coder.prototype = new Person() // inherits parent's prototype
Coder.prototype.constructor = Coder // get back constructor
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
myClass = {
constructor: function(text){
console.log(text);
}
}
let ob = Object.create(myClass);
ob.constructor("old constructor "); //Output: old constructor
myClass.constructor = function(){
console.log("new constructor ")
}
ob.constructor(); //Output: new constructor
You can do this with every property or function of a class.
Watch this Video here. It explains it perfectly.
I am having some trouble understanding function scope in JavaScript:
function Person() {
var _firstName;
var _lastName;
}
personOne = new Person();
personOne._firstName = "Fred";
alert(personOne._firstName);
This outputs "Fred", but I thought the variables of the Person function would only be accessible inside the function. Why does it work?
In JavaScript, objects are dynamically-expandable.
For example:
var obj = {};
obj.firstName = "Matías"; // <-- This adds the property even if it doesn't exist
In the other hand, if you want to declare properties that should be part of the object in the constructor function you need to qualify them with this:
function Person() {
this._firstName = null;
this._lastName = null;
}
Extra info
If you want to avoid objects from being dynamically-expandable, you can use the ECMA-Script 5 Object.preventExtensions function:
var obj = {};
Object.preventExtensions(obj);
// This property won't be added!
obj.text = "hello world";
Because in the line:
personOne._firstName = "Fred";
You assigned a new property to the object with a value of "Fred". It has nothing to do with the (internally-scoped) variable you declared inside the function.
And in the following line, you're actually alerting the value of the newly-created property and not the variable.
See MDN
It works because you create the property _firstName for the object Person.
personOne._firstName = "Fred"; // here you create the property
In the example below I highlighted the fact that _firstName is innacesible.
function Person() {
var _firstName= "Fred";;
var _lastName;
}
personOne = new Person();
alert(personOne._firstName); // output: "undefined"
If you want to make them accesible you can make use of this to add a new property to the object.
function Person() {
var self = this;
self._firstName= "Fred";
var _lastName;
return self;
}
var personOne = new Person();
alert(personOne._firstName); // output: "Fred"
In this line:
personOne._firstName = "Fred";
you are actually creating the property _firstName of the object. it is not the same as the var you created in the constructor function. You can always add new properties to a JavaScript object. Each property of an object is accessible. There is no such thing as a private property.
Due to function scope you will not be able to change the variables inside Person() from outside if you do not make methods available in Person to set the values of those variables.
function Person(firstName, lastName) {
var _firstName = firstName, _lastName = lastname;
this.getFullName = function () {
return _firstName + " " + _lastName;
};
}
var someone = new Person("Some", "one");
someone._firstName = "something else"; // creates new property in the object someone
var fullName = someone.getFullName(); // still returns "some one"
You cannot reference _firstName inside the object declaration. If you want to access the object property you need to declare with this, otherwise the _firstName or _lastName are considered local variables.
So to access the _firstName or _lastName as object properties, you have to declare as in the following way:
function Person() {
this._firstName = "John";
this._lastName = "Doe";
}
You may access _firstName and _lastName after you instantiate the Person.
personOne = new Person();
personOne._firstName = "Fred";
This way you will override the properties already defined in the object constructor. In your case because _firstName is declared inside the Object definition the scope of that variable is bind locally to that object. But when you instantiate the object you assign a new property which extends the originally declared object.
The most widely accepted pattern is to bind the object properties on the object declaration, but declare the object methods on their prototype level.
Like so:
function Person() {
this._firstName;
//...
}
Person.prototype = function() {
getName : function() {
//...
},
setName : function(name) {
this._firstName = name;
}
}
JS objects objects are "expandable", you can add properties dinamically.
function Person() {
var _firstName;
var _lastName;
}
var personOne = new Person();
console.log(personOne); // Person {}
personOne._firstName = "Fred";
personOne._age = 20;
console.log(personOne); // Person {_firstName: "Fred", _age: 20}
You don't actually have access to the _firstName created inside the function scope, but rather you create a property with that name on your newly created object.
In order to expose a property, you attach it using this keyword (which is a reference to the newly created object).
function Person() {
console.log(this); // Person {}
this._firstName = "Sam";
console.log(this); // Person {_firstName: "Sam"}
}
please clarify the difference b/w this two codes
function Person(gender) {
this.gender = gender;
alert('Person instantiated');
}
Person.prototype.sayHello = function()
{
alert ('hello');
};
var person1 = new Person('Male');
var person2 = new Person('Female');
// call the Person sayHello method.
person1.sayHello()
and the second one is below where function define inside funciton (without prototype property)
function Animal(gender) {
this.gender = gender;
alert('animal instantiated');
this.sayToodle = function()
{
alert ('GOOOOOOO!!');
};
}
var Animal1 = new Animal('Male');
var Animal2 = new Animal('Female');
Animal1.sayToodle();
my more simple question are:
what is the difference?
define method inside or out side of a function. what is the effect?
if both same then which is the fine way to define this.
and what does prototype do?
Can we not define method of a obj out side of its function(CLASS)???
Defining a member inside the constructor (such as: this.name) gives only that instance of the object access to that member.
Defining a member inside the prototype allows all instances to "share" that property.
A way that helped me understand this was to define an array (or any other member that is not a method) inside the prototype, like so:
function Animal() {}
Animal.prototype = {
kids: [],
giveBirth: function() {
for(var i = 0; i < arguments.length; i++) {
this.kids.push(arguments[0]);
}
}
}
var cat = new Animal();
var giraffe = new Animal();
cat.giveBirth('kitten','another kitten','yet another kitten');
// cat.kids === ['kitten','another kitten','yet another kitten'];
// giraffe.kids === ['kitten','another kitten','yet another kitten'];
If you notice, the giraffe's kids were set (as kittens). Why is this? Because in this case, .giveBirth() accesses the prototype's kids array, which is shared by all instances.
What if we don't want to share the members, because the members are unique? You can do like so:
function Animal() {
this.kids = [];
}
Animal.prototype = {
giveBirth: function() {
for(var i = 0; i < arguments.length; i++) {
this.kids.push(arguments[0]);
}
}
}
var cat = new Animal();
var giraffe = new Animal();
cat.giveBirth('kitten');
// cat.kids === ['kitten']
// giraffe.kids == undefined
giraffe.giveBirth('baby giraffe');
// cat.kids === ['kitten']
// giraffe.kids === ['baby giraffe']
As you pointed out in the comments, part of how you decide to define the properties plays into memory usage; another part plays into what members you want to be "shared" across all instances.
To get a little more insight into prototypes (through understanding how new works), see What is the 'new' keyword in JavaScript?, on StackOverflow.
Here's a quote from there:
After a lot of searching, I have finally found out exactly what the
new keyword does, and it is 4 things:
It creates a new object. The type of this object, is simply object.
It sets this new object's internal, inaccessible, [[prototype]] property to be the constructor function's external, accessible,
prototype object.
It executes the constructor function, using the newly created object whenever this is mentioned.
It returns the newly created object, unless the constructor function returns a non-primitive value. In this case, that
non-primitive value will be returned.
Prototype members are shared among instances and members in the constructor function defined as this.something are instance specific.
When an instance need instance specific members (like Person.name) define it as this.name. When it can be shared (like a method sayName) define it on the prototype like: Person.prototype.sayName=function(){...
For more info on prototype and constructor functions you can check this answer.
I'm confused about the notion of "prototype" in javascript.
When I'm defining an object both of the following seem to work:
myObject = {};
myObject.prototype.method1 = function() { ... };
myObject.prototype.method2 = function() { ... };
myObject.prototype.method3 = function() { ... };
and...
myObject = {};
myObject.method1 = function() { ... };
myObject.method2 = function() { ... };
myObject.method3 = function() { ... };
Could anyone shed some light on this? What exactly is the difference between these two ways of creating an object and why would I choose one over the other? (I have this feeling in my gut it's important...)
Thanks!
You should use the prototype property only on Constructor Functions, not in object instances, for example:
function Test () {}
Test.prototype.method1 = function () {/*...*/};
var obj = new Test();
The prototype property of constructor functions, is used by the new operator, when it creates our new object instance.
All native objects have a hidden link, that builds up the prototype chain.
This hidden link between objects is the [[Prototype]] internal property, and the new operator is the only one that can set it.
In the above example, the obj is associated internally with it's constructor prototype, the method1 is accessible from obj, but it doesn't exists physically on this object, that method exists on the Test.prototype object, and it's retrieved through the prototype chain, e.g.:
typeof obj.method1; // "function"
obj.hasOwnProperty('method1'); // false
obj.method1 === Test.prototype.method1; // true
On object instances, assigning a prototype property is meaningless, it will be taken just as any other property name:
var myObject = {};
myObject.prototype = "foo";
myObject.bar = "bar";
// myObject is simply {"prototype":"foo","bar":"bar"}
Second way adds methods only to this object. First way makes it available for other objects created with new with this "type".