function DoIHavePrototype()
{
var a = 10;
}
CheckIt = new DoIHavePrototype();
DoIHavePrototype.prototype.GetFnName = function()
{
return "DoIHavePrototype"
}
alert(CheckIt.GetFnName())
In the above code,I observe that prototype is an in-built property for the function using which we can append property/method to a function.
But if I remove the prototype keyword in the above code like the following:
DoIHavePrototype.GetFnName = function()
{
return "DoIHavePrototype"
}
I don't get error in function definition but instead I get error while calling the method
alert(CheckIt.GetFnName()) as "CheckIt.GetFnName is not a function"
What does the JS interpreter assume this to be??
In order to be able to invoke some function a method on an object, there are 4 ways to introduce it to the object.
The first way is what you've done in your original code, which is to assign the function to the object prototype:
Foo.prototype.myFunc = function () { .... }
Another way is to assign it to this within the constructor.
function Foo() {
this.myFunc = function () { .... }
}
We can also assign it directly to the instance:
var foo = new Foo();
var myFunc = function () { .... }
foo.myFunc = myFunc
Finally, we can bind a function to the instance:
var foo = new Foo();
var myFunc = function () { .... }
var myFuncFoo = myFunc.bind(foo)
The last case is a bit special since we have a function that's not a property of the instance, but behaves like an instance method because it's invocation context is affixed to the instance.
The most common way of defining instance methods is assignment to the prototype. The prototype property on the constructor is what the instances inherit from, so that's where we put stuff. It's important to keep in mind that the instances inherit from the prototype property, not the constructor function. Assigning anything to a constructor property does not make it available as an instance property.
Assignment to this can sometimes be used if we want to have a method that's bound. For instance:
function Foo() {
this.boundMeth = this.meth.bind(this)
this.val = "foo"
}
Foo.prototype.meth = function () {
console.log(this.val)
}
This is useful if we want to pass instance.boundMeth() as a value to another function (e.g., event handler). In JavaScript, unlike many OO languages, methods are unbound:
// Using Foo from the previous example
function runner(fn) {
fn()
}
var obj = new Foo()
runner(obj.meth) // Logs `undefined`
runner(obj.boundMeth) // Logs `foo`
When assigning to the constructor prototype, you can assign in bulk:
Foo.prototype = {
meth1: function () { .... },
meth2: function () { .... },
}
If you use ES6, you can also use the class keyword:
class Foo {
myFunc() { .... }
}
This is the same as Foo.prototype.myFunc = function () { .... }.
If you append your function straight to the class it will generate so called static method which you can only call from you class like in Array.from.
So in your case you should call it using you class (not its instances) like so DoIHavePrototype.GetFnName();
you can read about this on MDN
This can also be done, in case if you still want to use it as instance method.
function DoIHavePrototype()
{
var a = 10;
this.GetFnName = function() {
return "DoIHavePrototype";
}
}
CheckIt = new DoIHavePrototype();
alert(CheckIt.GetFnName())
I noticed not all the Javascript functions are constructors.
var obj = Function.prototype;
console.log(typeof obj === 'function'); //true
obj(); //OK
new obj(); //TypeError: obj is not a constructor
Question 1: How do I check if a function is a constructor so that it can be called with new keyword?
Question 2: When I create a function, is it possible to make it NOT a constructor?
A little bit of background:
ECMAScript 6+ distinguishes between callable (can be called without new) and constructable (can be called with new) functions:
Functions created via the arrow functions syntax or via a method definition in classes or object literals are not constructable.
Functions created via the class syntax are not callable.
Functions created in any other way (function expression/declaration, Function constructor) are callable and constructable.
Built-in functions are not constructrable unless explicitly stated otherwise.
About Function.prototype
Function.prototype is a so called built-in function that is not constructable. From the spec:
Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function.
The value of Function.prototype is create at the very beginning of the runtime initialization. It is basically an empty function and it is not explicitly stated that it is constructable.
How do I check if an function is a constructor so that it can be called with a new?
There isn't a built-in way to do that. You can try to call the function with new, and either inspect the error or return true:
function isConstructor(f) {
try {
new f();
} catch (err) {
// verify err is the expected error and then
return false;
}
return true;
}
However, that approach is not failsafe since functions can have side effects, so after calling f, you don't know which state the environment is in.
Also, this will only tell you whether a function can be called as a constructor, not if it is intended to be called as constructor. For that you have to look at the documentation or the implementation of the function.
Note: There should never be a reason to use a test like this one in a production environment. Whether or not a function is supposed to be called with new should be discernable from its documentation.
When I create a function, how do I make it NOT a constructor?
To create a function is truly not constructable, you can use an arrow function:
var f = () => console.log('no constructable');
Arrow functions are by definition not constructable. Alternatively you could define a function as a method of an object or a class.
Otherwise you could check whether a function is called with new (or something similar) by checking it's this value and throw an error if it is:
function foo() {
if (this instanceof foo) {
throw new Error("Don't call 'foo' with new");
}
}
Of course, since there are other ways to set the value of this, there can be false positives.
Examples
function isConstructor(f) {
try {
new f();
} catch (err) {
if (err.message.indexOf('is not a constructor') >= 0) {
return false;
}
}
return true;
}
function test(f, name) {
console.log(`${name} is constructable: ${isConstructor(f)}`);
}
function foo(){}
test(foo, 'function declaration');
test(function(){}, 'function expression');
test(()=>{}, 'arrow function');
class Foo {}
test(Foo, 'class declaration');
test(class {}, 'class expression');
test({foo(){}}.foo, 'object method');
class Foo2 {
static bar() {}
bar() {}
}
test(Foo2.bar, 'static class method');
test(new Foo2().bar, 'class method');
test(new Function(), 'new Function()');
You are looking for if a function has a [[Construct]] internal method. The internal method IsConstructor details the steps:
IsConstructor(argument)
ReturnIfAbrupt(argument). // (Check if an exception has been thrown; Not important.)
If Type(argument) is not Object, return false. // argument === Object(argument), or (typeof argument === 'Object' || typeof argument === 'function')
If argument has a [[Construct]] internal method, return true.
Return false.
Now we need to find places where IsConstructor is used, but [[Construct]] isn't called (usually by the Construct internal method.)
I found that it is used in the String function's newTarget (new.target in js), which can be used with Reflect.construct:
function is_constructor(f) {
try {
Reflect.construct(String, [], f);
} catch (e) {
return false;
}
return true;
}
(I could have used anything really, like Reflect.construct(Array, [], f);, but String was first)
Which yields the following results:
// true
is_constructor(function(){});
is_constructor(class A {});
is_constructor(Array);
is_constructor(Function);
is_constructor(new Function);
// false
is_constructor();
is_constructor(undefined);
is_constructor(null);
is_constructor(1);
is_constructor(new Number(1));
is_constructor(Array.prototype);
is_constructor(Function.prototype);
is_constructor(() => {})
is_constructor({method() {}}.method)
<note>
The only value that I found it didn't work for is Symbol, which, although new Symbol throws a TypeError: Symbol is not a constructor in Firefox, is_constructor(Symbol) === true. This is technically the correct answer, as Symbol does have a [[Construct]] internal method (Which means it can also be subclassed), but using new or super is special cased for Symbol to throw an error (So, Symbol is a constructor, the error message is wrong, it just can't be used as one.) You can just add if (f === Symbol) return false; to the top though.
The same for something like this:
function not_a_constructor() {
if (new.target) throw new TypeError('not_a_constructor is not a constructor.');
return stuff(arguments);
}
is_constructor(not_a_constructor); // true
new not_a_constructor; // TypeError: not_a_constructor is not a constructor.
So the intentions of the function of being a constructor can't be gotton like this (Until somthing like Symbol.is_constructor or some other flag is added).
</note>
There is a quick and easy way of determining if function can be instantiated, without having to resort to try-catch statements (which can not be optimized by v8)
function isConstructor(obj) {
return !!obj.prototype && !!obj.prototype.constructor.name;
}
First we check if object is part of a prototype chain.
Then we exclude anonymous functions
There is a caveat, which is: functions named inside a definition will still incur a name property and thus pass this check, so caution is required when relying on tests for function constructors.
In the following example, the function is not anonymous but in fact is called 'myFunc'. It's prototype can be extended as any JS class.
let myFunc = function () {};
With ES6+ Proxies, one can test for [[Construct]] without actually invoking the constructor. Here's a snippet:
const handler={construct(){return handler}} //Must return ANY object, so reuse one
const isConstructor=x=>{
try{
return !!(new (new Proxy(x,handler))())
}catch(e){
return false
}
}
If the passed item isn't an object, the Proxy constructor throws an error. If it's not a constructable object, then new throws an error. But if it's a constructable object, then it returns the handler object without invoking its constructor, which is then not-notted into true.
As you might expect, Symbol is still considered a constructor. That's because it is, and the implementation merely throws an error when [[Construct]] is invoked. This could be the case on ANY user-defined function that throws an error when new.target exists, so it doesn't seem right to specifically weed it out as an additional check, but feel free to do so if you find that to be helpful.
If the function is a constructor then it will have a "prototype" member which in turn has a "constructor" member that is equal to the function itself.
function isConstructor(func) {
return typeof func === 'function' && !!func.prototype && func.prototype.constructor === func;
}
There is a quick and easy way of determining if function can be instantiated, without having to resort to try-catch statements (which can not be optimized by v8)
function isConstructor(value) {
return !!value && !!value.prototype && !!value.prototype.constructor;
}
First, we check value is truthy.
Then checks if value is part of a prototype chain.
At last, simply checks if constructor is set ;-)
Note that above is named isConstructor not is isConstructable, I mean, this will return false for Bound-constructors as said in comments, because "bound" means to redirect to something, instead of being a real constructor directly.
So this answers title's "check ... is constructor" question, but not later "check ... can be called with new" question.
Example:
const myClazz = {method() {}};
myClazz.method = myClazz.method.bind(myClazz);
// We can call above with new keyword.
new (myClazz.method);
// But it's just a callback.
if (isConstructor(myClass))
throw new Error('expected to return false for arrow-functions and similar.');
Unit-testing
Below is based on Jasmine.
// Change import to wherever your common functions are
// (for me they're in src directory, outside of tests directory).
import * as common from '../common-tools';
let isMyClassCalled = false;
class MyClass {
constructor() {
isMyClassCalled = true;
}
}
describe('App isConstructor tool', () => {
it('should detect constructor', function () {
detect(class A {});
detect(Array);
detect(Function);
detect(new Function);
detect({method() {}}.method);
});
it('should NOT detect as constructor', function () {
noDetect();
noDetect(undefined);
noDetect(null);
noDetect(1);
noDetect(new Number(1));
noDetect(new (function(){}));
noDetect(Array.prototype);
noDetect(Function.prototype);
// Commented because optimizations convert below into function.
//noDetect((() => {}));
});
it('should NOT detect bound constructors', function () {
const clazz = {method() {}};
clazz.method = clazz.method.bind(clazz);
noDetect(clazz.method);
});
it('should never call constructor', function () {
common.isConstructor(MyClass);
expect(isMyClassCalled).toBe(false);
});
function detect(value, expecting = true) {
expect(common.isConstructor(value))
.withContext('For "' + value + '" value')
.toBe(expecting);
}
function noDetect(value) {
detect(value, false);
}
});
Alternative
All above tests pass with below as well.
function isConstructor(value) {
return typeof value === 'function' && !!value.prototype && value.prototype.constructor === value;
}
For question 1, what about this helper?
Function.isConstructor = ({ prototype }) => Boolean(prototype) && Boolean(prototype.constructor)
Function.isConstructor(class {}); // true
Function.isConstructor(function() {}); // true
Function.isConstructor(() => {}); // false
Function.isConstructor("a string"); // false
For question 2, the arrow function is the solution. It cannot be used as a constructor since it does not rely on the same scope as a regular function and does not have a prototype (definition of instances, similar to class definition for real OOP)
const constructable = function() { console.log(this); };
const callable = () => { console.log(this); };
constructable(); // Window {}
callable(); // Window {}
new constructable(); // aConstructableFunction {}
new callable(); // Uncaught TypeError: callable is not a constructor
I tried many workarounds but it didn't satisfy my needs, So i made my own workaround by using reflection metadata.
GOAL: Check if the current Function has it's own __class__ metadata which represent if this function is a constructor or not.
npm install reflect-metadata
Create class decorator factory #Class()
Create a helper function to check __class__ metadata attached to the current function or not.
NOTE: The only way in this workaround to distinguish between Constructor Function and Normal Function or Class is by using Class Decorator #Class()
import 'reflect-metadata';
type Constructor<T = any> = new (...args: any[]) => T;
function Class() {
return function (target: Constructor) {
if (!!Reflect.getOwnMetadata('__class__', target)) {
throw new Error(`Cannot apply #Class decorator on ${target.name} multiple times.`);
}
Reflect.defineMetadata('__class__', target, target);
};
}
function isConstructor<T>(type: Constructor<T>): boolean {
if (typeof type !== 'function') return false;
return !!Reflect.getOwnMetadata('__class__', type);
}
/*
* ------------------
* Example
* ------------------
*/
#Class()
class ServiceClass1 {}
class ServiceClass2 {}
function Test() {}
console.log(isConstructor(ServiceClass1)) // true
console.log(isConstructor(ServiceClass2)) // false
console.log(isConstructor(Test)) // false
As an addition to Felix Kling's answer, even if a function is not constructable, we can still use it like a constructor if it has a prototype property. We can do this with the help of Object.create(). Example:
// The built-in object Symbol is not constructable, even though it has a "prototype" property:
new Symbol
// TypeError: Symbol is not a constructor.
Object.create(Symbol.prototype);
// Symbol {}
// description: (...)
// __proto__: Symbol
I'm new to Javascript's Object Oriented programming (from C++ area).
I want to know the best practice of calling member function from constructor.
Following is a working piece of code:
Obviously the "initialize" is declared ahead of the invocation "this.initialize();"
function Foo() {
this.initialize = function() {
alert("initialize");
};
this.hello = function() {
alert("helloWorld");
this.initialize();
};
this.initialize();
};
var f = new Foo();
f.hello();
If I change the code as following, it will fail at "this.initialize();".
Question 1 Why is that? Won't the Javascript Engine firstly read in all member function declarations of an object?
function Foo() {
this.initialize(); //failed here
this.initialize = function() {
alert("initialize");
};
this.hello = function() {
alert("helloWorld");
this.initialize();
};
};
var f = new Foo();
f.hello();
Then I made the change like this.
The function "initialize" is executed on construction, however, the calling for "this.initialize()" in function "hello" failed.
function Foo() {
this.initialize = function() {
alert("initialize");
}();
this.hello = function() {
alert("helloWorld");
this.initialize(); //failed here
};
};
var f = new Foo();
f.hello();
Question 2: is the first piece of code the only way of calling member function from the constructor?
Update:
if I have to define a function before using it, Question 3: why following code works?
function Foo() {
this.hello = function() {
alert("helloWorld");
this.initialize();
};
this.initialize();
};
Foo.prototype.initialize = function() {
alert("initialize");
};
var f = new Foo();
f.hello();
Question 4:
Why following code succeeded? (considering the "future" function is defined after calling)
alert("The future says: " + future());
function future() {
return "We STILL have no flying cars.";
}
In the first case, you are calling initialize before it is defined (on the next line).
In the second case, you are assigning the return value of the function (undefined in this case) to this.initialize, so when you try to invoke it as a function later, you get your error.
You may want to look further into the prototype pattern for making class-like structures - Douglas Crockford wrote a lot of useful stuff on this and it's useful for introductory learning: http://javascript.crockford.com/prototypal.html is a good start.
My answers inline (kind of)
Question 1 Why is that? Won't the Javascript Engine firstly read in all member function declarations of an object?
No, if they are defined as in your example, they will be executed in order, as the method doesn't exist yet, it will throw.
This way would be a different case (not OO, but to ilustrate):
function Foo(){
initialize(); //This would work
function initialize(){ ... } //Parser defines its function first
}
In this case, the parser does define the function declarations first, it's a different case.
The function "initialize" is executed on construction, however, the calling for this.initialize() in function "hello" failed.
this.initialize = function() {
alert("initialize");
}(); //This executes the function!
The problem with the above code is that you're not assigning the function to this.initialize, you're assigning the result of its execution, in this case undefined (because there is no return inside the function)
for example, if the code were:
this.initialize = function() {
return 2;
}();
then this.initialize would be... 2 !! (not a function).
Hope this helps. Cheers
Calling a method from constructor :
var f = new Foo();
function Foo() {
this.initialize(); //failed here
};
Foo.prototype.initialize = function() {
alert("initialize");
};
Execution Process:
1) All functions are created (that are defined at the root)
2) Code is executed in order
3) When Foo is created/constructed it executes the code.
It try's to run Initialize() but it doesn't find it,
it throws an internal exception that is caught and
then creates the Prototype method and executes it.
4) If the Foo.Prototype.initialize line came BEFORE the,
"var f = new Foo()" then the initialize function would have existed.
This process occurs for every line of execution.
Look at the following code:
function doNotCallMe(){
alert("Otherwise the world will be destroyed!");
}
function getNotCallable(){
return new function() {
alert("Attention!");
doNotCallMe();
};
}
var not_callable = getNotCallable();
The browser shows the alerts, which it shouldn't be. Why? How to fix?
return function() { ... }
is what you want instead.
All functions in JavaScript will act as object constructors when used with operator new; so you're defining an anonymous function, and then invoking it through new.
http://jsfiddle.net/ZLH7J/1/
What the jsFiddle and code below shows are two examples that essentially do the same thing. When trying to call first(); or this.first(); in either example, an undefined error is thrown. I can call the functions later through the instance, but not when trying to instantiate the object using init(){...}() like a constructor. I put init() at the bottom thinking it was an order of operations thing, but that is not the case. This does not work the way I thought it would work.
I am curious to understand how this is supposed to be done, and why this cannot be done.
//create and return an obj
var fishSticks = function(){
return {
first: function(){
document.getElementById('output').innerHTML="Success";
},
init: function(){
try{
first(); //err
this.first(); // also err
}catch(e){
document.getElementById('output').innerHTML=e.toString();
}
}()
}
}
//do function stuff and then return 'this'
var fishFillet = function(){
var first = function(){
document.getElementById('output2').innerHTML="Success";
}
var init = function(){
try{
first(); //err
this.first(); // also err
}catch(e){
document.getElementById('output2').innerHTML=e.toString();
}
}()
return this;
}
var test = new fishSticks();
var test2 = new fishFillet();
You need to understand two things:
1) JavaScript does not automatically insert this like Java does, so the first() call will only look through the lexical scope for a definition of first, it will nok look at the this object. Therefore the call to first() should work but this will be bound to something else than what you might expect inside first.
2) Local variables in a constructor do not become members of the constructed object.
In your second example, if you comment out the call in "init" to this.first() then you get the "Success" message.
The first version doesn't work because JavaScript simply does not allow for references to be made within an under-construction object to the object itself. There's just no way to do it.
The second one works (well the simple reference to "first" works) because "first" is declared as a local variable. Local variables are not properties of any object, and in particular they're not properties of the object allocated when the function is called with new. That's why this.first() doesn't work.
In the second one, you could make this.first() work by declaring things differently:
var fishFillet = function(){
this.first = function(){
document.getElementById('output2').innerHTML="Success";
}
var init = function(){
try{
this.first(); //will work
}catch(e){
document.getElementById('output2').innerHTML=e.toString();
}
}()
return this;
}
Also, for what it's worth, the weird anti-pattern of
var something = function() { ... }
is not as useful as
function something() { ... }
There's no reason to use the var declaration instead of the function declaration.
How about...
var fishFillet = function () {
var first = function () {
document.write( 'Success' );
};
var init = function () {
first();
};
init();
return {
first: first
};
};
And then:
var ff = fishFillet(); // calls init() which calls first()
ff.first(); // call first() manually
Live demo: http://jsfiddle.net/uaCnv/
So, first you define all your functions, next you manually invoke init, and last you return an object containing those functions which should be available through the resulting object (as methods).
Since you are using both as a constructor, format them as such:
function fishFillet(){
this.first = function(){
document.getElementById('output2').innerHTML="Success";
}
this.init = function(){
try{
this.first();
}catch(e){
document.getElementById('output2').innerHTML=e.toString();
}
}
}
var food = new fishFillet();
food.init();
The reason it wasn't working for you is b/c "first" is created as a local varaible, and is deleted after execultion. Init isn't being called until after the execution of the constructor has finished