function Person(name) {
this.name = name;
this.say = function() {
console.info('I am ' + this.name);
}
}
var p=new Person('stackoverflow');
Someone tell me that the above codes are equals to :
function Person(name) {
this.name = name;
this.say = function() {
console.info('I am ' + this.name);
}
}
var p={};
Person.call(p,'stackoverflow');
Is this true?
If so, how about the prototype?
Each object in javascripte owns a prototype,and the prototype chain hold the releationship of the obejcts,I wonder if this prototype does something or not.
In this example, when the object of 'p' is created,does it call some build-in method of the superclass of Person?
BTW,what I want to know is what does the syntax var p=new Person('stackoverflow'); do ?
-----------------update------------------
function Person(name) {
this.name = name;
}
Person.prototype.say = function() {
console.info('I am ' + this.name);
}
How about if I put the defination of say inside the person function:
function Person(name) {
this.name = name;
Person.prototype.say = function() {
console.info('I am ' + this.name);
}
}
The code:
var p=new Person('stackoverflow');
creates a new instance of the Person class. You must remember that classes in javascript are functions, so when you call:
Person.call(p,'stackoverflow');
You are just calling the Person function and binding it to the p object (this means that in the function context the this will refer to the p object). Those pieces of code do the same thing, except for the fact that the first is an instance of the class so if you update the prototype object of person its properties will be updated.
Anyway the situation is different when you fill the prototype object of the Person function:
Person.prototype={test:"test"}
If you add this after the Person function declaration you will see that those pieces of code have a different behaviour. The object initialized with "new" will contain the test property, but the other one hasn't it. This happens because the prototype object is applied only to the instances of the class when using "new".
Well, actually
var p=new Person('stackoverflow');
is equivalent to:
var p={};
p.__proto__ = Person.prototype;
Person.call(p,'stackoverflow');
except that __proto__ is not standard JavaScript (but is supported by
some implementations).
Related
i have problem about scoping in javascipt. I tried to create new object using the "new" keyword without any problem. The code looks like this
"use strict";
function Person() {
this.name = "john doe";
console.log(this.name);
}
Var foo = new Person()
The problem i encountered is when i try to add inner function the scope of the name variable becomes undefined inside the inner function
"use strict";
function Person() {
this.name = "john doe";
Function speak() {
console.log("my name is" + this.name);
}
speak();
}
var foo = new Person();
//error: "cannot read property 'name' of undefined"
Can somebody explained what seems to be the problem? Thank guys
With Strict mode when you are creating the object with new Person(), this refers to the window object which does not have the property called name. property called name belongs to the Person object.
Thus you are getting error cannot read property 'name' of undefined.
User another variable to hold the value of Person object's this to use that inside the inner function.
var thatObj = this;
"use strict";
function Person() {
this.name = "john doe";
var thatObj = this;
function speak() {
console.log("my name is: " + thatObj.name);
}
speak();
}
var foo = new Person();
You can also give speak the same scope as this. It should be noted that this will also make it a public function, so speak can be called from outside of the Person class.
function Person() {
this.name = "john doe";
this.speak = function() {
console.log("my name is " + this.name);
};
this.speak();
}
var foo = new Person();
this is determined by how a function is invoked, not where the function is defined. Since this.name is inside its own scope it has lost a reference to this.name instead it is referencing a global window object.
It is important to be aware of the fact when using this keyword inside of nested functions you are more than likely going to lose reference to the object that you are inside of and your this keyword will end up referencing the global object.
There is also another solution to your example using call or apply methods.
call and apply will allow you to change the value of this when function is executed.
'use strict';
function Person () {
this.name = 'john doe';
function speak () {
console.log('my name is: ' + this.name);
}
speak.call(this);
}
var foo = new Person();
I am trying to figure out how I can add methods to a constructor after I have created it.
In my code below, I cannot use Person's prototype property to add a new public method which has access to Person's vars. (Do the functions attached to the prototype property not close over the vars in the main function).
Unlike the first way, the second way works - Person 2. seems like these are called privileged methods -http://www.crockford.com/javascript/private.html.
function Person(name, age){}
Person.prototype.details = function(){
return "name: "+name+", age: "+age;
};
function Person2(name, age){
this.details = function(){
return "name: "+name+", age: "+age;};
}
var per1 = new Person("jim", 22);
var per2 = new Person2("jack", 28);
per1.details();
//=> ReferenceError: age is not defined
per2.details();
//=> "name: jack, age: 28"
No, they do not have closure over the constructor functions vars. They are in a different scope.
// This function is in one scope.
function Person(name, age) {
}
// This statement is in the parent scope, which
// doesn't have access to child scopes.
Person.prototype.details = function(){
return "name: "+name+", age: "+age;
};
That's the way that "public" functions work in JavaScript. You could make details a privileged function by defining it within the constructor:
function Person(name, age) {
this.details = function() {
return "name: "+name+", age: "+age;
};
}
Of course, that means that each instance of Person gets it's own copy of the details function.
You could also, as #Chuck suggests, make name and age public members, in which you would have access to them in a prototype function:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.details = function(){
return "name: " + this.name + ", age: " + this.age;
};
No. Typically you would either use the second approach, or set this._name = name; in the constructor and reference it that way in the other method.
Of course not, the function was declared in a scope, different to the scope where the arguments/variables were declared, so JS wouldn't know which variables you're on about. Suppose you had a second closure, or better (well, worse actually) yet: a global variable called name. Which one would JS pick?
Here's an example for you:
function MyObject(name)
{
var localVar = 'foobar';
this.evilMethod = (function(localVar)
{
return function()
{
console.log('localVar = '+localVar);//=== name
};
})(name);
this.badMethod = function()
{
console.log('localVar = '+ localVar);// === 'foobar'
};
}
var name = 'Global Name';
var anotherClosure = (function(name)
{
var localVar = name.toLowerCase();
return function()
{
console.log(name);
console.log(localVar);
}
})('Bobby');
MyObject.prototype.closureVars = function()
{
console.log(name);//Global name
console.log(localVar);//undefined
};
Now first off: this is terrible code, but you get the point: you can have hundreds of variables with the same name, which one JS has to use, might not always be clear.
Giving prototypes access to instance closure variables has other implications, too: you could, for instance change their values, which defeats the point of having a closure in the first place. But the biggest problem by a country mile would be: multiple instances! If you create a constructor, odds are you're going to instantiate more than 1 object with it. How would that work, if they all share the same prototype?
Just assign the arguments/variables you want to access in the prototype to a property, like FishBasketGordo's example does
I have this code:
function Person(name){
var self = this;
this.name = name;
function hello(){
alert("hello " + self.name);
}
return {
hello: hello
};
}
var newPerson = new Person("john");
newPerson.hello();
I want to be able to use the 'this' keyword to access the 'name' property in the 'hello' function; I want an alternative to using the 'self' variable.
Except using the $.proxy function of jquery to control the context, how can I write the same code but without the variable 'self'?
I want a code that looks like below but 'name' is always 'undefined' when I call 'newPerson.hello()'. I don't know why because I have always believed that the scope of a function is always the object at the left of the dot of the caller and in this case, it's 'newPerson' that have been assign a value 'john' when creating the object.
function Person(name){
this.name = name;
function hello(){
alert("hello " + this.name);
}
return {
hello: hello
};
}
var newPerson = new Person("john");
newPerson.hello();
Thank you.
You can use .bind to force the owner of a function to be whatever object you pass. So, you can write your Person object like so:
function Person(name){
this.name = name;
var hello = function(){
alert("hello " + this.name);
}.bind(this);
return {
hello: hello
};
}
This will ensure that .hello always executes in the context of the Person that is calling it.
Here's a demo:
--- jsFiddle DEMO ---
Don't use return by default when using the new keyword the function will return this
you will need to change how your function is declared how ever.
Here is a fiddle
http://jsfiddle.net/SaintGerbil/9SAhD/
function Person(name){
this.name = name;
this.hello = function (){
alert("hello " + this.name);
}
}
var newPerson = new Person("john");
newPerson.hello();
EDIT if you require name to be private then here is an alternative
function Person(name){
var _name = name;
this.hello = function (){
alert("hello " + _name);
}
}
var newPerson = new Person("john");
newPerson.hello();
In answer to your question there are 4 ways to call a function
These affect the value of this they are
Constructor call (using the new keyword) where this is the new object which is returned automatically.
Method call if a function is attached to an object and called from it then this is the object called from.
Function call a direct call to a function will result in this being the global object, (a common mistake when calling a contstructor without new)
Apply\Call call when using a method to specify what this should be (see jackwanders as an example)
FURTHER EDIT
So taking your desired code at the start and explaining what is happening.
function Person(name){
this.name = name; // 1
function hello(){ // 2
alert("hello " + this.name); // 3
}
return {
hello: hello
}; //4
}
Person as a function can be called two ways:
var x = Person("ted");
and
var x = new Person("jimmy");
Since you have named Person with a capital it implies that you are expecting people to use new.
So sticking with that we enter the function and javascript creates a new object and assigns it to this.
line 1 we then attach a 'name' variable to this and initialise with the passed parameter.
line 2 we then attach a 'hello' function to this.
line 3 the function expects to have a 'name' variable exist attached to this (which it does for now).
line 4 rather than return this (default behavior) we are now declaring a new object and attaching the function to it. This new object does not have a 'name' variable with in its scope.
So when you create the object you get an object with a function attached but it cannot get to the variable it needs to execute correctly.
Which is why you are getting the undefined.
Does that make sense I always worry that I'm waffling when I have to expand the textbox?
Or if I wrote out your function as verbosely as possible it would look something like this.
function Person(name){
var this = new Object();
this.name = name;
var hello = function (){
alert("hello " + this.name);
}
this.hello = hello;
var that = new Object();
that.hello = hello;
return that;
}
You appear to be confusing two things.
a) Regular functions
function CreatePerson(name) {
// create a new object
var person = {};
// or (if you want to provide a prototype)
var person = Object.create(...);
// fill it with some more data
person.name = name;
person.foo = 123;
person.bar = function() { /* ... your method body ... */ };
}
That's invoked like:
var person = CreatePerson("Jack");
b) Constructors
function Person(name) {
// called after a Person is created,
// `this` is bound to the new object
// and its prototype is set to `Person.prototype`
this.name = name;
this.foo = 123;
this.bar = function() { /* ... your method body ... */ };
}
var person = new Person("Jack");
Note the special new syntax here.
When using this style, you'll probably want to create the methods only once, not for every created instance:
function Person(name) {
// called after a Person is created,
// `this` is bound to the new object
// and its prototype is set to `Person.prototype`
this.name = name;
this.foo = 123;
}
Person.prototype.bar = function() {
/* ... your method body ... */
};
var person = new Person("Jack");
Doing like this works.
If you only want to access the this within the function you can do like this.
you use the return {hello:hello} to declare the function and you don't need do to it, unless it's what you want
example 1
function _persons(array) {
this.available = array;
this.write = function () {
writedata(this.available, '#array2');
};
this.SortAge = function () {
array.sort(compare);
writedata(this.available, '#array3');
};
array.sort(compareName);
}
var users = new _persons(myarray);
example 2
function Person(name ){
this.name = name ;
this.hello = function(){
alert("hello " + this.name);
}
}
var a = "john";
var newPerson = new Person(a);
newPerson.hello(); var
otherPerson = new Person("annie");
otherPerson.hello();
Suppose I have two constructor function:
var Person = function(xx,xx,xxx,xxxxxxx) {
//Person initialization
}
var Man = function(xx,xx,xxx,xxx) {
//Man initialization
}
And I want Man extends from Person.
The following is what I thought:
Given a created Man object:
var m=new Man("xx",....);
1) when a property of m is accessed,it will search it in Man.prototype.
2) If not find, It should find it in Man.prototype.__prop__.
So what I have do is make the Man.prototype.__prop__ linked to Person.prototype.
I know this is the common way:
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
Man.prototype=inherit(Person);
But when I try this:
Man.prototype.prototype=Person.prototype.
Why it does not work?
It sounds like you actually want to link instances of Man to an instance of Person that retains any properties added in its constructor, in which case you might really want something like this:
function Person(a, b) {
this.a = a;
this.b = b;
}
function Man() {}
Man.prototype = new Person("val1", "val2");
var m = new Man();
console.log(m.a);
...which prints val1.
Additional Ramblings
The purpose of inherit is to create an object from a function whose prototype is that of the given super class (without explicitly using new), which is exactly what it does. Therefore, the following prints string:
function Person() {}
Person.prototype.test = "string";
function Man() {}
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
var t = inherit(Person);
console.log(t.test);
But you generally want to assign the returned object to another function's prototype:
Man.prototype = inherit(Person);
var m = new Man();
console.log(m.test);
...so that m.test also prints string, which means that objects created using Man are linked to Person's prototype).
Note that Man.prototype.prototype is undefined and -- this is the important part -- also meaningless. Functions have prototypes. Other objects (such as Man.prototype) do not. The prototype property is not magical in any other context. Assigning a value to a random object's prototype property doesn't do anything special. It's just another property.
Note also that the thing we returned from inherit is linked to Person by way of its prototype and has no access to any properties added to instances of Person.
How I do it (in regards to your example):
var Person = function () {
}
// Define "Person" methods
var Man = function () {
}
Man.prototype = new Person();
// Define "Man" methods
UPDATE
Regarding constructors with parameters: just found this SO question that can really help you figure it out (second answer, first part): JavaScript inheritance: when constructor has arguments.
There are quite a few generic methods to do that. I will provide three of them:
1.) Using Function object as a constructor and as a prototype object for inherited new objects. The implementation should look like as the following:
var person = {
toString : function() {
return this.firstName + ' ' + this.lastName;
}
}
function extend(constructor, obj) {
var newObj = Object.create(constructor);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
var man = extend(person,
{
sex: "male",
age: "22"
});
var name = extend(man,
{
firstName: "Simo",
lastName: "Endre"
});
name.man;
name.toString();
2.) In this case we'll use the Function object as the constructor for simulating the classical inheritance in a language like C# or Java. The prototype property of an object will be used in the role of a constructor and the the newly created object will inherit all the properties from the object prototype root. In this case the object's prototype has only one kind of augmentation role, the effective implementation is done in the function method.
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.toString = function() {
return this.firstName + ' ' + this.lastName;
}
function inherit(func) {
// passing function arguments into an array except the first one which is the function object itself
var args = Array.prototype.slice.call(arguments, 1);
// invoke the constructor passing the new Object and the rest of the arguments
var obj = Object.create(func.prototype);
func.apply(obj, args);
//return the new object
return obj;
}
var man = inherit(Person, "Simo", "Endre");
man.toString();
3.) The well known inheritance model:
function extend(o) {
function F() {}
// We'll set the newly created function prototype property to the object.
//This act as a constructor.
F.prototype = o;
// Using the `new` operator we'll get a new object whose prototype is o.
return new F();
};
So if I was to create an object literal like this..
var person1 = {
age : 28,
name : 'Pete' }
Then I add a function to the object...
person1.sayHelloName = function(){
return 'Hello ' + this.name;
};
alert(person1.sayHelloName());
Im wondering where the 'prototype' keyword comes into all this. I cant add a prototype to an object (only to a function constructor) so would I be able/have to use the prototype in this scenario.
You can't use the prototype in this way because, like you say, it's used to add properties to a constructor which must be defined with the function() keyword. What you are doing in your example is extending the person1 object, but that object is just a single variable and not an instantiable class. Meaning you can't "create" another person1 using the new keyword, whereas you could if it were an instance of a defined class.
You don't have to (can) use prototype here. As you have only one instance of something (one object), you can set the functions directly on the object.
FWIW, ECMAScript 5 defines Object.getPrototypeOf with which you can get the protoype of any object (only available in "modern" browsers).
var Person = function() {
this.age = 28;
this.name = "peter";
}
Person.prototype.sayHelloName = function(){
return 'Hello ' + this.name;
};
var person1 = new Person;
You would bring prototype into play to define methods all instances of a class have. In your case that doesn't make any sense since you only create a standalone object that doesn't belong to a class.
function Person (age, name)
{
this.age = age;
this.name = name;
}
Person.prototype.sayHelloName = function ()
{
return 'Hello ' + this.name;
}
person1 = new Person(28,'Pete');
alert(person1.sayHelloName());
This only makes sense of course if you are expecting to be creating more than one person.
There's no need for you to use 'prototype' in object literal. Only when you use the constructor pattern (and some other design patterns), that you can use 'prototype'.