new to javascript: not sure what function (o) means - javascript

What is o ?
If I am not mistaken, prototype means that F is going to inherit from o , but that is all I can understand here.
Can someone break this down for me:
if (!Object.create) {
Object.create = (function () {
var F = function(){};
return function (o) {
if (arguments.length !== 1) {
throw new Error('Object.create implementation only accepts one parameter.');
}
F.prototype = o;
return new F();
};
}());

o is a parameter that you pass into the function.
For example:
var myObj = Object.create({
myFn: function(){}
});
Then you can do:
myObj.myFn();

The context of that code can help you understand it better.
This polyfill covers the main use case which is creating a new object for which the prototype has been chosen but doesn't take the second argument into account. - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill
The code is intended to serve as a replacement for Object.create(proto [, propertiesObject ]) when Object.create is not provided by the environment.
So, o is just the object which will serve as the prototype of the new object you are creating.
In practice, this means that we can use o as our superclass (or more correctly o is the prototype of our superclass).
The example from the Mozilla docs makes this clear:
//subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Answering the comment, this feels a little too long for the comment box:
o is the prototype of the object you want to inherit from. Technically it is an object too, everything in JS is an object. How is almost everything in Javascript an object?.
Why would you want to inherit from another object? What's the point of OOP?
What does this line do? F.prototype = o;
Lets repeat the full code, except with comments:
// if the execution environment doesn't have object.create, e.g. in old IE
if (!Object.create) {
// make object.create equal to something
Object.create = (function(){
// create a new object F which can be inherited from
function F(){}
// return a function which
return function(o){
// throw an error if
if (arguments.length != 1) {
throw new Error('Object.create implementation only accepts one parameter.');
}
// force F to inherit o's methods and attributes
F.prototype = o
// return an instance of F
return new F()
}
})() // this is an IIFE, so the code within is automatically executed and returned to Object.create
}

Related

Can you create functions with custom prototypes in JavaScript?

First of all, I don't want to add methods to Function.prototype. Doing that would make them available for all functions and that's not what I'm looking for.
In JavaScript you can create objects with custom prototypes like this:
function CustomObj() {}
CustomObj.prototype = {};
CustomObj.prototype.sayFoo = function () { return 'foo' };
var myCustomObj = new CustomObj(); //=> returns an object: {}
myCusomObj.sayFoo(); //=> 'foo'
You can also create array-like objects with custom prototypes like this:
function CustomArr() {}
CustomArr.prototype = [];
CustomObj.prototype.sayFoo = function () { return 'foo' };
var myCustomArr = new CustomArr(); //=> returns an ordered object: []
myCustomArr.sayFoo(); //=> 'foo'
What I'd like to do is use some kind of constructor to create a function with its own custom prototype in the same way. However, the following does not work:
function CustomFn() {}
CustomFn.prototype = function () {};
CustomFn.prototype.sayFoo = function () { return 'foo' };
var myCustomFn = new CustomFn(); //=> PROBLEM! returns an object: {}
myCustomFn.sayFoo(); //=> 'foo'
// ^^ Here, the prototype was applied but the output was not a function.
myCustomFn(); //=> TypeError: object is not a function
So is there any way to accomplish what I'm trying to do?
UPDATE
Maybe there's another way I could be asking this question that would make it a little clearer.
There's a problem with the idea of a closure:
function makeFn() {
var output = function () { /* do some stuff */ };
output.foo = function () { /* do some stuff */ };
return output;
}
var specialFn = makeFn();
Essentially, this technique gives me what I want. However, the problem is that every time I call makeFn, output.foo has to be created as a totally independent function that takes up its own memory. Gross. So I could move that method out of the closure:
var protoMethods = {
"foo" : function () { /* do some stuff */ }
};
function makeFn() {
var output = function () { /* do some stuff */ };
for (var i in protoMethods) {
Object.prototype.hasOwnProperty.call(protoMethods, i) &&
(output[i] = protoMethods[i]);
}
return output;
}
var specialFn = makeFn();
But now I have to manually do an iteration every time I call makeFn which would be less efficient than if I could just assign protoMethods to be the prototype of output. So, with this new update, any ideas?
It is a tricky thing indeed, more complicated than it should be if the language was designed well...
Basically, you just can't do it cleanly in current versions. Objects other than functions can not be callable.
In future Javascript versions, you can do it with a "proxy" object that can define a "call" handler. But it is still way too complicated and contrived in my opinion.
Another way to go about it is to make your object a real function, not a custom object. Then try to set its __proto__, which is non-standard yet but works in most modern browsers, except Opera and IE 8 or less. Also maybe set its constructor property for faking instanceof checks... such hacks are quite tricky though and results will vary a lot with environments.
The following example works fine on my Firefox:
http://jsfiddle.net/Q3422/2/
function MyFun() {
if (!this || this==window) {
return new MyFun();
}
var f = function() {
return "thanks for calling!";
}
f.__proto__ = MyFun.prototype;
f.constructor = MyFun;
return f;
}
MyFun.prototype = {
foo: function() {
return "foo:" + this();
},
__proto__: Function.prototype
};
var f = new MyFun();
alert("proto method:"+f.foo()); // try our prototype methods
alert("function method:"+f.call()); // try standard function methods
alert("function call:"+f()); // try use as a function
alert('typeof:' + typeof f); // "function", not "object". No way around it in current js versions
alert('is MyFun:' + (f instanceof MyFun)); // true
alert('is Function:' + (f instanceof Function)); // true
Just wanted to add that you should not be worried about "copying" functions to each instance of your objects. The function itself is an object, so is never really copied, nor is it recompiled or anything. It does not waste memory, except for the function object reference itself and any closure variables.
Iterating over the prototype to copy it should not concern you as well, I guess you will not have a gazillion methods.
So your own last solution is probably the best if you need to support environments where proto is not settable, and you are not worried that your prototype might get extended after some objects already got created and they may not pick up the changes.
You're at the heart of what inheritance in JavaScript is all about. Yes, since prototypes are objects, you'll want to set the prototype of CustomFn to an object instead of a function.
But that object can come from another function:
function ParentFn() {}
function CustomFn() {}
CustomFn.prototype = Object.create(ParentFn.prototype);
CustomFn.prototype.sayFoo = fun ...
If you don't have ES5 or a polyfill:
CustomFn.prototype = (function() {
function F(){}
F.prototype = ParentFn.prototype;
return new F();
}());
Some may tell you just to do the following but the above way is better:
CustomFn.prototype = new ParentFn();
I tried that too, when working on V library. I wanted to override the Function constructor to enforce a restricted syntax of constructor functions, that I'm calling "class functions" (and I'm confident to do so).
Answer is no, using the new operator you can only create new "object"s, but not new "function object"s.
However you can use a constructor function both as a constructor and as a function!
var CustomFn = function () {
if (this instanceof CustomFn) {
// here we are 'new CustomFn()'
}
else {
// here we are 'CustomFn()' or 'CustomFn.call()'
}
};
Or as I believe is the better concept, to do the function in first place and then let the constructor go:
var CustomFn = function () {
if (!(this instanceof CustomFn)) { // functioning
// here we are 'CustomFn()' or 'CustomFn.call()'
return new CustomFn(); // or return undefined or throw
}
// constructing
// here we are 'new CustomFn()'
// BaseCustomFn.call(this);
};

