In the functional inheritance pattern, Crockford introduces a new superior method via:
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function () {
return method.apply(that, arguments);
};
});
Where method is :
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Example:
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;
};
My question is Why don't just assign that.get_name to super_get_name ?
"My question is Why don't just assign that.get_name to super_get_name?"
Because the way the get_name method has its this value set to the that object is by invoking it as:
that.get_name();
When a function is invoked as the method of an object, the object becomes the value of this in that invocation of the function.
If you had done this instead:
var super_get_name = that.get_name;
super_get_name();
Now you're invoking a detached function, so it doesn't know what its this value should be, and so it uses the default, which is usually the window object.
I don't like the solution that crockford shows at all. Typically, in that situation, you'd simply make a new function right there instead of relying on extensions to Object.prototype to do it for you. (Extending Object.prototype is very ugly IMO.)
var coolcat = function (spec) {
var that = cat(spec),
_original_get_name = that.get_name,
super_get_name = function() {
return _original_get_name.apply(that, arguments);
};
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
Or in modern implementations, you'd use Function.prototype.bind to create a new function with its this value bound to whatever you provided as the first argument to .bind().
var coolcat = function (spec) {
var that = cat(spec),
super_get_name = that.get_name.bind(that);
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
In the sense of Crockford's Functional Inheritance Pattern it is completely valid to reference the base class method
var super_get_name = that.get_name;
This is how Crockford teaches it in his lecture JavaScript Master Class , see the part on Functional Inheritance.
Later - the method might be overriden by the derived class - you invoke it simply
super_get_name();
Crockford's superior method makes no sense in the Functional Inheritance Pattern.
Because in my opinion this is never needed in a method defined by a producer function. If you use this in your methods you'll run in all sorts of trouble because of dynamic scoping and manipulation of this:
function mammal(spec){
var that = {};
that.legs = Math.round(Math.random() * 4);
that.get_name = function(){
return spec.name + "with" + that.legs; // always use that not this
};
that.isProperThis = function(){
console.log( this === that );
};
return that;
};
var myMammal = mammal({name: 'Herb'});
myMammal.isProperThis(); // true
myMammal.isProperThis.call(window); // false
setTimeout(myMammal.isProperThis, 1); // false
If you insist on using this in your methods you can no longer treat them as "first-class" variables in JavaScript. Instead you have to convert them to "binders" by calling bind as described in the first answer in this post.
superior is a method defined in the prototype of the Object constructor function. It caches an object's method, so that it returns the original method even if it were changed later.
From JavaScript: The Good Parts, p.54:
The function will invoke the original method even if the property is changed.
The accepted answer given by cookie monster is correct, but I would like to add clarification.
As cookie monster says, if you write
var super_get_name = that.get_name;
invocation of super_get_name will no longer bind any value to this, making it an unbound function.
However, in the case of the example Crockford gives in The Good Parts, it would not matter if super_get_name were unbound by writing it in the way you propose, because this would never be used in its invocation.
You would essentially end up doing the following:
super_get_name = function () {
return that.says() + ' ' + spec.name +
' ' + that.says();
(where the right operand executes in the context of the function assigned to cat).
I assume that Crockford avoids unbound functions here to demonstrate a general principle, even though his specific example does not require binding.
Related
In the below code, which one is the right and how these two are different
Using call method
var obj = {
num: 10
};
var add = function(a) {
return this.num + a
}
console.log(add.call(obj,4))
Passing object in parameter
var obj = {
num: 10
};
var add = function(obj,a) {
return obj.num + a
}
console.log(add(obj,4))
Your second code block is just a regular function. The first one however is a bit more tricky. So the question is basically:
When to work with context in javascript?
In javascript, the term context basically means this. It is usually used when you call a method of an object, so that you can refer to the object. That's one of the core concepts of OOP, were we only define a function once inside the prototype, and every object of that class which inherits from it exposes this method, it won't work without context. So that's what this was invented for. However there are some cases, were context is useful without inheritance. E.g. Eventhandlers are usually contextless, as they are not part of any object:
window.addEventListener("load", function(evt){
const el = evt.target;
};
However as it is an Eventhandler of window, wouldn't it make sense that it is executed in the context of window? If you now say "YES", then you (will) probably love JS:
window.addEventListener("load", function(){
this.document.body.innerHTML = "Dynamic context can be cool!";
});
So in JS this is the way of refering to the object, the function refers to. Through Function.prototype.call we can make use of this everywhere. However that does not mean that we should use it everywhere. this should stay in the sense of context, as using it somewhere else will create confusion / uglify your code / make your code buggy.
var add = function(a) {
return this.num + a;
}
In your codesnippet i think its unclear what thisrefers to. So its rather a misuse of this. However it could get a meaning if you make it a method of obj, so its context becomes clear from the code:
const num = {
value:10,
add(a){ return this.value + a }
};
It gets even more beautiful if you use inheritance to make it reusable:
class CustomNumber {
constructor(n = 0){
this.value = n;
}
add(a){ return this.value + a; }
}
const num = new CustomNumber(10);
I declared the function:
function makePerson() {
this.first = 'John';
this.last = 'Oliver';
fullName = function(){
return this.first + this.last;
}
}
Did not instantiate it but called this function.
makePerson()
Now I am able to access first, last and fullName in global access.
Can someone explain me why it happens.
Note: Rather than calling, I instantiated it and checked. It is not in global and is accessible within function/class/object scope.
These are the normal semantics of the this keyword in a function. this may be evaluated in several ways, depending on how you call the function. Let's say we have the function f which body contains the this keyword :
In f(a,b) (standard function call syntax) this is bound to the global JavaScript Object, which means that if you add properties to this in the function body, you actually add them to global scope.
In anObject.f(a,b) (method call syntax), this is bound to anObject.
In new f(a,b) (constructor call syntax), this is bound to the object being constructed.
this can be a source of confusion, and as soon as a function body contains this, the function stops being first-class. For that reason, I recommend you to avoid using this as much as you can, as does Douglas Crockford.
If you want to make a factory function (which I strongly recommend for the reason above), you may do it that way :
function makePerson() {
var person = {
first: 'John',
last: 'Oliver'
};
person.fullName = function(){
return person.first + person.last;
};
return person;
}
If you still want to make a constructor, convention dictates that the name be capitalized :
function Person() {
this.first = 'John';
this.last = 'Oliver';
this.fullName = function(){
return this.first + this.last;
};
}
Finally, there can be good reasons to use the this keyword, and that is prototypical inheritance. However, I find the constructor syntax to be misleading in that regard. Fortunately, now we have Object.create:
var personPrototype = {
fullName: function () {
return this.first + this.last;
}
};
function makePerson(first,last) {
var person = Object.create(personPrototype);
person.first = first;
person.last = last;
return person;
}
As a last warning, here is an example of how using this can lead to unanticipated constraints and confusion :
var cn = makePerson("Chuck","Norris");
// works fine
console.log(cn.fullName());
// does not work, fullName is not a first-class function. You cannot detach it.
var fullName = cn.fullName;
console.log(fullName());
I have declared a prototype function A.a but would like to provide some syntactic sugar by other functions, e.g. A.sayHi and A.sayBye. The problem is binding the context because of course I'd like it to point to the instance but don't have access to it when I declare the prototype.
function A() {
this.txt = 'so';
};
A.prototype.a = function (txt) {
alert(txt + ' ' + this.txt);
}
A.prototype.sayHi = A.prototype.a.bind(A, 'hi');
A.prototype.sayBye = A.protoype.a.bind(A.prototype, 'bye');
When I do new A().sayHi().sayBye(); I get alerts with "hi undefined" and "bye undefined". Sure, I can do
A.prototype.sayHi = function() {
this.a('hi');
};
but that's ugly :)
Is there a way that I keep the context of the instance (so that this.txt equals 'so') without writing a function?
Bind is not what you want.
Bind is designed to create a function that wraps a this pointer (which must exist when Bind is called), to avoid having to write lots of temporary functions like
var that = this;
callMeBack(function() { that.callback(); });
(i.e. the above becomes)
callMeBack(this.callback.Bind(this));
It can be used for partial application / limited currying, but in your case you don't have a this at the point you're trying to call Bind. You definitely don't want either the constructor or its prototype object to be this, you want this to be the actual object, but that doesn't exist when you run this code.
Your last example is exactly right.
Digression: I don't think it is ugly - it is clear, and explicit, and highly idiomatic Javascript. Perhaps a touch verbose. If you think this is ugly, then you may not be used to Javascript yet. Get used to functions as first-class data, e.g.:
var A = function() { ... };
instead of
function A { ... }
the former being what Javascript means by the latter. Getting into the habit of thinking of functions as just another data-type, will help you 'get' Javascript and see its inherent beauty. And will have the side-effect that you won't be offended by the 'ugly' on show when you program for node.js :)
you can try little change a function
function A() {
this.txt = 'so';
};
A.prototype.a = function (txt) {
return function(){
alert(txt + ' ' + this.txt);
return this;
}
}
A.prototype.sayHi = A.prototype.a("Hi")
A.prototype.sayBye = A.protoype.a('bye');
Does this work for you?
function runtimeContextBinder(func){
var args = Array.prototype.slice.call(arguments, 1);
return function(){
func.apply(this,args);
}
}
function A() {
this.txt = 'so';
};
A.prototype.a = function (txt) {
alert(txt + ' ' + this.txt);
}
A.prototype.sayHi = runtimeContextBinder(A.prototype.a,'hi');
A.prototype.sayBye = runtimeContextBinder(A.prototype.a, 'bye');
What I'm doing here is to create a closure on the function, which is then executed in the context of the instance.
I am learning function currying in JavaScript by reading online and writing some simple code. I got following example in online article
function toArray(obj) {
return Array.prototype.slice.call(obj);
}
Function.prototype.curry = function() {
if (arguments.length<1) {
return this; //nothing to curry with - return function
}
var __method = this;
var args = toArray(arguments);
return function() {
return __method.apply(this, args.concat(toArray(arguments)));
}
}
var add = function(a,b) {
return a + b;
}
var addTen = add.curry(10); //create function that returns 10 + argument
alert(addTen(20)); //alerts 30 correctly
Then I tried to try it on the method of an instantiated function. So I tried following. But it gave me error "Unable to get property 'prototype' of undefined or null reference" on the second last line. I know this error is nothing to do with currying but I am messing up with some basics of JS functions concept. So where I am going wrong.
function Person()
{
this.age = 15;
}
Person.ageAfter = function (years) {
return this.age + years;
}
var personObj = new Person();
var ageAfterFiveYears = personObj.ageAfter.prototype.curry(5); //**Error**
alert(ageAfterFiveYears());
You have two issues:
The ageAfter function is not an instance method - you've added it to the "class" (i.e. it's kind of like a static method). It should be added to the prototype.
When you curry the function you lose your object's context, so you either need to rebind the context
e.g:
var ageAfterFiveYears = Person.prototype.ageAfter.curry(5).bind(personObj);
giving you a function that only works on the current instance, or better yet, as #Pointy suggests in the comments, you should just put the curried function back onto the prototype:
Person.prototype.ageAfterFiveYears = Person.prototype.ageAfter.curry(5);
which then adds the .ageAfterFiveYears method to every Person object.
You shouldn't include the prototype in your call:
var ageAfterFiveYears = personObj.ageAfter.curry(5);
The "ageAfter" property has a function for its value, so that function will have access to your "curry" function just like the function in your first example.
When you call it on the prototype, the value of this inside your function will be the prototype object, not the "ageAfter" function.
Also as a comment points out, you need to put "ageAfter" on the prototype:
Person.prototype.ageAfter = function(years) { ... }
edit — the binding issue that Alnitak points out is also important. (When I say "important", what I mean is "necessary to make your code work".)
Curry will not work for your use case. You need to bind the context so this is your personObj.
function Person() {
this.age = 15;
}
Person.prototype.ageAfter = function (years) {
return this.age + years;
}
var personObj = new Person();
var ageAfterFiveYears = personObj.ageAfter.bind(personObj, 5);
alert(ageAfterFiveYears());
I thought I understood the concept of the JavaScript prototype object, as well as [[proto]] until I saw a few posts regarding class inheritance.
Firstly, "JavaScript OOP - the smart way" at http://amix.dk/blog/viewEntry/19038
See the implementation section:
var parent = new this('no_init');
And also "Simple JavaScript Inheritance" on John Resig's great blog.
var prototype = new this();
What does new this(); actually mean?
This statement makes no sense to me because my understand has been that this points to an object and not a constructor function. I've also tried testing statements in Firebug to figure this one out and all I receive is syntax errors.
My head has gone off into a complete spin.
Could someone please explain this in detail?
In a javascript static function, you can call new this() like so,
var Class = function(){}; // constructor
Class.foo = function(){return this;} // will return the Class function which is also an object
Therefore,
Class.foo = function(){ return new this();} // Will invoke the global Class func as a constructor
This way you get a static factory method. The moral of the story is, not to forget functions are just like any other objects when you are not calling them.
What is confusing you, I think, is just where "this" is really coming from. So bear with me-- here is a very brief explanation that I hope will make it quite clear.
In JavaScript, what "this" refers to within a function is always determined at the time the function is called. When you do:
jimmy.nap();
The nap function (method) runs and receives jimmy as "this".
What objects have references to nap is irrelevant. For example:
var jimmy = {}, billy = {};
jimmy.nap = function(){ alert("zzz"); };
var jimmy_nap = jimmy.nap;
jimmy_nap(); // during this function's execution, this is *NOT* jimmy!
// it is the global object ("window" in browsers), which is given as the
// context ("this") to all functions which are not given another context.
billy.sleep = jimmy.nap;
billy.sleep(); // during this function's excution, this is billy, *NOT* jimmy
jimmy.nap(); //okay, this time, this is jimmy!
In other words, whenever you have:
var some_func = function(arg1, arg2){ /*....*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(2, 3);
other_obj.some_meth(2, 3);
What it's getting "translated" into (not literally-- this is pedagogical, not about how javascript interpreters actually work at all) is something like:
var some_func = function(this, arg1, arg2){ /* ...*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(obj, 2, 3);
other_obj.some_meth(other_obj, 2, 3);
So, notice how extend is used in the example on that page:
UniversityPerson = Person.extend({ /* ... */ });
Pop quiz: When extend runs, what does it think "this" refers to?
Answer: That's right. "Person".
So the puzzling code above really is the same as (in that particular case):
var prototype = new Person('no_init');
Not so mysterious anymore, eh? This is possible because unlike in some languages,
a JavaScript variable-- including "this"-- can hold any value, including a function such as Person.
(There is nothing that makes Person specifically a constructor. Any function can be invoked with the new keyword. If I recall the exact semantics, I think they are that when a function is called with the new keyword, it is automatically given an empty object ({}) as its context ("this") and when the function returns, the return value is that same object unless (maybe?) the function returns something else)
This is a cool question because it speaks to a pretty essential part of JavaScript's neatness or oddness (depending on how you see it).
Does that answer your question? I can clarify if necessary.
AJS.Class effectively* translates this:
var Person = new AJS.Class({
init: function(name) {
this.name = name;
Person.count++;
},
getName: function() {
return this.name;
}
});
Person.count = 0;
into this:
var Person = function (name) {
this.name = name;
Person.count++;
};
Person.prototype = {
getName: function() {
return this.name;
}
};
Person.extend = AJS.Class.prototype.extend;
Person.implement = AJS.Class.prototype.implement;
Person.count = 0;
Therefore, in this case, this in AJS.Class.prototype.extend refers to Person, because:
Person.extend(...);
// is the same as
Person.extend.call(Person, ...);
// is the same as
AJS.Class.prototype.extend.call(Person, ...);
* There are a lot of cases I don't go over; this rewrite is for simplicity in understanding the problem.
Imagine the following situation :
var inner = function () {
var obj = new this;
console.log(obj.myProperty);
};
var f1 = function () {
this.myProperty = "my Property"
}
f1.f2 = inner;
f1.f2();
Here the calling object is itself a function, so this will return a function, and we can instantiate it.
In order to use this()(not this) the outer function(the context) must itself return smth that can be instantiated(another function):
var inner = function () {
var obj = new this();
console.log(obj.myProperty);
};
var f1 = function () {
var func = function () {};
func.myProperty = 'my property';
return func;
};
f1.f2 = inner;
f1.f2();
A simpler code explaination:
class User {
constructor() {
this.name = '';
this.age = '';
}
static getInfo() {
let user = new this();
console.log(user);
}
}
User.getInfo()
Output:
Object {
age: "",
name: ""
}
see this link http://www.quirksmode.org/js/this.html It will tell you about the this keyword, but I am not sure what this() is, may be its some kind of user defined function...... that you are not aware of...
"this" means the context of the function currently running.
The code you are posting surely appears in a function that act as a method for an object.
So the object is the context of the function.
"new this()" will return a clone of the current object after running its constructor function with the passed arguments.
this() refers to the the function that the code is in, but this() would have to be within that function. Calling new this(); within a function would create a never ending loop. Calling it outside of a function would be redundant because there is no function/class set as this().