Prototypes and scoping in Javascript - javascript

var Bar = function(a, b) {
this.b = b - a;
this.m2 = function() {
return this.a / b;
}
}
var Foo = function(a, b) {
this.a = a;
this.b = b;
Bar.prototype.a = a + b;
Bar.prototype.b = a - b;
Bar.prototype.m1 = Bar.prototype.m2;
Bar.prototype.m2 = function() {
return this.a * a + this.b * b;
}
}
o1 = new Bar(1, 5);
o2 = new Foo(2, 3);
o4 = new Foo(3, 2);
r1 = o1.m1();
console.log(r1)
console.log(o1.a)
console.log(o1.b)
The value of r1 seems to be based off of the prototype methods set forward from the instantiation of the o2 Foo object, and not the the o4 Foo object. However, removing the o4 Foo object seems to stop the entire thing from working. Similarly, removing o2 also prevents it from working.
I feel like correct behavior would be the modification of the object Bar's prototype by o4, meaning the value returned from executing o1.m1() would be derived from the o4 Bar prototype. So,
return this.a * 3 + this.b * 2;
However this is not the case. The correct solution returns from this:
return this.a * 2 + this.b * 3;
This seems quite counterintuitive. What properties are at work here? Why does the solution (that r1 == 22) rely on both the instantiation of o2 and o4?
EDIT: r1 should be 22. I'm trying to figure out what path I need to go down to reach this number.