Difference between methods of defining JavaScript 'classes'

What's the difference between these two method of defining a 'class' in JavaScript?
Method One
Define method within the constructor:
function MyClass()
{
this.foo = function() { console.log('hello world!'); };
}
Method Two
Define method on the prototype:
function MyClass()
{}
MyClass.prototype.foo = function() { console.log('hello world!'); };
The first will create a new function object on each instantiation of your object, the second will assign a reference to a prototype method to each instance. In short: the second is more efficient, because all instances will share a single function object.
That's just the logic of a prototype chain, you can try and access anything via any object:
var objLiteral = {foo:'bar'};
When accessing objLiteral.foo JS will first look at the properties that the object itself has defined, and return the value if it is found. If JS can't find the property on the object itself, it'll check the object's prototype, hence:
objLiteral.valueOf();//method defined #Object.prototype
objLiteral.valueOf === Object.prototype.valueOf //true
But when you use your first method:
function SomeConstructor()
{
this.methd = function()
{
return true;
}
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//FALSE!
That shows that we're dealing with 2 separate function objects. Move the function definition to the prototype and f.methd === g.methd; will be true:
function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//true!
In response to your comment:
Defining a method on a prototype-level allows you to change a method for a specific task, and then "reset" it back to it's default behaviour. Suppose you're in a function that's creating an AJAX request:
someObject.toString = function(){ return JSON.stringify(this);}
//when concatinating this object you'll get its json string
//do a lot of stuff
delete (someObject.toString);
Again JS will check if the object has the toString property defined on itself, which it has. So JS will delete the function you've assigned to the toString property. Next time the toString will be invoked, JS will start scanning the prototype chain all over again, and use the first occurance of the method (in the prototype). Let's clarify:
function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd = function(){return false;};
g.methd();//returns true, still <-- method is gotten from the prototype
f.methd();//returns false <-- method is defined # instance level
delete (f.methd);
f.methd();//returns true, f doesn't have the method, but the prototype still does, so JS uses that.
Or even better, you can even replace an instance's method by a method from another prototype:
f.methd = Object.prototype.valueOf;//for as long as you need
the last example is pointless, because f has the valueOf method already: its inheritance chain looks like this: var f ---> SomeConstructor ---> Object, giving you access to all Object.prototype methods, too! Neat, isn't it?
These are just dummy examples, but I hope you see this is one of those features that make JS an incredibly flexible (sometimes too flexible, I must admit) and expressive language.
In first case the function will be created for each instance and set to the foo property in the object. In second case it is shared function. When you call obj.prop then it looks for it in object itself, if it is not there, then it looks for it in proto object and so on, it is called chain of prototypes.
For example this code provides foo:
function MyClass() {
this.foo = function () {};
}
var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);
But this not:
function MyClass() {
}
MyClass.prototype.foo = function () {};
var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);

