As far as I know, constructors are unable to produce functions: they can assign properties to this, and offer an immediate prototype reference for further properties that are generic and thus not instance-specific. But it's impossible to assign anything to this directly. Even if it were, the logical outcome would be to replace the instance with the assignment, along with its prototype chain.
From what I have read of ES6 Classes, they amount to syntax sugar for grouping constructor declaration and prototype instantiation in a single statement.
My practical interest lies in the value of the instanceof operator in asserting that X conforms to the higher order description of Y without any duck-typing. In particular, duck-typing is undesirable because it relies on some kind of definition of Y which is external to Y itself.
Edit
I'm interested in functions which are instances of other functions
In ECMAScript 6 you should be able to call Object.setPrototypeOf on a function, but it isn't advised and although in JavaScript a Function is an Object too you may end up with unexpected behaviour
function foo() {}
function bar() {}
Object.setPrototypeOf(bar, foo.prototype);
bar instanceof foo; // true
bar.constructor === foo; // true
I'm not entirely sure what you're asking, but hopefully these code examples will help you
Returning an Object from a function invoked with new
function Foo() {
// a constructor
}
function Bar() {
// another constructor
return new Foo();
}
var b = new Bar();
b instanceof Bar; // false
b instanceof Foo; // true
Using new Function
function Fizz() {
return new Function('return "Buzz";');
}
var b = Fizz();
b(); // "Buzz"
Invoking a function with a different this by using call, apply or bind
function hello() {
return this;
}
hello(); // window, null or error depending on environment
hello.call({'foo': 'bar'}); // {'foo': 'bar'}
hello.apply({'foo': 'bar'}); // {'foo': 'bar'}
var b = hello.bind({'fizz': 'buzz'});
b(); // {'fizz': 'buzz'}
Extending a constructor
function Foo() {
this.foo = 'foo';
}
Foo.prototype = {'fizz': 'buzz'};
function Bar() {
Foo.call(this);
this.bar = 'bar';
}
// and link in inheritance
Bar.prototype = Object.create(Foo.prototype);
var b = new Bar();
b.bar; // "bar"
b.foo; // "foo"
b.fizz; // "buzz"
b instanceof Bar; // true
b instanceof Foo; // true
// but
Bar instanceof Foo; // false
Constructors can construct functions. If your constructor returns an object, the object returned by the constructor function becomes the result of the whole new expression.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
As functions are objects, you can return them just as well from your constructor as shown here:
function Shout(text) {
return function () {
alert(text);
};
}
shout1 = new Shout('hola');
shout2 = new Shout('eeee');
shout1(); // hola
shout2(); // eeee
Related
What different between assigning property on Object and Object.prototype?
for example
Object.test =function(){};
and
Object.prototype.test =function(){}
The first gives Object a static method that can be invoked directly from the class, without an instance. For example:
Object.test =function(){
console.log('Object test running');
};
Object.test();
Assigning a function to the prototype, on the other hand, allows for instances to run the method:
Object.prototype.test = function() {
console.log('test running on object ', this);
};
// don't use the object constructor, this is just an example:
const obj = new Object();
obj.test();
It might make a bit more sense if you didn't use the built-in Object, which everything inherits from:
function Foo() {}
Foo.checkIfFoo = function(arg) {
return arg instanceof Foo;
};
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Here, foo.checkIfFoo is a helper function on Foo that checks if a passed object is an instance of Foo or not - no instance is required to run checkIfFoo. Functions on the prototype, on the other hand, require an instance to run:
function Foo() {
this.info = 'A Foo instance';
}
Foo.prototype.checkInfo = function() {
console.log(this.info);
};
const f = new Foo();
f.checkInfo();
Note that in ES6+, you can put a function directly on the class with the static keyword:
// roughly equivalent to the snippet with checkIfFoo above
class Foo {
static checkIfFoo(arg) {
return arg instanceof Foo;
}
}
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Whereas a standard method lacks the static keyword:
// roughly equivalent to the snippet with checkInfo above
class Foo {
constructor() {
this.info = 'A Foo instance';
}
checkInfo() {
console.log(this.info);
}
}
const f = new Foo();
f.checkInfo();
Say I have
function Foo() {
// stuff
}
Foo.prototype.bar = function() {
return new Bar();
}
function Bar() {};
module.exports = Foo;
Now say I have
const foo = new Foo();
console.log(foo instanceof Foo); // true
const bar = new Foo().bar();
console.log(bar instanceof Foo); // false
console.log(bar instanceof Foo.prototype.bar); // false
Here Bar is never exported. So how can I test if bar is an instance of ... something? Can I somehow have bar instanceof Foo or a subset of Foo or something?
By default, the function Bar is available as the constructor on Bar.prototype, which is in new Bar()'s prototype chain. (This is basically the only thing that constructor is ever useful for in practice.)
bar instanceof new Foo().bar().constructor
Conversely, if you don't want to leak the Bar constructor function in this fashion, you can clobber Bar.prototype.constructor with a new value (or just delete it) before your export Foo. If constructor has been cleared in this way, you can still check if an object's prototype chain includes the same prototype as a newly-created Bar instance:
var barProto = Object.getPrototypeOf(new Foo().bar());
var isBar = barProto.isPrototypeOf(bar);
You could compare the prototype of one bar to another:
Object.getPrototypeOf(bar) === Object.getPrototypeOf((new Foo).bar())
I have a chain of constructors using prototype inheritance in JavaScript like so:
var Test = function(){};
var Foo = function(){};
var Bar = function(){};
var Baz = function(){};
Bar.prototype = new Baz();
Foo.prototype = new Bar();
Test.prototype = new Foo();
I want to write a function getRootConstructor() such that
getRootConstructor(Test) === Baz.
The goal was that I could do
getRootConstructor(Test).prototype = new UniversalBaseConstructor();
So I could add functionality to a constructor without breaking the prototype chain. This turns out to be very unintuitive.
If you don't set the prototype of a function, they have a circular reference such that F.prototype.constructor === F. The function you want, then, is:
function getRootConstructor(T){
return T.prototype.constructor === T ? T : getRootConstructor(T.prototype.constructor);
}
In the OP, note that:
var t = new Test();
t.constructor == Test; // false
t.constructor == Baz; // true
So the base constructor is given by t.constructor.
However, it is very common to re–set ("fix") the constructor property when building inheritance like that so that each prototype's constructor property points to the right constructor:
var Test = function(){};
var Foo = function(){};
var Bar = function(){};
var Baz = function(){};
Bar.prototype = new Baz();
Bar.prototype.consructor = Bar;
Foo.prototype = new Bar();
Foo.prototype.constructor = Foo;
Test.prototype = new Foo();
Test.prototype.constructor = Test;
which means that Brad's getRootConstructor function will not work as Constructor.prototype.constructor always points to the "real" constructor and
getRootConstructor(Test) === Test;
In this case it is also common to add a _super (or similar named) property to each prototype that points to the prototype's constructor, so the base constructor could be found that way.
Note that if Brad's function really worked, it would always return the built–in Function object, as it is the base constructor for all functions.
If I can use obj.constructor.prototype to access the prototype of an object, then why can't I use obj.constructor.prototype.constructor.prototype to traverse the prototype chain and have to use Object.getPrototypeOf?
function MyConstructor()
{
this.prop = 1;
}
var o = new MyConstructor();
console.log(o.constructor.prototype) // MyConstructor
console.log(o.constructor.prototype.constructor.prototype) // MyConstructor?
Shouldn't it return the prototype of MyConstructor which is function() { [native code] } (in Chrome console)?
All constructors are instances of the global Function object:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo instanceof Function) // => true; Foo is an instance of global Function constructor
All prototypes are instances of the global Object object:
console.log(Foo.prototype instanceof Object); // => true
When a constructor Foo is defined, it automatically has a Foo.prototype object attached to it, which you can think of as a "blank" object that itself, as per the above, inherits from the global Object object. In other words, the prototype of Foo.prototype is Object.prototype:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo.prototype); // Foo (object); already exists
console.log(Object.getPrototypeOf(Foo.prototype) === Object.prototype); // => true
Since Foo.prototype is a blank object, one would expect its constructor to be the global Object constructor function:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo.prototype.constructor) // => function Foo() { this.x = 1; } ??
console.log(Foo.prototype.constructor === Object.prototype.constructor); // => false
However this "blank" object has an explicit self-referential constructor property that points back to function Foo(){ this.x = 1 } and overwrites or "masks" the default constructor property you are expecting:
function Foo(){ this.x = 1 }; // Dummy constructor function
delete Foo.prototype.constructor; // Delete explicit constructor property
console.log(Foo.prototype.constructor) // => function Object() { [native code] }
console.log(Foo.prototype.constructor === Object.prototype.constructor); // => true
Therefore you can't use obj.constructor.prototype recursively to traverse the prototype chain and have to rely on the Object.getPrototypeOf() method.
Here's a great visual reference.
If I can use obj.constructor.prototype to access the prototype of an object
You can't in general. Consider how this approach works:
var proto = MyConstructor.prototype;
// has an (nonenumberable) property "constructor"
proto.hasOwnProperty("constructor"); // `true`
// that points [back] to
proto.constructor; // `function MyConstructor() {…}`
As you see, that's a circular property structure. When you do
var o = new MyConstructor();
// and access
o.constructor; // `function MyConstructor() {…}`
// then it yields the value that is inherited from `proto`
// as `o` doesn't have that property itself:
o.hasOwnProperty("constructor"); // `false`
But that only works for object like o that inherit the constructor property from their prototype object and where that has a useful value with something pointing to the prototype object. Think of
var o = {};
o.constructor = {prototype: o};
Oops. Accessing o.constructor.prototype yields o itself here, and it could have been any other nonsensical value. The structure actually is the same as above with MyConstructor.prototype - and if you access proto.constructor.prototype.constructor.prototype[.constructor.prototype…] you won't get anything else than just proto.
then why can't I use obj.constructor.prototype.constructor.prototype to traverse the prototype chain and have to use Object.getPrototypeOf?
Because you're trapped in the circular structure as MyConstructor.prototype) has that constructor property itself and not inherited from Object.prototype. For really getting the next object the true prototype chain, you have to use Object.getPrototypeOf.
var o = new MyConstructor();
console.log(o.constructor.prototype) // MyConstructor
It should have been MyConstructor.prototype actually. Chrome console sometimes gets confused at displaying useful titles for unnamed objects though, and is not always correct.
If you get its prototype, it should yield Object.prototype, and when you get the prototype of the MyConstructor function itself it should be Function.prototype. Notice that you can do the latter by MyConstructor.constructor.prototype again…
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () { };
c.prototype = a;
var d = new c();
d.b(); // returns "bar"
d(); // throws exception, d is not a function
Is there some way for d to be a function, and yet still inherit properties from a?
Actually, it turns out that this is possible, albeit in a non-standard way.
Mozilla, Webkit, Blink/V8, Rhino and ActionScript provide a non-standard __proto__ property, which allow changing the prototype of an object after it has been created. On these platforms, the following code is possible:
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () {
return "hatstand";
}
c.__proto__ = a;
c(); // returns "hatstand"
c.b(); // returns "bar"; inherited from a
This might be of use to anyone who doesn't need to worry about cross-platform compatibility.
However, note that only the properties of an object can be inherited. For example:
var d = {};
d.__proto__ = a;
d.b(); // returns "bar"
d(); // throws exception -- the fact that d is inheriting from a function
// doesn't make d itself a function.
Short answer: not possible.
This line of your code:
var d = new c();
automatically assumes that d is an object. Unless c is a constructor of a builtin object, e.g., Function. But if c is already defined by the language, you cannot manipulate its prototype, and cannot "inherit" it from whatever you like. Well, in some interpreters you can, but you cannot do it safely across all interpreters — the standard says: "you doth not mess with standard objects or the interpreter will smite you!".
The builtin objects are "unique" and JavaScript does not provide ways to duplicate them. It is not possible to recreate String, Number, Function, and so on without resorting to incompatible trickery.
Based on a discussion on meta about a similar question I'm posting this answer here based on #alexander-mills original
This can now be done in a standards compliant way
First create an object which inherits Function
const obj = Object.create(Function.prototype); // Ensures availability of call, apply ext
Then add you custom methods and properties to obj
Next declare the function
const f = function(){
// Hello, World!
};
And set obj as the prototype of f
Object.setPrototypeOf(f,obj);
Demonstraction
const obj = Object.create(Function.prototype);
// Define an 'answer' method on 'obj'
obj.answer = function() {
// Call this object
this.call(); // Logs 'Hello, World'
console.log('The ultimate answer is 42');
}
const f = function() {
// Standard example
console.log('Hello, World');
};
Object.setPrototypeOf(f, obj);
// 'f' is now an object with an 'answer' method
f.answer();
// But is still a callable function
f();
Yes, it is possible if you use the __proto__ property Daniel Cassidy mentioned. The trick is to have c actually return a function that has had a attached to its prototype chain.
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () {
var func = function() {
return "I am a function";
};
func.__proto__ = a;
return func;
}
c.prototype = a;
var d = new c();
d.b(); // returns "bar"
d(); // returns "I am a function"
However, you'll need to do some more tweaking of the prototype chain if you want instanceof to return better results.
d instanceof c // true
d instanceof a // false
c instanceof a // false
Does it have to actually be a prototype chain? You can use a mixin pattern to make a function have all of the properties of a instead. You can even wrap it in a nice "new" syntax to fake it if you really want.
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () {
var f = function(){
return a();
};
//mixin all properties on a
for(var prop in a){
f[prop] = a[prop];
}
return f; //just returns the function instead of "this"
};
var d = new c(); //doesn't need the new keyword, but just for fun it still works
alert(d()); //show "foo"
alert(d.b()); //shows "bar"
You can add properties to d without affecting a. The only difference between this and what you want is that changes to a will not affect existing "instances" of c.
This is something I've been trying to do for a while now. Special thanks to the authors above for their input.
Here is a chained implementation of using a "callable-object":
var $omnifarious = (function(Schema){
var fn = function f(){
console.log('ran f!!!');
return f;
};
Schema.prototype = {
w: function(w){ console.log('w'); return this; },
x: function(x){ console.log('x'); return this; },
y: function(y){ console.log('y'); return this; }
};
fn.__proto__ = (new Schema()).__proto__;
return fn;
})(function schema(){ console.log('created new schema', this); });
console.log(
$omnifarious()().w().x().y()()()
);
Also, with this "Schema" approach, it may be possible to create a reusable interface using Object.freeze() on Schema's prototype or __proto__ object. That might look something like this: fn.__proto__ = Object.freeze(new Schema().__proto__) -- this is not a practical example and more may be needed. That said, its a different discussion. Try it out and let me know!
Hope this is helpful.