I'm studying a javascript book, and i have this example
var p = {
// x and y are regular read-write data properties. x: 1.0,
y: 1.0,
// r is a read-write accessor property with getter and setter. // Don't forget to put a comma after accessor methods.
get r() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}, set r(newvalue) {
var oldvalue = Math.sqrt(this.x * this.x + this.y * this.y);
var ratio = newvalue / oldvalue;
this.x *= ratio;
this.y *= ratio;
},
// theta is a read-only accessor property with getter only.
get theta() {
return Math.atan2(this.y, this.x);
} };
var q = inherit(p); // Create a new object that inherits getters and setters
q.x = 0; q.y = 0; // Create q's own data properties
console.log(q.r); // And use the inherited accessor properties console.log(q.theta);
But I have this error Uncaught ReferenceError: inherit is not defined
Looking up this code on internet suggests you might be reading O'Reilly's 'JavaScript: the Definitive Guide'. If so, the code for inherit() is given in example 6-1:
See here: https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-6/creating-a-new-object-that
To add to Mchl's answer (I had the same problem, but couldn't follow the link in his answer), the following is the code for the inherit function as in Javascript The Definitive Guide's example 6.1:
// inherit() returns a newly created object that inherits properties from the
// prototype object p. It uses the ECMAScript 5 function Object.create() if
// it is defined, and otherwise falls back to an older technique.
function inherit(p) {
if (p == null) throw TypeError(); // p must be a non-null object
if (Object.create) // If Object.create() is defined...
return Object.create(p); // then just use it.
var t = typeof p; // Otherwise do some more type checking
if (t !== "object" && t !== "function") throw TypeError();
function f() {}; // Define a dummy constructor function.
f.prototype = p; // Set its prototype property to p.
return new f(); // Use f() to create an "heir" of p.
Straight to the point, you've missed the code on page 119 (see references at the end), on which inherit function is defined. It seems that you are treating 'inherit' function as a "native function" and it is not. So as has been said, you need to "construct" that function before inicialization - so you don't get Uncaught ReferenceError: inherit is not defined.
That error is telling you the clue: "inherit is not defined", so the first step is to look up where is this function defined. If it is not defined yet and you want to use it, you just need to define it as suggested bellow or with the specific instructions you need to play. If you're learning, it is very important to understand what erros are teeling you.
So, before calling 'inherit' function add the following code as suggested by the book:
// inherit() returns a newly created object that inherits properties from the
// prototype object p. It uses the ECMAScript 5 function Object.create() if
// it is defined, and otherwise falls back to an older technique.
function inherit(p) {
if (p == null) throw TypeError(); // p must be a non-null object
if (Object.create) // If Object.create() is defined...
return Object.create(p); // then just use it.
var t = typeof p; // Otherwise do some more type checking
if (t !== "object" && t !== "function") throw TypeError();
function f() {}; // Define a dummy constructor function.
f.prototype = p; // Set its prototype property to p.
return new f(); // Use f() to create an "heir" of p.
}
Example 6-1. Creating a new object that inherits from a prototype. JavaScript: The Definitive Guide, by David Flanagan (O'Reilly). Copyright 2011 David Flanagan, 978-0-596-80552-4. 6th Edition.
Related
Today I was reading the MDN documentation on Function.prototype.bind(). Under the section Bound functions used as constructors there is an example that I cannot quite understand.
I ran the following piece of code both in Node.js (v.4.4.5) and Google Chrome ( v58.0.3029.81)
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return this.x + ',' + this.y;
};
var p = new Point(1, 2);
p.toString(); // '1,2'
var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 1/*x*/);
var axisPoint = new YAxisPoint(5);
console.log(axisPoint.toString()); // '1,5'
console.log(axisPoint instanceof Point); // true
console.log(axisPoint instanceof YAxisPoint); // true
console.log(new Point(17, 42) instanceof YAxisPoint); // true
I can clearly see why axisPoint is an instance of both Point and YAxisPoint. But how in the world can new Point(17,42) be an instance of YAxisPoint?
But how in the world can new Point(17,42) be an instance of YAxisPoint?
Because instanceof works special with bound functions (those created from .bind() calls). Usually it would check whether the object inherits from the constructors .prototype, but bound functions don't have a .prototype. Instead, when you use instanceof on a bound function, it checks whether the object is an instance of the target function (that bind() was called upon). So
… instanceof YAxisPoint
is exactly equivalent to
… instanceof Point
You can check this in the specs (ES5, ES6).
This article defines instanceof as below:
The instanceof operator tests whether an object has in its prototype
chain the prototype property of a constructor.
That's a fair explanation and life was good until I came across this code from the book Eloquent Javascript:
function TextCell(text) {
this.text = text.split("\n");
}
TextCell.prototype.minWidth = function() {
return this.text.reduce(function(width, line) {
return Math.max(width, line.length);
}, 0);
}
TextCell.prototype.minHeight = function() {
return this.text.length;
}
TextCell.prototype.draw = function(width, height) {
var result = [];
for (var i = 0; i < height; i++) {
var line = this.text[i] || "";
result.push(line + repeat(" ", width - line.length));
}
return result;
}
function RTextCell(text) {
TextCell.call(this, text);
}
RTextCell.prototype = Object.create(TextCell.prototype);
RTextCell.prototype.draw = function(width, height) {
var result = [];
for (var i = 0; i < height; i++) {
var line = this.text[i] || "";
result.push(repeat(" ", width - line.length) + line);
}
return result;
};
Let's create an instance of RTextCell and execute the below c
var rt = new RTextCell("ABC");
console.log(rt instanceof RTextCell); // true
console.log(rt instanceof TextCell); // true
I understand why the output of the 2nd console.log is "true" - because constructor TextCell is part of the prototype chain.
However the 1st console.log confuses me.
If you look at the code (10th line from bottom), the prototype of RTextCell is updated to a new Object, whose prototype is set to TextCell.prototype.
RTextCell.prototype = Object.create(TextCell.prototype);.
Looking at the snapshots below, there is no mention of constructor "RTextCell" in the prototype chain of the object "rt". So, going by the definition which I mentioned at the beginning of my post, shouldn't the output be false? Why does it returns a true value?
I also read this but didn't help me to understand this specific problem.
See below for the snapshots of rt, RTextCell, TextCell in that order.
You do change RTextCell.prototype, but you change it before you construct any RTextCell instances. Consider this massively different example, where RTextCell.prototype is modified after an instance is created with the original prototype:
var rt = new RTextCell();
RTextCell.prototype = somethingTotallyDifferent;
rt instanceof RTextCell; // false!
When rt is created, it is true that rt.__proto__ === RTextCell.prototype. Once RTextCell.prototype changes, that stops being true.
You're not testing if rt has the original prototype property from RTextCell in its prototype chain. Rather, you're testing if the value of RTextCell.prototype right now exists in the object's prototype chain. That will always be true for RTextCell instances, because instances created by the RTextCell constructor always get the current value of RTextCell.prototype in their prototype chain, and you never change RTextCell.prototype after you start constructing instances.
The exact wording is important. You talk about the constructor being in the prototype chain, but the original quote doesn't:
The instanceof operator tests whether an object has in its prototype
chain the prototype property of a constructor.
So the expression rt instanceof RTextCell actually is testing something like this (keeping in mind that __proto__ is not standard):
var p = rt.__proto__;
while(p)
{
if(p == RTextCell.prototype)
return true;
p = p.__proto__;
}
return false;
So even though the function RTextCell is not referenced directly in the object trees above, the RTextCell.prototype object is.
obj instanceof RTextCell
is testing whether RTextCell.prototype is present in the prototype chain of obj. It is since obj was made using new RTextCell. The fact that RTextCell.prototype has as it's prototype TextCell.prototype is beside the point here and seems to be throwing you.
RTextCell.prototype = Object.create(TextCell.prototype);
doesn't get rid of RTextCell.prototype, it's still an object, but it's prototype happens to be TextCell.prototype.
This seems strange to me. I have
var j = "x";
var k = "y";
function fun1 ( a, b) {
var j = a;
var k = b;
console.log("this.j is:", this.j);
console.log("this.k is:", this.k);
this.j = a;
this.k = b;
return this.j + this.k;
};
console.log("j is ", j);
console.log("k is ", k);
console.log("fun1(3,4) is ", fun1(3,4));
console.log("j is ", j);
console.log("k is ", k);
console.log("fun1(2,7) is ", fun1(2,7));
console.log("j is ", j);
console.log("k is ", k);
When I run this in Node.js, I get:
j is x
k is y
this.j is: undefined
this.k is: undefined
fun1(3,4) is 7
j is x
k is y
this.j is: 3
this.k is: 4
fun1(2,7) is 9
j is x
k is y
Why aren't j and k being set to arguments a and b in the function when they are declared? It just doesn't seem right that I have to do BOTH var j = a; AND this.j = a; !! What am I doing wrong?
In node, the output properly shows that the j and k variables in global are not being clobbered by the local variables j and k in fun1. When I run this in Chrome or Firefox, the global variables DO GET clobbered. In other words I get
j is x
k is y
this.j is: undefined
this.k is: undefined
fun1(3,4) is 7
j is 3
k is 4
this.j is: 3
this.k is: 4
fun1(2,7) is 9
j is 2
k is 7
Why isn't the local scope protecting the global var?
Thanks for any hints.
I recommend you to go read that! :) That explain precisely how to use this and what is the this!
Read here! Mozilla Developper Network
Here is the article if the link is dead. (Sorry, the formating is not perfect and the text is very long.)
Summary
A function's this keyword behaves a little differently in JavaScript
compared to other languages. It also has some differences between
strict mode and non-strict mode.
In most cases, the value of this is determined by how a function is
called. It can't be set by assignment during execution, and it may be
different each time the function is called. ES5 introduced the bind
method to set the value of a function's this regardless of how it's
called.
Syntax this Global context In the global execution context (outside of
any function), this refers to the global object, whether in strict
mode or not.
console.log(this.document === document); // true
// In web browsers, the window object is also the global object:
console.log(this === window); // true
this.a = 37; console.log(window.a); // 37 Function context Inside a
function, the value of this depends on how the function is called.
Simple call
function f1(){ return this; }
f1() === window; // global object In this case, the value of this is
not set by the call. Since the code is not in strict mode, the value
of this must always be an object so it defaults to the global object.
function f2(){ "use strict"; // see strict mode return this; }
f2() === undefined;
In strict mode, the value of this remains at
whatever it's set to when entering the execution context. If it's not
defined, it remains undefined. It can also be set to any value, such
as null or 42 or "I am not this".
Note: In the second example, this should be undefined, because f2 was
called without providing any base (e.g. window.f2()). This feature
wasn't implemented in some browsers when they first started to support
strict mode. As a result, they incorrectly returned the window object.
As an object method
When a function is called as a method of an object, its this is set to
the object the method is called on.
In the following example, when o.f() is invoked, inside the function
this is bound to the o object.
var o = { prop: 37, f: function() {
return this.prop; } };
console.log(o.f()); // logs 37 Note that this behavior is not at all
affected by how or where the function was defined. In the previous
example, we defined the function inline as the f member during the
definition of o. However, we could have just as easily defined the
function first and later attached it to o.f. Doing so results in the
same behavior:
var o = {prop: 37};
function independent() { return this.prop; }
o.f = independent;
console.log(o.f()); // logs 37 This demonstrates that it matters only
that the function was invoked from the f member of o.
Similarly, the this binding is only affected by the most immediate
member reference. In the following example, when we invoke the
function, we call it as a method g of the object o.b. This time during
execution, this inside the function will refer to o.b. The fact that
the object is itself a member of o has no consequence; the most
immediate reference is all that matters.
o.b = {g: independent, prop: 42}; console.log(o.b.g()); // logs 42
this on the object's prototype chain
The same notion holds true for methods defined somewhere on the
object's prototype chain. If the method is on an object's prototype
chain, this refers to the object the method was called on, as if the
method was on the object.
var o = {f:function(){ return this.a + this.b; }}; var p =
Object.create(o); p.a = 1; p.b = 4;
console.log(p.f()); // 5 In this example, the object assigned to the
variable p doesn't have its own f property, it inherits it from its
prototype. But it doesn't matter that the lookup for f eventually
finds a member with that name on o; the lookup began as a reference to
p.f, so this inside the function takes the value of the object
referred to as p. That is, since f is called as a method of p, its
this refers to p. This is an interesting feature of JavaScript's
prototype inheritance.
this with a getter or setter
Again, the same notion holds true when a function is invoked from a
getter or a setter. A function used as getter or setter has its this
bound to the object from which the property is being set or gotten.
function modulus(){ return Math.sqrt(this.re * this.re + this.im *
this.im); }
var o = { re: 1, im: -1, get phase(){
return Math.atan2(this.im, this.re); } };
Object.defineProperty(o, 'modulus', {
get: modulus, enumerable:true, configurable:true});
console.log(o.phase, o.modulus); // logs -0.78 1.4142 As a constructor
When a function is used as a constructor (with the new keyword), its
this is bound to new object being constructed.
Note: while the default for a constructor is to return the object
referenced by this, it can instead return some other object (if the
return value isn't an object, then the this object is returned).
/* * Constructors work like this: * * function MyConstructor(){ *
// Actual function body code goes here. * // Create properties on
|this| as * // desired by assigning to them. E.g., * this.fum =
"nom"; * // et cetera... * * // If the function has a return
statement that * // returns an object, that object will be the *
// result of the |new| expression. Otherwise, * // the result of
the expression is the object * // currently bound to |this| * //
(i.e., the common case most usually seen). * } */
function C(){ this.a = 37; }
var o = new C(); console.log(o.a); // logs 37
function C2(){ this.a = 37; return {a:38}; }
o = new C2(); console.log(o.a); // logs 38 In the last example (C2),
because an object was returned during construction, the new object
that this was bound to simply gets discarded. (This essentially makes
the statement "this.a = 37;" dead code. It's not exactly dead, because
it gets executed, but it can be eliminated with no outside effects.)
call and apply
Where a function uses the this keyword in its body, its value can be
bound to a particular object in the call using the call or apply
methods that all functions inherit from Function.prototype.
function add(c, d){ return this.a + this.b + c + d; }
var o = {a:1, b:3};
// The first parameter is the object to use as // 'this', subsequent
parameters are passed as // arguments in the function call
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// The first parameter is the object to use as // 'this', the second
is an array whose // members are used as the arguments in the function
call add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 Note that with
call and apply, if the value passed as this is not an object, an
attempt will be made to convert it to an object using the internal
ToObject operation. So if the value passed is a primitive like 7 or
'foo', it will be converted to an Object using the related
constructor, so the primitive number 7 is converted to an object as if
by new Number(7) and the string 'foo' to an object as if by new
String('foo'), e.g.
function bar() { console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number] The bind method
ECMAScript 5 introduced Function.prototype.bind. Calling
f.bind(someObject) creates a new function with the same body and scope
as f, but where this occurs in the original function, in the new
function it is permanently bound to the first argument of bind,
regardless of how the function is being used.
function f(){ return this.a; }
var g = f.bind({a:"azerty"}); console.log(g()); // azerty
var o = {a:37, f:f, g:g}; console.log(o.f(), o.g()); // 37, azerty As
a DOM event handler
When a function is used as an event handler, its this is set to the
element the event fired from (some browsers do not follow this
convention for listeners added dynamically with methods other than
addEventListener).
// When called as a listener, turns the related element blue function
bluify(e){ // Always true console.log(this === e.currentTarget);
// true when currentTarget and target are the same object
console.log(this === e.target); this.style.backgroundColor =
'#A5D9F3'; }
// Get a list of every element in the document var elements =
document.getElementsByTagName('*');
// Add bluify as a click listener so when the // element is clicked
on, it turns blue for(var i=0 ; i
elements[i].addEventListener('click', bluify, false); } In an in–line
event handler
When code is called from an in–line handler, its this is set to the
DOM element on which the listener is placed:
Show this
The above alert shows button. Note however that only the
outer code has its this set this way:
Show inner
this In this case, the inner function's this isn't set so it
returns the global/window object (i.e. the default object in
non–strict mode where this isn't set by the call).
Consider the following code:
var f = function() { return 10; }
typeof f; // returns "function"
f(); // returns 10
var g = f;
g(); // returns 10, obviously
var h = new f;
h; // console evaluates to f - ????
h(); // Type error - called_non_callable
typeof h; // returns "object"
So, what is h here? The Chrome console seems to evaluate it as f, but it isn't callable. What does it mean to "new" a function like this? How is h now related to f?
As an aside, these two lines appear to be equivalent:
var h = new f;
var h = new f();
What's up with that?
The root of your confusion is the way that Chrome represents objects on its console.
The expression new f() in your example is represented as 'f' on the Chrome's console output, but just as a mere "convenience" of this particular console, for example, logging the following object:
({constructor: function Foo(){}});
Will show it represented as "Foo". Basically the console tries to find a representation of which constructor your object is instance of.
So, the console shows you f, but you are not logging the function, the new operator produces an object that inherits from f.prototype.
You are returning 10 from the function, but since you call it with new, and the return type is a primitive, the value is discarded, the newly created object that inherits form f.prototype is returned.
For example:
var F = function () { return 10; };
F.prototype.inherited = 'foo';
var h = new F(); // the 10 returned is ignored
h instanceof F; // true
h.inherited; // "foo"
On the other hand, if you return an object from a constructor, the object instance that the new operator creates behind the scened (and inherits from the constructor's prototype) will be lost, for example:
var F = function () { return {}; };
F.prototype.inherited = 'foo';
var h = new F(); // the empty object is returned
h instanceof F; // false
h.inherited; // undefined
Yes, new f; and new f(); are completely equivalent, although people recommend using the parentheses to add clarity to your code.
this is how object-orientation in JavaScript works. if you call new on a function, this function would be treated as if it's a constructor of a class (the keywords class to define a class like other languages do doesn't exist in js).
so calling var h = new f(); makes h an object of class f, and an object itself isn't callable (that's why you get called_non_callable).
if you want to give your "class" some methots, you should do it like this:
function cat(name) {
this.name = name;
this.talk = function() {
alert( this.name + " says meeow!" )
}
}
cat1 = new cat("felix")
cat1.talk() //alerts "felix says meeow!"
cat2 = new cat("ginger")
cat2.talk() //alerts "ginger says meeow!"
that's an example from page 2 of this tutorial. for more information, read that or ask Google for object-orientation in JavaScript.
I'd recommend reading https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/this, especially the section on "Function context".
In a nutshell, when you new function, you're creating a new object:
var h = new f;
This says: "Create a new object referenced by the variable named h of type f". The function is then treated as a constructor rather than what you're expecting.
Once the object has been created, it's no longer callable (which is why you're experiencing an error on the line h().
In most language (Javascript not excluded), the () of a constructor are optional (unless there are required parameters (in some languages)).
Basically, the new keyword calls f as the constructor of a new object. The first reply to this question, on StackOverflow, sums it up quite nicely:
What is the 'new' keyword in JavaScript?
In JavaScript, functions aren't just functions, and they're not just objects; they're also used to defined constructors for types.
Generally speaking, when you have a function f, that function defines a type, whether that was intended or not. So the line
var h = new f();
defines an object h whose type is f.
I've never seen the line
var h = new f;
but I'm assuming it does the same as the other line.
I've:
function Obj1(param)
{
this.test1 = param || 1;
}
function Obj2(param, par)
{
this.test2 = param;
}
now when I do:
Obj2.prototype = new Obj1(44);
var obj = new Obj2(55);
alert(obj.constructor)
I have:
function Obj1(param) {
this.test1 = param || 1;
}
but the constructor function has been Obj2... why that?
Obj1 has become the Obj2 prototype...
Can someone explain me, in detail, the prototype chain and the constructor property
Thanks
constructor is a regular property of the prototype object (with the DontEnum flag set so it doesn't show up in for..in loops). If you replace the prototype object, the constructor property will be replaced as well - see this explanation for further details.
You can work around the issue by manually setting Obj2.prototype.constructor = Obj2, but this way, the DontEnum flag won't be set.
Because of these issues, it isn't a good idea to rely on constructor for type checking: use instanceof or isPrototypeOf() instead.
Andrey Fedorov raised the question why new doesn't assign the constructor property to the instance object instead. I guess the reason for this is along the following lines:
All objects created from the same constructor function share the constructor property, and shared properties reside in the prototype.
The real problem is that JavaScript has no built-in support for inheritance hierarchies. There are several ways around the issue (yours is one of these), another one more 'in the spirit' of JavaScript would be the following:
function addOwnProperties(obj /*, ...*/) {
for(var i = 1; i < arguments.length; ++i) {
var current = arguments[i];
for(var prop in current) {
if(current.hasOwnProperty(prop))
obj[prop] = current[prop];
}
}
}
function Obj1(arg1) {
this.prop1 = arg1 || 1;
}
Obj1.prototype.method1 = function() {};
function Obj2(arg1, arg2) {
Obj1.call(this, arg1);
this.test2 = arg2 || 2;
}
addOwnProperties(Obj2.prototype, Obj1.prototype);
Obj2.prototype.method2 = function() {};
This makes multiple-inheritance trivial as well.
Check out Tom Trenka's OOP woth ECMAscript, the "Inheritance" page. Everything from the prototype is inherited, including the constructor property. Thus, we have to unbreak it ourselves:
Obj2.prototype = new Obj1(42);
Obj2.prototype.constructor = Obj2;
Short version: ‘constructor’ doesn't do what you think, and isn't cross-browser compatible. Never use it.
Long version: Convention for prototype inheritance in JavaScript
Generally: you're getting confused due to (a) the impedence mismatch between class-based and prototype-based OO, and (b) the strangeness of JavaScript's particular rather poor interpretation of prototype-based OO.
You'll probably be happier if you find one classes-in-prototypes implementation you like and stick with that. Many libraries have one. Here's an arbitrary one I use:
Function.prototype.subclass= function() {
var c= new Function(
'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+
'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); '
);
if (this!==Object)
c.prototype= new this(Function.prototype.subclass.FLAG);
return c;
}
Function.prototype.subclass.FLAG= new Object();
And here's an example of how one might use it:
// make a new class
var Employee= Object.subclass();
// add members to it
Employee.prototype._LEGS= 2;
Employee.prototype.getLegs= function() {
return this._LEGS;
};
// optional initialiser, takes arguments from constructor
Employee.prototype._init= function(name) {
this.name= name;
};
// make a subclass
Manager= Employee.subclass();
// extend subclass method
Manager.prototype._init= function(name, importance) {
// call base class's method
Employee.prototype._init.call(this, name);
this.importance= importance;
}
// all managers are well-known to have three legs
Manager.prototype._LEGS= 3;
// create one
var jake= new Manager('Jake the Peg', 100);
Well, the constructor property is a property like any other, on the prototype (property) of Obj1. If you understand how prototypes work, this might help:
>>> obj.hasOwnProperty("constructor")
false
// obj's [[Prototype]] is Obj2.prototype
>>> Obj2.prototype.hasOwnProperty("constructor")
false
// Obj2.prototype's [[Prototype]] is Obj1.prototype
>>> Obj1.prototype.hasOwnProperty("constructor")
true
// Oh?
>>> Obj1.prototype.constructor
Obj1()
Aha! So obj has no constructor, JS goes to get it up the [[Prototype]] chain, all the way from Obj1.prototype.constructor
I'm not sure why the constructor property isn't just set on an object when you use `new'. There might be a reason, or it might just be an oversight. Either way, I tend to avoid it.