javascript: using inheritance "as is"

I want to use some very simple inheritance in Javascript without any libraries (jQuery, Prototype, etc.) and I'm forgetting how to do this.
I know how to create a simple non-inherited object:
function Foo(x)
{
this.x = x;
}
Foo.prototype = {
inc: function() { return this.x++; }
}
which I can then use as follows:
js>f1=new Foo(0)
[object Object]
js>f1.inc()
0
js>f1.inc()
1
js>f1.inc()
2
But how would I add a subclass with one additional method that inherits the Foo "inc" method, without changing the Foo class?
function Bar(x)
{
this.x = x;
}
Bar.prototype = new Foo();
Bar.prototype.pow = function(y) { return this.x+"^"+y+"="+Math.pow(this.x,y); }
That seems right except for this weirdness with the constructor; I have to call the Foo constructor once to create the Bar prototype, and when Bar's constructor is called, it seems like there's no way to call the Foo constructor.
Any suggestions?
The trick is to use Object.create instead of doing new Foo(). It will also create a new object inheriting from Foo.prototype but without calling the Foo constructor.
Bar.prototype = Object.create(Foo.prototype);
While Object.create might not be defined on older browsers, it is possible to define it yourself if you need to. (the following code is from the MDN link)
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation only accepts the first parameter.');
//tbh, the second parameter is for stuff you dont need right now.
}
function F() {}
F.prototype = o;
return new F();
};
}
You can use this code. It does exactly what you do, which is the only way I know to inherit, but this function uses create, which is new in ECMAScritp 5, if it's available, and does some extra checking:
function inherit(p) {
if (p == null) throw TypeError(); // p must be non-null
if (Object.create) // If Object.create() is defined (ECMAScript 5 way)
return Object.create(p); // use it
var t = typeof p; // If not, do some more checking (the old way)
if (t !== "object" && t !== "function") throw TypeError();
function f() {}; // Define constructor
f.prototype = p; // Set prototype to p.
return new f(); // call constructor f() to create an "heir" of p
}

JavaScript inheritance: when constructor has arguments