After the call to new Bar(1, 5), the value of o1.b will be 4. The value of o1.m2 will be that function, but it doesn't matter; that's a red herring.
After the call to new Foo(2, 3):
Bar.prototype.a will be 5
Bar.prototype.b will be -1 (and this will never matter)
Bar.prototype.m1 will be undefined (won't matter)
Bar.prototype.m2 will be a function that's effectively:
function() {
return this.a * 2 + this.b * 3;
}
The a and b (as distinct from this.a and this.b) are "frozen in time" in that function, and they'll never be anything other than 2 and 3.
After the call to new Foo(3, 2):
Bar.prototype.a will be 5
Bar.prototype.b will be 1 (won't matter)
Bar.prototype.m1 will be that "m2" function above
Bar.prototype.m2 will be that same function, except with the local a being 3 and b being 2 (won't matter)
So when o1.m1() is called, we're running a function that's going to be working with the following values:
this.a will be 5, because that's the most recently set value of the Bar prototype property "a"
this.b will be 4, because that's the value of the "b" property on the instance of Bar created in the first step, and instance properties shadow prototype properties
Thus in the function
function() {
return this.a * 2 + this.b * 3;
}
given those values we've got 5 * 2 + 4 * 3 and that's 22.

The question investigates multiple behaviors of JavaScript:
local properties of an object shadow inherited properties, rendering values held in the prototype chain inaccessible,
Closures created by nested functions use outer function variable and parameter values that were in place when the inner function was created: the lexical record chain of nested functions is different for each call to an outer function that creates them (the inner function).
the behavior and value of this inside functions.
var Bar = function(a, b) {
this.b = b - a;
this.m2 = function() {
return this.a / b;
}
}
// every Bar object has a local property b, and method m2
// these are not inherited
// Bar.prototype values for b and m2 will be ignored
var Foo = function(a, b) {
this.a = a;
this.b = b;
Bar.prototype.a = a + b;
Bar.prototype.b = a - b;
Bar.prototype.m1 = Bar.prototype.m2;
Bar.prototype.m2 = function() {
return this.a * a + this.b * b;
}
}
// Foo is (nonsense) code that sets Foo object properties a and b
// These are not used by Bar object methods where "this" refers to the Bar object.
// Setting Bar.prototype.b has no affect as discussed under Bar.
// Although Bar.prototype.m2 is never inherited by Bar objects, it is
// a valid place to store a function value. Initially it is undefined.
// After calling Foo once, Bar.prototype.m1 is undefined.
// After calling Foo twice, Bar.prototype.m1 is
//
// function() { return this.a * a + this.b * b}
//
// Where this.a was calculated in the most recent call to Foo,
// set on Bar.prototype, and inherited by Bar objects,
// this.b is a local property of the Bar object, and
// a and b are the parameter values of the call to Foo which created
// the anonymous function object currently stored in Bar.prototype.m1.
o1 = new Bar(1, 5);
// at this point o1.b is set to 4 and does not change
// o1.a is not in the inheritance chain and is undefined
//
o2 = new Foo(2, 3);
// at this point o1.a is inherited as 5 and o1.m1 is undefined
o4 = new Foo(3, 2);
// at this point o1.a is again inherited as 5 (the sum of 3+2)
// and o1.m1 is defined
r1 = o1.m1();
// uses o1.a=5, o1.b=4 and the values of parameter variables a and b
// held in the closure created by the nested m2 function inside Foo.
//
// the method function is shuffled down before arriving at Bar.prototype.m1,
// where it captures the a and b parameters of the second to last call to Foo,
// which in this example is a=2, b=3
// So the expected value of o1.m1() is
// o1.a * a + o1.b * b
// = 5 * 2 + 4 * 3
// = 22
console.log(r1)
console.log(o1.a)
console.log(o1.b)

Related

stoyanov javascript prototype exercises from object oriented javascript

Although I have some working experience with jQuery and JavaScript I still find it difficult to understand prototypal inheritance. Hence I have started reading Stoyan Stefanov's book entitled "Object Oriented JavaScript". However I ran into problems while solving the following exercises from the book:
Create an object called shape that has a type property and a getType method.
Define a Triangle constructor function whose prototype is shape. Objects created with Triangle should have three own properties: a, b and c representing the sides of a triangle.
Add a new method to the prototype called getPerimeter.
Test your implementation with this code:
var t = new Triangle(1, 2, 3);
t.constructor; // Triangle(a, b, c)
shape.isPrototypeOf(t); // true
t.getPerimeter(); // 6
t.getType(); // "triangle"
I have tried to solve this problem with the following code:
shape = {
type : "",
getType: function(){
return this.type;
}
};
function Triangle(a, b, c) {
}
Triangle.prototype = shape;
However it does not seem to work as expected. How would you solve this problem? Please explain it in detail. I would really like to understand prototypal inheritance.
You don't do anything with the params passed to the constructor function, probably assuming that they are just assigned to the newly-created object. The problem is, they aren't.
You should write something like this...
var shape = {
type: '',
getType: function() { return this.type; }
};
function Triangle(a, b, c) {
this.type = 'triangle';
this.a = a;
this.b = b;
this.c = c;
}
Triangle.prototype = shape;
Triangle.prototype.getPerimeter = function() {
return this.a + this.b + this.c;
};
Triangle.prototype.constructor = Triangle;
The point (why constructor is defined for prototype) is very simple: each Triangle object should know about its constructor function, but this property will be the same for each instance of Triangle. That's why it's placed it on Triangle.prototype instead.
Something like this will work:
function Shape() {
this.type = "shape";
this.getType = function(){
return this.type;
}
}
function Triangle(a,b,c){
this.type="triangle";
this.a =a;
this.b = b;
this.c = c;
}
var shape = new Shape(); //follow the requirements a bit more literally :)
Triangle.prototype = shape;
Triangle.prototype.getPerimeter = function() {
return this.a + this.b + this.c;
}
jsfiddle example: http://jsfiddle.net/TbR6q/1
Tangentially, this is an area where coffeescript is very nice and allows you to be much more clear/concise. This is the equivalent in Coffeescript.
class Shape
constructor: ->
#type = "shape"
getType : -> #type
class Triangle extends Shape
constructor: (#a,#b,#c) ->
#type="triangle"
getPerimeter: () -> #a + #b + #c
http://jsfiddle.net/qGtmX/
You're on the right track. Your code is correct. You only need to add a few more lines of code:
shape = {
type : "",
getType: function () {
return this.type;
}
};
function Triangle(a, b, c) {
this.type = "triangle";
this.a = a;
this.b = b;
this.c = c;
}
Triangle.prototype = shape;
shape.getPerimeter = function () {
return this.a + this.b + this.c;
};
To understand what's happening I suggest you read the following answers:
Object Inheritance in JavaScript
What are the downsides of defining functions on prototype this way?
JavaScript inheritance and the constructor property
For the sake of learning I would make it like this
function Shape(){
this.type = 'Shape';
this.getType = function()
{
return this.type;
}
}
var shape = new Shape();
function Triangle(a, b ,c)
{
this.type = 'triangle';
this.arguments = arguments;
}
Triangle.prototype = shape;
var triangle = new Triangle(1, 2, 3);
triangle.getType();
Triangle.prototype.getParimeter = function()
{
var perimeter = 0;
for(i = 0; i < this.arguments.length; i++){
perimeter = perimeter + this.arguments[i];
}
return perimeter;
}
console.log(triangle.getParimeter());
This is one solution (explanations on comments):
shape = {
type : "",
getType: function(){
return this.type;
}
};
function Triangle(a,b,c){
//This three variables are defined inside a closure, so in this case
//only the getPermiter function can access them
var A = a, B = b, C = c;
//The new Triangle object is crafted in the lines below as usual
this.type = "triangle";
this.getPerimeter = function(){
return A + B + C;
}
}
//Here we set the triangle prototype to point the shape object.
//So every time we call the Triangle function with the "new" operator
//the __proto__ internal property of the newly created object will be
//the shape object.
Triangle.prototype = Object.create(shape);
//The problem is that the shape object doesn't have a constructor property,
//so the shape constructor is shape.__proto__.constructor, which is the
//Object function.
//All this means that when we create a new object with the Triangle function the
//constructor property will be the Object function (shape.__proto__.constructor).
//To avoid this we must manually set the constructor to be Triangle.
Triangle.prototype.constructor = Triangle;
var t = new Triangle(1, 2, 3);
console.log(t.constructor === Triangle);
console.log(shape.isPrototypeOf(t) === true);
console.log(t.getPerimeter() === 6);
console.log(t.getType() === "triangle");

Two operation in one function

function test(a, b){
a = a + 2;
b = b + 5;
}
var a = 1;
var b = 2;
test(a, b);
console.log(a);
console.log(b);
This return 1 and 2, but i would like 3 and 7.
Is possible to make two operation in one function? This working if i use return, but how to use return to two operation?
live: http://jsfiddle.net/anCq6/
The reason you are getting 1 and 2 instead of 3 and 7 is because there are two different a and b variables. There's the a and b you declared outside the function, and there is the a and b which represent the values you passed into the function. (Basically, the parameters declared in the function's parentheses are newly declared variables.)
If you want to change the external a and b, change your test function to the following:
function test(x, y) {
a = x + 2;
b = y + 5;
}
Or, alternatively, don't pass a reference into the function, so that the a and b in the inner scope refer to the same a and b as the outer scope:
function test() {
a = a + 2;
b = b + 5;
}
Just send it back as an object...
function test(a, b){
a = a + 2;
b = b + 5;
return {a:a,b:b};
}
var a = 1;
var b = 2;
var test = test(a, b);
alert(test.a);
alert(test.b);
DEMO HERE
This doesn't work because since numbers are passed by value and not by reference, you're modifying the local copies of those variables, however the ones in the outer scope remain unmodified.
If you remove the a and b parameters from your function, you'll get the behavior that you want since the a and b parameters that are being modified will be the ones in the outer scope.
What are references?
Here's a pretty decent answer - Javascript by reference vs. by value
In short, only objects and arrays are passed by reference. Although in reality it's more complex than this depending on how functions are defined and syntax, at this point you can assume that anything that's defined by calling new or the syntactic shorthands [] ( array ) and {} ( object ) are passed by reference. Other types like numbers and strings are passed by value.
Another solution: because of how variable scope works in JavaScript, you can just remove the parameters of "test" function and it will work.
function test(){
a = a + 2;
b = b + 5;
}
function test(){
a = a + 2;
b = b + 5;
}
var a = 1;
var b = 2;
test();
console.log(a);
console.log(b);

javascript - where should I put "var" in order to get specifc values

That's a code fragment task - you should enter "var" (as many as want) in it in order to get 17 in the first, and 21 in the second alert. I thing that I have met this before, but still was not able to solve the issue.
a = 3;
b = 2;
function line(x) {
a = 5;
b = 4;
return a*x + b
}
//b should be 17
b = line( a ) - b;
alert( b );
//c should be 21
c = line ( a ) + b;
alert(c);
If you put "var" in the function in front of b, it will alert "17". The next alert gives us 46 because of the new value of b, return by the function.
function line(x) {
a = 5;
var b = 4;
return a*x + b
}
That's the source of the task:
http://www.codecademy.com/courses/javascript-for-jquery/1?curriculum_id=4fc3018f74258b0003001f0f/#!/exercises/3
Using exactly what's given, in exactly the way it's given is impossible.
What I mean by that is if the call:
c = line(a) + b;
is dependent upon the value of b which is the assignment at:
b = line(a) - b;
Then it's 100% impossible to either have made a a significantly-small number, or made b a significantly-large negative number to make the math work.
Therefore it's my belief that they're intended to be two separate checks.
Best-case scenario, if we're trying to have b=17 included:
a = 3;
3 * 5 = 15 + 4 = 19 + 4 = 23;
That's the smallest you're going to get, assuming you run the two back-to-back.
Even if you did it that way, you wouldn't get b = line(a) - b = 17 on the first run...
If it was written:
c = line(a) - b;
d = line(a) + b;
Then you could run both in succession and get the expected result.
Or you can run:
var a = 3,
b = 2;
function line (x) {
var a = 5,
b = 4;
return a*x + b;
}
b = line(a) - b;
and get 17.
Then you can run:
var a = 3,
b = 2;
function line (x) {
var a = 5,
b = 4;
return a*x + b;
}
c = line(a) + b;
(ie: the exact same setup with a different instigator, and without the saved b value from the return of the previous call), and get the desired result.
But it's not possible to run both of them one after the other, and expect to have them both work, without doing anything to the code but add a var or four.
Keep your function like this, if you want to maintain consisitency. Using "var" before a and b will make them local to the function block and that call. Otherwise they will refer to the global variable.
function line(x) {
var a = 5;
var b = 4;
return a*x + b
}

Why can I not successively increment a variable within a function?

I'm trying to add 10 over and over for every invocation of d. It stays 20 every time, why?
function d() {
var c = [10];
c[0] += 10;
alert(c[0]); // always 20
}
d(); d(); d(); // supposed to be 20, 30, 40...
You create a new array and assign it to c each time the function is called. That resets it.
Move the assignment so it is outside the function (so it only runs once).
var c = [10];
function d() {
c[0] += 10;
alert(c[0]);
}
d(); d(); d(); // will be 20, 30, 40...
But globals are good source of bugs, so it is considered good style to wrap such things in closures to minimise the use of globals.
var d =(function () {
var c = [10];
function d() {
c[0] += 10;
alert(c[0]);
};
return d;
})();
d(); d(); d();
#Quentin already explained the reason for your problem and provided a solution. For more information about variable scope, have a look at the MDN JavaScript Guide.
As an alternative, you can assign the value to a property of the function:
function d() {
var c = d.c || (d.c = [0]); // initialize property if not set
c[0] += 10;
alert(c[0]);
}
What you have is local variable. Which gets initialized to 10 every time you invoke the function.
Try using global variable as
var c = [10];
function d() { c[0] += 10; alert(c[0]); // always 20 }
Why not just
var c = 10;
function d(){
c+=10;
alert(c);
}
d();d();d();

Javascript chain rule, return specific value instead of [Object object] [x]

The question is at the title, but first please look at this code:
function number(a) {
return {
add: function(b) {
result = a + b;
return this;
}, substract(b) {
result = a - b;
return this;
}
}
These code above are simple example of chain rule. I retun an object so I can do it continuously:
number(2).add(5).add(3 * 12).substract(Math.random());
My problem is, I have to retun an object to keep the function chainable. I'd like to immitate the chain rule, but to return specific value. For instance number(2).add(3) would return 5.
Any suggestion is highly appreciated.
Thanks everyone in advanced.
[x]
One way to make a numeric value like 5 "chainable" is to define a method on the appropriate prototype object, such as Number.prototype. For instance:
Number.prototype.add = function (n) {
return this + n
}
(5).add(2) // 7
5.0.add(2) // 7
5..add(2) // 7
((5).add(2) + 1).add(34) // okay! 42
The syntax above is funny because 5.add(2) is invalid: JavaScript is expecting a number (or "nothing") after 5.. Because this is a global side-effect (it will affect all numbers), care should be taken to avoid unexpected interactions.
The only other Another way to make "5" chain-able is to create a new Number object (5 is not a real Number instance, even though it uses Number.prototype!) and then copy over required methods. (I used to think this was the only other way, but see KooiInc's answer -- however, I am not sure how well-defined returning a non-string from toString is.)
function ops(a) {
return {
add: function(b) {
var res = new Number(a + b) // important!
var op = ops(res)
res.add = op.add // copy over singletons
return res
}
}
}
function number(a) {
return ops(a)
}
number(5).add(2) + 1 // 8
(number(5).add(2) + 1).add(34) // error! add is not a function
However, keep in mind this introduces subtle issues:
typeof 5 // number
typeof new Number(5) // object
5 instanceof Number // false
new Number(5) instanceof Number // true
And this is why we need a Number (search SO for "primitives" in JavaScript):
x = 5
x.foo = "bar"
x.foo // undefined
Furthermore, in conjunction with cwolves' answer, consider:
function number (n) {
if (this === window) { // or perhaps !(this instanceof number)
return new number(n)
} else {
this.value = n
}
}
Then both new number(2) and both number(2) will evaluate to a new number object.
number(2).value // 2
new number(2).value // 2
number(2) instanceof number // true
new number(2) instanceof number // true
Happy coding.
You have two options. You can return new objects:
function number(a){
return this instanceof number ? (this.value = a, this) : new number(a);
}
number.prototype = {
valueOf : function(){
return this.value;
},
add : function(b){
return new number(this.val + b);
},
subtract : function(b){
return new number(this.val - b);
}
};
or you can modify the existing one (mostly the same code as above, this is different):
add : function(b){
this.value += b;
return this;
},
The difference is in how they act:
var x = new number(5),
y = x.add(10);
// with first example
// x == 5, y == 15
// with 2nd example
// x == 15, y == 15, x === y
If you define the value as property (this.a) and use toString within the returned Object, you can chain the methods:
function number(a) {
return {
a: Number(a) || 0, //if not a, or a===NaN, default = 0
add: function(b) {
this.a += b;
return this;
},
subtract: function(b){
this.a -= b;
return this;
},
valueOf: function(){
return Number(this.a);
},
toString: this.valueOf
}
}
var n = number(5);
alert(number.add(5).add(2).subtract(2)); //=> 10
alert(number.add(0.5)); //=> 10.5
alert(number(2).add(5).add(3 * 12).subtract(Math.random());
//=> 42.36072297706966

Categories

Resources