I don't understand working of the program - javascript

I am learning objects in JavaScript and I don't understand methods assigned as property to objects, when objects are defined through user-defined functions.
This is a code snippet from tutorial point.com/JavaScript
<script type = "text/javascript">
function addPrice(amount) {
with(this){
price = amount;
}
}
function book(title, author) {
this.title = title;
this.author = author;
this.price = 0;
this.addPrice = addPrice;
}
</script>
<script type = "text/javascript">
var myBook = new book("Perl", "Mohtashim");
myBook.addPrice(100);
document.write("Book title is : " + myBook.title + "<br>");
document.write("Book author is : " + myBook.author + "<br>");
document.write("Book price is : " + myBook.price + "<br>");
</script>
I want to know how the this.addPrice = addPrice is working and why if I remove the line no output is shown?

JS is pretty flexible language. In JS this:
var obj = {
name: "Raju Ritigya",
sayHi: function() {
console.log("hello, I'm " + this.name);
}
};
Is the same as this:
var obj = {};
obj.name = "Raju Ritigya";
obj.sayHi = function() {
console.log("hello, I'm " + this.name);
};
Basically, there are two ways of adding properties and methods to an object in JS.
With that being said, your course is teaching you how to write "Classes", constructors and this in JS. IMO if you're just starting with JS, this is too complex to understand. JS doesn't support Classes natively and it tries to mimic them with prototype inheritance.
But anyway, here's my 0.02$ on what's going on there
In JS you have primitive types (string, number, boolean, symbol, null, undefined) and everything else is an object (yes, array is an object, function is an object, object is an object).
Primitive values are passed around by value and they are immutable, but objects are passed by reference (a point in memory) and they are mutable
var foo = {};
var bar = {};
console.log(foo === bar) //false
Even though foo and bar look the same, they point to different places in memory, hence for JS they are not the same!
var foo = {};
var bar = foo;
bar.name = "random name";
console.log(foo.name); // "random name"
And now foo and bar point to the same reference and making changes to one of them reflect to the other one.
In JS every function needs to return something. If you don't explicitly put a return statement in your function it will return undefined and if you use new keyword in front of your function call, it will return a new object that will have that function as a constructor.
So, in conclusion, what's going on there is that you have a constructor (book) that's gonna return an object with 3 properties (author, title, price) and a method (addPrice). That method is a function (and as we already said, functions are objects in JS and can be easily passed around). It would be exactly the same if you wrote your constructor like this:
function book(title, author) {
this.title = title;
this.author = author;
this.price = 0;
this.addPrice = function(amount) {
this.price = amount
};
}
As #deceze mentioned, using with is highly discouraged.
By removing the this.addPrice = addPrice line, you don't add a method to your object but later on you try to call it on this line myBook.addPrice(100);
Your code breaks on that line and JS won't continue executing the rest of your program (you can open console tab in dev tools and see the error there).
Hope it helps,
Cheers!

Related

Running order of JS constructor