Using pure JavaScript to do inheritance, this is what I usually do:
function A() {}
A.prototype.run = function () {};
function B() {}
B.prototype = new A;
B.prototype.constructor = B;
Since there is no arguments to pass into the constructor, new A has nothing to complain about. Now, I haven't figured out a good way to do inheritance if the constructor has arguments to pass. For example,
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {}
B.prototype = new A;
B.prototype.constructor = B;
I could pass some arbitrary values like:
B.prototype = new A(null, null);
In some cases, I may need to validate x and y in the constructor of A. In some extreme cases, I need throw errors when checking x or y. Then, there is no way for B to inherit from A using new A.
Any suggestions?
Thanks!
Well, if you want to make B.prototype an object that inherits from A.prototype, without executing the A constructor, to avoid all possible side-effects, you could use a dummy constructor to do it, for example:
function tmp() {}
tmp.prototype = A.prototype;
B.prototype = new tmp();
B.prototype.constructor = B;
You could create a function to encapsulate the logic of the creation of this new object, e.g.:
function inherit(o) {
function F() {}; // Dummy constructor
F.prototype = o;
return new F();
}
//...
B.prototype = inherit(A.prototype);
B.prototype.constructor = B;
If you target modern browsers, you could use the ECMAScript 5 Object.create method for the same purpose, e.g.:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
//..
Although this is an old topic, I thought I'd respond anyway.
Two ways to do it:
Although the Pseudo Classical way is the most popular, it has its down sides since it needs to call the parent constructor once in the child constructor and once while inheriting the prototype. Besides, the child's prototype will contain all the properties of the parent constructor which will anyway get overwritten when the child constructor is called. My personal choice is Prototypal Inheritance.
1. Pseudo Classical Inheritance:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = new A();
B.prototype.constructor = B;
2. Prototypal Inheritance:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
The problem is that you can't easily create a prototype object for B since invoking the constructor of A can't be done. This is due to the parameters for the constructor being unknown before new B is executed. You need a dummy constructor function to construct a prototype for B that links to A's prototype.
B.prototype = (function(parent){
function protoCreator(){};
protoCreator.prototype = parent.prototype;
// Construct an object linking to A.prototype without calling constructor of A
return new protoCreator();
})(A);
Once you've got the prototype object for B set up, you need to ensure to call the constructor of A in the constructor of B.
function B(x, y) {
// Replace arguments by an array with A's arguments in case A and B differ in parameters
A.apply(this, arguments);
}
You should now be able to instantiate B by calling new B(x, y).
For a complete same including parameter validation in A see a jsFiddle.
In your original code you are setting B.prototype.constructor = B. I'm not getting why you are doing this. The constructor property does not influence the inheritance hierarchy for which the prototype property is responsible. If you want to have the named constructor contained in the constructor property you'd need to extend the code from above a little:
// Create child's prototype – Without calling A
B.prototype = (function(parent, child){
function protoCreator(){
this.constructor = child.prototype.constructor
};
protoCreator.prototype = parent.prototype;
return new protoCreator();
})(A, B);
Using the first definition of B.prototype you'd get the following results:
var b = new B(4, 6);
b.constructor // A
console.info(b instanceof A); // true
console.info(b instanceof B); // true
With the extended version, you'll get:
var b = new B(4, 6);
b.constructor // B
console.info(b instanceof A); // true
console.info(b instanceof B); // true
The cause for the different output is that instanceof follows up the whole prototype chain of b and tries to find a matching prototype object for A.prototype or B.prototype (in the other call). The b.constructor prototype does refers to the function that was used to define the instances prototype. In case you wonder why it does not point to protoCreator this is because its prototype was overwritten with A.prototype during the creation of B.prototype. The extended definition as show in the updated example fixes this constructor property to point to a more appropriate (because probably more expected) function.
For daily use, I'd recommend to discard the idea of using the constructor property of instances entirely. Instead do use instanceof since its results are more predictable/expected.
Consider this:
function B( x, y ) {
var b = Object.create( new A( x, y ) );
// augment b with properties or methods if you want to
return b;
}
And then
var b = new B( 12, 13 );
Now b inherits from an instance of A, which in turn inherits from A.prototype.
Live demo: http://jsfiddle.net/BfFkU/
Object.create isn't implemented in IE8, but one can easily manually implement it:
if ( !Object.create ) {
Object.create = function ( o ) {
function F() {}
F.prototype = o;
return new F();
};
}
This can be placed inside a ie8.js file which is loaded only for IE8 and below via conditional comments.

Javascript inheritance idea?

EDIT: I posted before I thought everything out. Here is a better implementation of what was in my mind: Javascript inheritance idea (part 2)
Okay, so I've seen that the following is bad
function A() {
this.variable = 7;
this.method = function() { alert(this.variable); };
}
alpha = new A();
beta = new A();
because you're duplicating the method for each instance. However, why couldn't you do:
var A = new function() {
this.variable = null;
this.method = function() { alert(this.variable); };
};
var alpha = {variable: 8};
alpha.__proto__ = A;
var beta = {variable: 9};
beta.__proto__ = A;
Then you inherit the methods without wasting memory, and you can specify new instance variables.
Of course, I've never seen this pattern, so what's the obvious reason it's not used?
I think you are looking for pure prototypical inheritance.
The ECMAScript 5th Edition standard introduced the Object.create method, this method creates an object that directly inherits from its first argument passed (which can be either null or an object).
For example:
var A = {
variable: null,
method : function () { alert(this.variable); };
};
var alpha = Object.create(A);
alpha.variable = 8; // or above `Object.create(A, {'variable': { value: 8 } });`
var beta = Object.create(A);
beta.variable = 9;
This method is available on the most recent browsers, however can be roughly emulated on an ECMAScript 3 implementation:
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) { throw Error('Second argument not supported'); }
if (o === null) { throw Error('Cannot set a null [[Prototype]]'); }
if (typeof o != 'object') { throw TypeError('Argument must be an object'); }
function F(){}
F.prototype = o;
return new F;
};
}
Note that there are some features that cannot be emulated on ES3, like the second argument, it expects a property descriptor like the descriptor used by the new Object.defineProperties method.
Also, Object.create allows you to create an object that doesn't inherit from any other object, by setting its [[Prototype]] to null
The obvious reason it's not used is that you're creating the objects yourself instead of letting the constructor create them. If the constructor is changed to work differently later, your code could break.
A better solution would be
function A(value) {
this.variable = value;
}
A.prototype.method = function() { alert(this.variable); };
Javascript already looks at the object's methods, then the object's prototype's methods, when figuring out what to call. So defining your method in A's prototype defines it for every A you will, or even already did, create.
The main reason that pattern is not used is that the __ proto __ is not standard. Works with firefox/chrome. But doesn't work with IE.
Also, the code you suggested doesn't have a constructor. It assumes that you'll initialize the object with the correct structure.

Categories