Javascript: lexical scoping issue using new keyword constructor - javascript

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();

Related

JavaScript object's function not returning

i have a question about JavaScript!
I've been studying JavaScript for a few days, but it wasn't that hard cuz i alread have a lot of knowledge from Java. I have programmed for long time until now. I work with objects and i wanted to add a function to the object. But that funcion doesn't work properly...
Code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function person(name){
this.name = name;
}
function printName(){
return this.name;
}
var joza = new person("Josip");
</script>
</head>
<body>
<script type="text/javascript">
document.write(joza.printName());
</script>
</body>
</html>
So this code is supposed to use the object's function and print out it's name...
But... all I get is just a blank webpage!
Please help!!
Thank you!!
You got some brutal answers, but the one with a lexical closure seems to be missing. So here you are:
function Person(name){
this.printName=function(){
console.log(name);
};
}
test=new Person("John");
test.printName();
The thing is that JavaScript functions retain the environment where they were declared. So here the inner function can access local variables of the outer function, even when the outer function is not running any more. Actually it is similar to accessing final local variables from anonymous inner classes in Java, just these variables do not have to be final (so it would be perfectly possible to provide a setName method, which would alter the same name variable).
It is not very important/interesting for this particular use case, but this is a common way how you can get parameters into callback methods for example.
And the best part for confusion:
Your original code can be used too. JavaScript is not very picky about "this", you can invoke any method on any object:
function Person(name){
this.name=name;
}
function printName(){
console.log(this.name);
}
test=new Person("Jane");
printName.call(test);
Functions are objects, and they have a call method. Where the first argument sets this, and the rest are just passed as arguments for the method itself. For completeness: there is an apply method too, where the arguments for the function are passed as an array.
This is not very important here either, however a thing you should keep in mind is that this is not necessarily the object you expect. Yet again callback methods: if you use an object method as a callback, when the browser invokes it, this is usually the window object.
Ignoring the HTML for now here is your code:
function person(name){
this.name = name;
}
function printName(){
return this.name;
}
var joza = new person("Josip");
joza.printName() // Error
So what's going on above is that you are creating this person constructor function and then another function outside of it. Your joza object does not have the printName function on it.
The printName function is just a regular function that has its own context for this, which in this case is just the window.
When you call joza.printName you will find that printName doesn't exist on the joza object you just created.
Try this instead by adding your printName method to the actual returned person object:
function person(name){
this.name = name;
this.printName = function() {
return this.name
}
}
var joza = new person("Josip");
joza.printName() // "Josip"
Just a minor change (you're trying to call the printName method of the person object).
function person(name){
this.name = name;
this.printName = function() {
return this.name;
}
}
var joza = new person("Josip");
document.write(joza.printName());
check this revision :
var person = function(name){
var tmp = {};
tmp.name = name;
tmp.printName = function(){
return tmp.name;
}
return tmp;
}
var joza = new person("Josip");
Fiddle : https://jsfiddle.net/jwvvkgaf/
This is a factory pattern, one of the way to accomplish what you want.
If you want simple constructor pattern :
var person = function(name){
this.name = name;
this.printName = function() {
return this.name;
}
}
Here's the way to add object like java in javascript
function person(name){
this.name = name;
}
Add methods like this. All Person objects will be able to invoke this
person.prototype.printName = function(){
return this.name;
}
Instantiate new objects with 'new'
var joza = new person("Josip");
Invoke methods like this
joza.printName();
<html>
<head>
<script type="text/javascript">
function person(name) {
this.name = name;
this.printName = function() {
return this.name;
}
}
var joza = new person("Josip");
</script>
</head>
<body>
<script type="text/javascript">
document.write(joza.printName());
</script>
</body>
</html>
The
function printName(){
return this.name;
}
is not a member of Person ,so you can get the name property from it, you should put the method inside the pesron object
(function(global){
function person(name){
this.name = name;
}
person.prototype ={
printName: function(){
return this.name;
},
};
window.person = person;
}(window));
var joza = new person("Josip");
document.write(joza.printName());
Let me break it down for you. (function(){ /* code in here */ }()) this is a scope. Basically kind of like a namespace so you don't pollute the window global variable. Then you declare the function person which is more or less your "constructor" that constructor initializes the property name. Then, put your functions inside the prototype and call them.

Some basic questions about OOP in JS

currently I´m learning about objects and I´m not sure about the terminology of some words and descriptions. I´m sure some of you can help me out here :)
Code example:
function Person(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
My questions:
Is there actually a difference between the code above and the following code:
var Person = function(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
Which one is better practice? I guess the first code snippet, since it´s less code.
Now the terminology.
2.1 Am I right, given the code example at the beginning, that you call the following snippet the Prototype?
function Person(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
2.2 Am I right, given the code example at the beginning, that you call the following snippet the constructor(-function)?
var jon = new Person("Jon")
Thanks and happy eastern! :)
Point 1: The big Words
function Person(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
This function has a name 'Person'. This is called a Function statement.
var Person = function(name) {
this.name = name,
this.introduce = function() {
console.log("My name is " + this.name);
}
}
var jon = new Person("Jon")
jon.introduce();
This funciton is anonymous and does not have a name. We can assign a name but
it is not required since the variable can be used to execute the function. This is called a function expression.
You can read more about Function statements and expressions here:
https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
Point 2: Execution (Hoisting)
Functions assigned to variable must be called after the function is defined because of the way hoisting works.
So for the first case the function can be called either below or above it is defined.
But for the second case the function must be invoked after it. Since it is stored in a variable. Invoking it before the function will return undefined. It won't give error. The variable is there in memory space but it is not defined at that point.
You can read more about variable and function hoisting here:
http://adripofjavascript.com/blog/drips/variable-and-function-hoisting
Point 3: Function constructor:
In your case the term to use for function is "Function Constructor" since you are essentially using function as a constructor for the Person object to define it's properties.
It's simply the difference between a function expression vs. declaration. I would go with the seemingly simpler declaration instead of the unnamed anonymous function assigned to a variable.
That snippet shows the constructor function also returned by jon.constructor. The prototype of a person constructed by that constructor function - which you can access via Object.getPrototypeOf(jon) or Person.prototype - is pretty much empty. Assigning this.name = name doesn't add a name attribute to the prototype but the currently created object.
It's the new operator applied to a constructor function returning a newly constructed object.

Do functions attached to the prototype property not have closure

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

Alternative to 'self = this' with object in javascript

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();

How does the javascript create an object?

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).

Categories

Resources