One question about JS constructor function:
var hm = {};
new function(name){
hm[name] = this;
}("hello")
Could anyone give me a little explanation about how this constructor running (such as which part runs first)
First var hm becomes an Object, then a new Anonymous function is called with ("hello") passed into name argument. The important thing to understand here is that when you see () with or without any arguments after a function name or an Anonymous function, it calls the function. In this case the new keyword and the fact that there is a this property inside the function makes it a Constructor. hm inside the Constructor creates a property based on the name argument and assigns the new instance itself to hm[name], as this refers to each new instance. End result is that hm.hello or hm['hello'] now refer to the new instance. Of course, all code runs from top to bottom and according to standard order of operations, like String resolution before assignment. Also, note that, this won't work:
func('wow');
var func = function(x){
console.log(x);
}
This will work:
func('wow');
function func(x){
console.log(x);
}
If you lack understanding of Constructors altogether you should know that a Constructor is used so you can have multiple instances of similar Objects. For instance:
function Person(last, first, middle){
this.lastName = last; this.firstName = first; this.middleName = middle;
this.said = this.ate = '';
this.saySomething = function(anything){
this.said = anything;
return this;
}
this.eatSomething = function(food){
this.ate = food;
return this;
}
this.didWhat = function(){
var m = this.middleName ? ' '+this.middleName : '';
var n = this.firstName+m+' '+this.lastName;
if(this.said){
n += ' said, "'+this.said+'"';
n += this.ate ? ', and' : '.';
}
if(this.ate){
n += ' ate '+this.ate+'.';
}
return n;
}
}
var Bob = new Person('Small', 'Bob', 'Richard');
Bob.saySomething('This programming stuff is pretty cool.').eatSomething('Some Vegan Food');
console.log(Bob.didWhat());
var Sally = new Person('Jones', 'Sally');
Sally.saySomething("It just takes time, but you'll get it.");
console.log(Sally.didWhat());
Remember that the keyword this refers to the instance itself. In the example above I have created Bob and Sally Objects by calling new instances of Person. By returning this within a Constructor method you can chain methods, since the result of the executing method with be the instance itself.
Note that
Bob.saySomething('This programming stuff is pretty cool.').eatSomething('Some Vegan Food');
is the same as
Bob.saySomething('This programming stuff is pretty cool.');
Bob.eatSomething('Some Vegan Food');
since, as far as .eatSomething() is concerned, Bob and this are synonymous.
If you just want to access a property, it's like:
console.log(Bob.said);
console.log(Bob.lastName);
Bob.said = "Now you're getting it.";
console.log(Bob.didWhat());

What is a super method in javascript? [duplicate]

I've been reading the chapter on functional inheritance in Crockford's 'The Good Parts'. In the mammal example he gives I'm a bit confused as to why he uses the superior method to modify the get_name function. Here is the example in question:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
var mammal = function (spec) {
var that = {};
that.get_name = function () {
return spec.name;
};
that.says = function () {
return spec.saying || '';
};
return that;
};
var myMammal = mammal({
name: 'Herb'
});
var cat = function (spec) {
spec.saying = spec.saying || 'meow';
var that = mammal(spec);
that.purr = function (n) {
var i, s = '';
for (i = 0; i < n; i += 1) {
if (s) {
s += '-';
}
s += 'r';
}
return s;
};
that.get_name = function () {
return that.says() + ' ' + spec.name + ' ' + that.says();
};
return that;
};
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function () {
return method.apply(that, arguments);
};
});
var coolcat = function (spec) {
var that = cat(spec);
var super_get_name = that.superior('get_name');
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
var myCoolCat = coolcat({
name: 'Bix'
});
var name = myCoolCat.get_name(); // 'like meow Bix meow baby'
I'm confused about this because I can replicate the same thing by removing the superior method and just changing coolcat as follows:
var coolcat = function(spec) {
var that = cat(spec);
var super_get_name = that.get_name();
that.get_name = function(n) {
return 'like ' + super_get_name + ' baby';
};
return that;
};
So, I don't understand why Crockford chooses to use the superior method. Is anyone able to explain at all?
The idea here is that this:
var super_get_name = that.superior('get_name');
makes super_get_name into a function that — every time it is called — invokes that's original get_name method. This allows the new get_name to call the old (super-class) get_name.
Now, if the original get_name method will never have any effect other than to return a single value that never changes, then yeah, this is kind of pointless; you can just save that single-value-that-never-changes and then use it in the new get_name. But if the original get_name can actually do things (such as, say, run an AJAX request, or change the styling of an HTML element), or if its return-value can change (say, if there were some corresponding set_name method), then there would be an important difference between what your code does (save the original return-value and use it) and what Crockford's code does (save the original method and invoke it).
The confusion that arises from this chapter of Crockford's book arises as what Crockford describes is "his" preferred pattern for implementing inheritance in JavaScript, which relies on his extending the Function object with the Function.prototype.method (chapter 1.3) which he uses to add methods to the Function object.
The problem addressed in the coolcat example is the need to access the method of the parent type. In 'classical' OO languages like Java this is natural as classes exist in their own right. In JavaScript inheritance is prototypical, you make an object of type mammal and then modify the object to create the type cat or coolcat.
Depending on your design you may add properties and functions or override an 'inherited' function. The problem arises when you override an 'inherited' function, in JavaScript you basically replace the old function with the new function, thereby loosing the older function.
Crockford now needs to do two things:
get the parent's (cat's) get_name method; and
save it in a manner that can be used from within the overridden method.
In this code:
var coolcat = function(spec) {
var that = cat(spec),
super_get_name = that.superior('get_name');
that.get_name = function(n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
He does 1. by calling the superior method to get a function that gets the cat's get_name function;
and he does 2. by saving it to the super_get_name variable within the coolcat function(/object) allowing access to the cat's get_name function before it is overridden (more correctly overwritten) by the coolcat's get_name function.
In my opinion the confusion arises because:
The superior method is named oddly: the 'superior' method is simply a function look up by name method and could be better named, for example as getFunctionByName (you can try this by replacing the string get_name, by purr, the coolcat's get_name will now call purr, just remember to call it as super_get_name(10) otherwise you'll get an empty string back).
Secondly the code and the pattern obfuscates the code by relying on some particular Crockford patterns, and is likely to stresses you out if you attempt to dive into this chapter without having followed the entire book.
I think there is a simpler way to achieve this, one that I think because it is completely localized is easier to understand etc., as in the code below:
var coolcat = function(spec) {
var that = cat(spec);
that.parent_get_name = that.get_name;
that.get_name = function() {
return 'like ' + this.parent_get_name() + ' baby';
};
return that;
};
There are some other oddities for example the argument n in definition of the coolcat get_name function, which I can only assume came from copying the purr function, which would suggest a ghost writer!
Finally, I would suggest that before one reads the book one should listen to his talk on 'JavaScript the good parts'. The talk is absolutely brilliant, much better than the book.

Accessing to superior methods in the functional Inheritance pattern (a counter example unexpectedly works !)

In the process of understanding the functional inheritance pattern introduced by Crockford I come with this peace of code:
var person = function(spec) {
var that= {};
that.name = spec.name;
that.job = spec.job || '';
that.greeting = function() {
console.log("Hello, I'm " + this.name + " and I'm a " + this.job);
};
return that;
};
var coder = function(spec) {
var that = person(spec);
that.job = "coder";
// that.superior_greeting= that.superior('greeting');
that.superior_greeting = that.greeting;
that.greeting = function(){
console.log("I write code");
};
return that;
};
Lets createcoder instance aCoder = coder({name: "tarrsalah"});, calling the greeting method prints I write code as I suspected.
My question is: Why running the superior_greeting give me a different result (prints Hello, I'm tarrsalah and I'm a coder) ?
Is superior_greeting points to that.greeting, isn't modifying the greeting method should modify the superior_greeting also ?
ps: very related question.
"Is superior_greeting points to that.greeting, isn't modifying the greeting method should modify the superior_greeting also?"
No. The superior_greeting doesn't point to greeting in the way you seem to assume. JavaScript doesn't have pointers, though its objects (including functions) are held as a reference.
So at the moment that you do this:
that.superior_greeting = that.greeting;
...the superior_greeting holds a reference to the same function as greeting. It does not however hold a pointer to the greeting property itself.
So basically you didn't make a copy of the function, but you did make a copy of the reference to the same function, which exists somewhere in memory.
Because you don't have a pointer to the .greeting property, changes to that property are not visible from .superior_greeting.
So when you do this:
that.greeting = function(){
console.log("I write code");
};
...you created a new function, and assigned the new reference to that new function to the .greeting property.
Now .greeting and .superior_greeting are holding reference to two different functions.
It is so because
that.superior_greeting = that.greeting;
comes before
that.greeting = function(){
console.log("I write code");
};
that.superior_greeting is set to the old person version of it, before coder overwrites it.
It's like
that.superior_greeting = function() {
console.log("Hello, I'm " + this.name + " and I'm a " + this.job);
};
that.greeting = function(){
console.log("I write code");
};
If you reverse your two original lines, you would wind up with something different.

trying to understand javascript objects

I've written this piece of code to try help me understand how objects work in js a bit more.
function person(personName){
var thiz = this;
var nameOfMe = (typeof(personName) === 'undefined')? 'default':personName;
var faveFood = 'stuff';
thiz.speakName =function(){
alert('I am '+ thiz.nameOfMe);
}
thiz.gotFoodAlert = function(){
alert('Yummy! I haz ' + thiz.faveFood )
}
}
var someGuy = new person('joe');
someGuy.faveFood = 'cheesecake';
someGuy.speakName();
var elseGuy = new person();
elseGuy.nameOfMe = 'bob';
elseGuy.speakName();
I'm trying to simulate a classical inheritance model to build a class then instantiate a person. Setting it separately in elseGuy.speakName() alerts 'bob' ok.
What I don't understand is why doesnt the someGuy.speakName() alert 'joe' when I instantiate?
update: on further reflection and taking notes from people commented, I should just give up trying to simulate a classical inheritance model.
Because nameOfMe is not a property of this in the first example. Try the following instead:
function person(personName) {
var nameOfMe = (typeof personName === 'undefined')? 'default':personName;
var faveFood = 'stuff';
this.speakName = function () {
alert('I am ' + nameOfMe);
}
this.gotFoodAlert = function () {
alert('Yummy! I haz ' + faveFood )
}
}
Even better:
function Person(personName) {
this.nameOfMe = personName ? 'default' : personName;
this.faveFood = 'stuff';
}
Person.prototype.speakName = function () {
alert(this.nameOfMe);
};
Person.prototype.gotFoodAlert = function () {
alert('Yummy! I haz ' + this.faveFood);
};
You have to set nameOfMe as a property of thiz:
thiz.nameOfMe = (typeof(personName) === 'undefined')? 'default':personName;
Also, unless you absolutely have to, why don't you use the normal this instead of thiz?
thiz = this aliasing is unnecessary here. You only need it for "private" properties by additional closures.
thiz.nameOfMe is causing an additional closure here, needlessly.
The value of thiz.nameOfMe is not "joe" because the object referred to by thiz does not have a nameOfMe property yet. The nameOfMe variable in constructor code is something else.
You are not using "the classical inheritance model". There are no classes. You are creating a person instance, that is, an object that has person as its constructor, and the object that person.prototype currently refers to next in its prototype chain. Nothing more, nothing less.
It is good code style to have constructor identifiers start with a capital letter: Person.
RTFM.

Object Creation in javascript

Just for the kicks i am trying to create a simple data object in javascript. Here is the code.
var roverObject = function(){
var newRover = {};
var name;
var xCord;
var ycord;
var direction;
newRover.setName = function(newName) {
name = newName;
};
newRover.getName = function() {
return name;
};
newRover.setDirection = function(newDirection) {
direction = newDirection;
};
newRover.getDirection = function() {
return direction;
};
newRover.setXCord = function(newXCord) {
xCord = newXCord;
};
newRover.getXCord = function() {
return xCord;
};
newRover.setYCord = function(newYCord) {
yCord = newYCord;
};
newRover.getYCord = function() {
return yCord;
};
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
return newRover;
};
rover1 = new roverObject();
rover2 = new roverObject();
rover1.setName("Mars Rover");
rover1.setDirection("NORTH");
rover1.setXCord(2);
rover1.setYCord(2);
console.log(rover1.where());
console.log(rover1);
rover2.setName("Moon Rover");
rover2.setDirection("SOUTH");
rover2.setXCord(1);
rover2.setYCord(1);
console.log(rover2.where());
console.log(rover2);
There are few questions that I have around this creation.
I want to create an object where the properties/attributes of object are private and not visible to world. Am I successful in doing that? Can I really not access the object attributes?
Is there a better way to create this kind of object?
If I want to inherit this object, I should do a newObject.prototype = roverObjectwill that work? And will that make sense most of all.
Finally I have a wierd problem. Notice the last method of objet "where" which returns a concatenated string. Here I tried following code instead.
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
}();
and then did a following console.log
console.log(rover1.where);
console.log(rover2.where);
It threw following error for me:
cannot access optimized closure
Why would it say that? What am I doing wrong?
Thanks for all the help. Any review comments would be appreciated too!
Cheers
Am I successful in doing that? Can I really not access the object attributes?
Indeed. You don't have object attributes, you have local variables in the roverObject function. Local variables can't be accessed from outside, only from the functions inside the roverObject function that have a closure over them.
That you are calling roverObject as a constructor, with new roverObject, is irrelevant, as you are returning a different object from the function. Saying var rover1= roverObject() without the new would do exactly the same thing. Notably the object returned by [new] roverObject is a plain Object as you created it from {}; rover1 instanceof roverObject is false.
If you wanted instanceof to work, you would have to call with new, and use this instead of newRover in the constructor function.
If I want to inherit this object, I should do a newObject.prototype = roverObject will that work? And will that make sense most of all.
No. You currently have no allowance for prototyping. You are using a separate copy of each method for each instance of the roverObject. You can do certainly objects this way but it's a different approach than prototyping. If you wanted to make something like a subclass of roverObject in the arrangement you have now, you'd say something like:
function AdvancedRover() {
var rover= new roverObject();
rover.doResearch= function() {
return rover.where()+' and is doing advanced research';
};
return rover;
}
Note since the ‘private’ local variables in the base class constructor really are private, even the subclass cannot get at them. There's no ‘protected’.
newRover.where = function(){ ... }();
What's that trying to do? I can't get the error you do; all the above does is assigns the string with the location to where (before the setter methods have been called, so it's full of undefineds).
Is there a better way to create this kind of object?
Maybe. see this question for a discussion of class/instance strategies in JavaScript.
Q1: you can create 'private' members in javascript 'classes'. In javascript, privacy is not determined by any access specifier. Instead, access needs to be specifically instrumented. Example:
function MyClass() {
this.val = 100; // public;
var privateVal = 200;
function getVal() { return this.val; } // private method;
this.getPrivateVal = function() { // public method, accessor to private variable
return privateVal;
}
}
Object scope in javascript is governed by a queer concept called closures. AFAIK, there is no parallel concept in any other popular launguage like C+/Java etc.
While I understand what closures are, I cannot put it in words. Perhaps a demonstration will help you:
function closureDemo() {
var done=false;
function setDone() { done=true; }
doLater(setDone);
}
function doLater(func) { setTimeout(func,1000); }
closureDemo();
now, while setDone is called from within doLater, it can still access done in closureDemo, even though done is not in scope (in the conventional procedural sense).
I think you will understand more when you read this.
Q2: I can only say what I do; I don't know if it is better or not. If I wrote your code, it would look like this:
function RoverObject() {
var newRover = {}; // privates
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) {
name = newName;
};
this.getName = function() {
return name;
};
this.setDirection = function(newDirection) {
direction = newDirection;
};
// and so on...
this.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
}
var rover1 = new RoverObject();
Points to note:
capitalization of "class name"'s first letter
use of this instead of roverObject
this function is a pure constructor. it returns nothing.
Q3: if you want to do inheritance, then my method (use of this) will not work. Instead, the public methods should be a part of the prototype of RoverObject. Read this. Excellent material.
Hope that helps.
EDIT: There is a problem with the way your code is doing work. Problems:
your function does not do what its name suggests. Its name had better be createRoverObject, because that's exactly what it is doing. It is not working like a class constructor
the methods supported by your class are part of the object, but the data members are not. While this may work (and it is not, as your console.log() problem suggests), it is not a good way to implement a class in javascript. The problem here is of closures. Again, i'm unable to articulate what the problem specifically is, but I can smell it.
With regards to 4. - you are trying to log the function, not the result of calling the function. Should be console.log(rover1.where()); My guess firebug(I assume it's firebug's console.log) does not like to log function definitions.
EDIT Oh I get it, you are actually executing the where funcion when you assign rover.where. Are you trying to get what looks like a property to actually be a function? If that's the case it won't work. It will have to be a function if you want it to be evaluated when it's called.
What happens in you case where gets executed in the constructor function. At that point you are still creating the roverObject closure and hence it's too early to access it's private variables.
This is just addressing point 1 of your post.
Here's a good article on javascript private members and more:
Private Members in JavaScript
Defining your object like this gives you private members.
function RolloverObject() {
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) { name = newName; };
this.getName = function() { return name; };
this.setDirection = function(newDirection) { direction = newDirection; };
this.getDirection = function() { return direction; };
this.setXCord = function(newXCord) { xCord = newXCord; };
this.getXCord = function() { return xCord; };
this.setYCord = function(newYCord) { yCord = newYCord; };
this.getYCord = function() { return yCord; };
this.where = function() {
return "Rover :: " + name + " is at Location(" + xCord + "," + yCord + ") pointing to " + direction;
};
}
var rolloverObject = new RolloverObject();

Categories

Resources