The Javascript "apply" function doesn't exist in window.external extension object - javascript

I'm using javascript extension (AKA window.external) on IE8 (might as well be any IE version) to expose certain functions.
I'm trying to call the apply function, which is (supposed to be, according to here) natively embedded in every JS function, on a window.external object's function, but the browser keep throwing exception that the apply function doesn't exist for that function.
For example, this code works:
function onDataReceived(url, success, status, data, errorMessage) {
alert(onDataReceived);
}
function innerTest() {
alert(arguments[0] + ", " + arguments[1]);
}
function outerTest() {
innerTest.apply(null, arguments);
}
outerTest("hello", "world");
// alerts "hello, world"
But This code throws exception:
function outerTest() {
window.external.innerTest.apply(null, arguments); // <-- exception
}
outerTest("hello", "world");
Bottom line is - I need to pass an unknown number of arguments to the external function, and so far i've reached a dead end...
Any ideas?
EDIT:
I accepted Mike Samuel's answer since (as far as i understand) the apply function doesn't exist in the window.external object, because it's not a native javascript object.
What Mike suggested as the "worst case" is what I ended up doing, for the moment.
thanks

If window.external is a host object, or from some extension mechanism that doesn't want its prototype exposed to page logic, then it may be a function but may not have the usual call and apply members. Luckily, you can call call and apply apply:
Function.prototype.apply.call(window.external, null, [argumentsToExtension])
or to be really meta,
Function.prototype.apply.apply(window.external, [null, [argumentsToExtension]])
where null is what is passed as the value of this which should be interpreted as window by the usual call/apply rules.
EDIT:
If that doesn't work, you can always fall back to the triangle of hackery.
function triangleOfHackery(obj, methodName, args) {
switch (args.length) {
case 0: return obj[methodName]();
case 1: return obj[methodName](args[0]);
case 2: return obj[methodName](args[0], args[1]);
case 3: return obj[methodName](args[0], args[1], args[2]);
...
}
}

Actually there is a general solution. A simple example is like below:
function invoke (funcName, ...args) {
var argStr = '';
for (let i in args) {
argStr += ', this.args[' + i + ']';
}
return (new Function('return window.external[\'' + funcName + '\'](' + argStr.substring(2) + ')')).bind({args})();
}
// define a circular structure which cannot be stringified:
const a = {}; a.a = a;
// make a call:
invoke('foo', 10, 'abc', new Date(), function(){}, a);
// equivalent to:
window.external.foo(10, 'abc', new Date(), function(){}, a);
As you can see, there is no necessary to keep the parameters serializable.
The main idea is properly specifying the context, and mounting all the parameters onto that context.
I used ES6 syntax here just to make the code easier to understand. And of course, to make it work in IE8, you can translate it to ES5-compatible syntax and you might have ES5 shim included first to polyfill Function.prototype.bind. OR, you just never need bind at all:
EDIT: ES5 compatible version:
function invoke (funcName) {
var argStr = '';
for (var i=1; i<arguments.length; i++) {
argStr += ', this.args[' + i + ']';
}
return {
args: arguments,
func: new Function('return window.external[\'' + funcName + '\'](' + argStr.substring(2) + ')')
}.func();
}

Related

Understanding the superior method introduced by Crockford

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.

How do I create a prototype function that binds another prototype function as syntactic sugar (and keep the context of the instance)?

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.

Javascript 'this' value changing, but can't figure out why

I'm a total Javascript newb, and I'm trying to wrap my head around OLN. What I'm encountering is that, when calling an object method from another method on the same object, the value of local value of 'this' in the called method is changing. Here's my code:
var generator = {
generateForLevelSkillAndCount : function(level, skill, count) {
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
},
generate_0_4 : function(count) {
return this.generate_generic_dots(count, 3);
},
generate_generic_dots : function(count, maxDots) {
/* do cool stuff and return it */
}
};
So, I call generator.generateForLevelSkillAndCount(0, 4, 20) and it works properly, calling generate_0_4(count). However, this is where it fails, with Chrome's Javascript console telling me "Uncaught TypeError: Object [object DOMWindow] has no method 'generate_generic_dots'."
I know enough to know that the problem is that the value of this in generate_0_4 is a DOMWindow object, rather than generator (which is what this is pointing to in generateForSkillLevelAndCount but I can't figure out why that would possibly be happening.
Update: I updated the example code per CMS's suggestion to get rid of eval, but the same error is being returned, so it's not just an eval bug.
In JavaScript, the context object (this) is set to the "global object" (window, in browsers) unless the method is accessed as an object property. Therefore:
var foo = { bar: function() { alert(this.baz); }, baz: 5 };
var bar = foo.bar;
var baz = 3;
foo.bar(); // alerts 5, from foo
foo["bar"](); // alerts 5, from foo
bar(); // alerts 3, from the global object
Note that all three function calls are to the exact same function!
So, in your code, you're assigning the desired method to functionCall and calling it directly, which causes the function to use window as its context object. There are two ways around this: access the method as an object property or use .call() or .apply():
function generateForLevelSkillAndCount1(level, skill, count) {
return this['generate_' + level + '_' + skill](count);
}
function generateForLevelSkillAndCount2(level, skill, count) {
var functionCall = this['generate_' + level + '_' + skill];
return functionCall.call(this, count);
}
First of all, I would encourage you to avoid eval where you don't need it, for example, in your fist function:
//...
generateForLevelSkillAndCount : function(level, skill, count) {
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
},
//...
You can use the bracket notation property accessor instead eval, it's unnecessary in this case.
Now, I guess you are trying your code on the Chrome's Console, and eval is failing because the console has a bug, when eval is invoked from a FunctionExpression (such as generateForLevelSkillAndCount), the evaluated code uses the Global context for its Variable Environment and Lexical Environment.
See this answer for more information on this bug.
Edit: After re-reading your code, the problem happens because you lose the base object reference when you assign the function to your functionCall variable, you can either:
Invoke the function directly, without using that variable:
//...
generateForLevelSkillAndCount : function(level, skill, count) {
this['generate_' + level + '_' + skill](count);
},
//...
Or still use your variable, but persist the this value:
//...
generateForLevelSkillAndCount : function(level, skill, count) {
var functionCall = this['generate_' + level + '_' + skill];
return functionCall.call(this, count);
},
//...
More info on this...
You can control the execution context of the method call by using call():
var generator = {
generateForLevelSkillAndCount : function(level, skill, count) {
return this['generate_' + level + '_' + skill].call(this, count);
},
generate_0_4 : function(count) {
return this.generate_generic_dots.call(this, count, 3);
},
generate_generic_dots : function(count, maxDots) {
/* do cool stuff and return it */
}
};
I'm as baffled as you are, but have you considered checking out what happens if you call generate_0_4 explicitly, instead of parsing it through eval()?
When you call generate_0_4 dynamically (using an implicit to_string()) it is returned to generateForLevelSkillAndCount as an ad-hoc function. Because it's in Window scope rather than Object scope, it can't reference this, and the internal call fails because this doesn't exist in that context.
Here's how to see what's happening:
generate_0_4 : function(count) {
throw(this);
return this.generate_generic_dots(count, 3);
},
With generator.generateForLevelSkillAndCount(0, 4, 1); you get [object Window] or [object DOMWindow].
With generator.generate_0_4(1); you get what you're expecting (and what works): [object Object] or #<an Object>.
This is a feature of Javascript: the value of this will depend on the object from which the function was called, not where it was defined. (Which makes sense when functions are first-class objects themselves.) this in most other contexts refers to the window object.
There are two common workarounds, using a wrapper function:
function bind(func, obj) {
return function() {
func.apply(obj, arguments);
}
}
or using a closure:
var self = this;
function generate_blah() {
// use self instead of this here
}
In your case, though, simply replacing
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
with
this['generate_' + level + '_' + skill](count);
would do the trick.

How to turn a String into a JavaScript function call? [duplicate]

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 9 years ago.
I got a string like:
settings.functionName + '(' + t.parentNode.id + ')';
that I want to translate into a function call like so:
clickedOnItem(IdofParent);
This of course will have to be done in JavaScript. When I do an alert on settings.functionName + '(' + t.parentNode.id + ')'; it seems to get everything correct. I just need to call the function that it would translate into.
Legend:
settings.functionName = clickedOnItem
t.parentNode.id = IdofParent
Seeing as I hate eval, and I am not alone:
var fn = window[settings.functionName];
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
Edit: In reply to #Mahan's comment:
In this particular case, settings.functionName would be "clickedOnItem". This would, at runtime translate var fn = window[settings.functionName]; into var fn = window["clickedOnItem"], which would obtain a reference to function clickedOnItem (nodeId) {}. Once we have a reference to a function inside a variable, we can call this function by "calling the variable", i.e. fn(t.parentNode.id), which equals clickedOnItem(t.parentNode.id), which was what the OP wanted.
More full example:
/* Somewhere: */
window.settings = {
/* [..] Other settings */
functionName: 'clickedOnItem'
/* , [..] More settings */
};
/* Later */
function clickedOnItem (nodeId) {
/* Some cool event handling code here */
}
/* Even later */
var fn = window[settings.functionName];
/* note that settings.functionName could also be written
as window.settings.functionName. In this case, we use the fact that window
is the implied scope of global variables. */
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
window[settings.functionName](t.parentNode.id);
No need for an eval()
Here is a more generic way to do the same, while supporting scopes :
// Get function from string, with or without scopes (by Nicolas Gauthier)
window.getFunctionFromString = function(string)
{
var scope = window;
var scopeSplit = string.split('.');
for (i = 0; i < scopeSplit.length - 1; i++)
{
scope = scope[scopeSplit[i]];
if (scope == undefined) return;
}
return scope[scopeSplit[scopeSplit.length - 1]];
}
Hope it can help some people out.
JavaScript has an eval function that evaluates a string and executes it as code:
eval(settings.functionName + '(' + t.parentNode.id + ')');
eval() is the function you need to do that, but I'd advise trying one of these things to minimize the use of eval. Hopefully one of them will make sense to you.
Store the function
Store the function as a function, not as a string, and use it as a function later. Where you actually store the function is up to you.
var funcForLater = clickedOnItem;
// later is now
funcForLater(t.parentNode.id);
or
someObject.funcForLater = clickedOnItem;
// later is now
(someObject.funcForLater)(t.parentNode.id);
Store function name
Even if you have to store the function name as a string, you can minimize complexity by doing
(eval(settings.functionName))(t.parentNode.id);
which minimizes the amount of Javascript you have to construct and eval.
Dictionary of handlers
Put all of the action functions you might need into an object, and call them dictionary-style using the string.
// global
itemActions = { click: clickedOnItem, rightClick: rightClickedOnItem /* etc */ };
// Later...
var actionName = "click"; // Or wherever you got the action name
var actionToDo = itemActions[actionName];
actionToDo(t.parentNode.id);
(Minor note: If instead here you used syntax itemActions[actionName](t.parentNode.id); then the function would be called as a method of itemActions.)
While I like the first answer and I hate eval, I'd like to add that there's another way (similar to eval) so if you can go around it and not use it, you better do. But in some cases you may want to call some javascript code before or after some ajax call and if you have this code in a custom attribute instead of ajax you could use this:
var executeBefore = $(el).attr("data-execute-before-ajax");
if (executeBefore != "") {
var fn = new Function(executeBefore);
fn();
}
Or eventually store this in a function cache if you may need to call it multiple times.
Again - don't use eval or this method if you have another way to do that.
I wanted to be able to take a function name as a string, call it, AND pass an argument to the function. I couldn't get the selected answer for this question to do that, but this answer explained it exactly, and here is a short demo.
function test_function(argument) {
alert('This function ' + argument);
}
functionName = 'test_function';
window[functionName]('works!');
This also works with multiple arguments.
If settings.functionName is already a function, you could do this:
settings.functionName(t.parentNode.id);
Otherwise this should also work if settings.functionName is just the name of the function:
if (typeof window[settings.functionName] == "function") {
window[settings.functionName](t.parentNode.id);
}
This took me a while to figure out, as the conventional window['someFunctionName']() did not work for me at first. The names of my functions were being pulled as an AJAX response from a database. Also, for whatever reason, my functions were declared outside of the scope of the window, so in order to fix this I had to rewrite the functions I was calling from
function someFunctionName() {}
to
window.someFunctionName = function() {}
and from there I could call window['someFunctionName']() with ease. I hope this helps someone!
I prefer to use something like this:
window.callbackClass['newFunctionName'] = function(data) { console.log(data) };
...
window.callbackClass['newFunctionName'](data);
Based on Nicolas Gauthier answer:
var strng = 'someobj.someCallback';
var data = 'someData';
var func = window;
var funcSplit = strng.split('.');
for(i = 0;i < funcSplit.length;i++){
//We maybe can check typeof and break the bucle if typeof != function
func = func[funcSplit[i]];
}
func(data);
In javascript that uses the CommonJS spec, like node.js for instance you can do what I show below. Which is pretty handy for accessing a variable by a string even if its not defined on the window object. If there is a class named MyClass, defined within a CommonJS module named MyClass.js
// MyClass.js
var MyClass = function() {
// I do stuff in here. Probably return an object
return {
foo: "bar"
}
}
module.exports = MyClass;
You can then do this nice bit o witchcraft from another file called MyOtherFile.js
// MyOtherFile.js
var myString = "MyClass";
var MyClass = require('./' + myString);
var obj = new MyClass();
console.log(obj.foo); // returns "bar"
One more reason why CommonJS is such a pleasure.
eval("javascript code");
it is extensively used when dealing with JSON.

How to detect if a function is called as constructor?

Given a function:
function x(arg) { return 30; }
You can call it two ways:
result = x(4);
result = new x(4);
The first returns 30, the second returns an object.
How can you detect which way the function was called inside the function itself?
Whatever your solution is, it must work with the following invocation as well:
var Z = new x();
Z.lolol = x;
Z.lolol();
All the solutions currently think the Z.lolol() is calling it as a constructor.
As of ECMAScript 6, this is possible with new.target
new.target will be set as true if the function is called with new (or with Reflect.construct, which acts like new), otherwise it's undefined.
function Foo() {
if (new.target) {
console.log('called with new');
} else {
console.log('not called with new');
}
}
new Foo(); // "called with new"
Foo(); // "not called with new"
Foo.call({}); // "not called with new"
NOTE: This is now possible in ES2015 and later. See Daniel Weiner's answer.
I don't think what you want is possible [prior to ES2015]. There simply isn't enough information available within the function to make a reliable inference.
Looking at the ECMAScript 3rd edition spec, the steps taken when new x() is called are essentially:
Create a new object
Assign its internal [[Prototype]] property to the prototype property of x
Call x as normal, passing it the new object as this
If the call to x returned an object, return it, otherwise return the new object
Nothing useful about how the function was called is made available to the executing code, so the only thing it's possible to test inside x is the this value, which is what all the answers here are doing. As you've observed, a new instance of* x when calling x as a constructor is indistinguishable from a pre-existing instance of x passed as this when calling x as a function, unless you assign a property to every new object created by x as it is constructed:
function x(y) {
var isConstructor = false;
if (this instanceof x // <- You could use arguments.callee instead of x here,
// except in in EcmaScript 5 strict mode.
&& !this.__previouslyConstructedByX) {
isConstructor = true;
this.__previouslyConstructedByX = true;
}
alert(isConstructor);
}
Obviously this is not ideal, since you now have an extra useless property on every object constructed by x that could be overwritten, but I think it's the best you can do.
(*) "instance of" is an inaccurate term but is close enough, and more concise than "object that has been created by calling x as a constructor"
1) You can check this.constructor:
function x(y)
{
if (this.constructor == x)
alert('called with new');
else
alert('called as function');
}
2) Yes, the return value is just discarded when used in the new context
NOTE: This answer was written in 2008, when javascript was still in ES3 from 1999. A lot of new functionality has been added since then, so now better solutions exists. This answer is kept for historical reasons.
The benefit of the code below is that you don't need to specify the name of the function twice and it works for anonymous functions too.
function x() {
if ( (this instanceof arguments.callee) ) {
alert("called as constructor");
} else {
alert("called as function");
}
}
Update
As claudiu have pointed out in a comment below, the above code doesn't work if you assign the constructor to the same object it has created. I have never written code that does that and have newer seen anyone else do that eighter.
Claudius example:
var Z = new x();
Z.lolol = x;
Z.lolol();
By adding a property to the object, it's possible to detect if the object has been initialized.
function x() {
if ( (this instanceof arguments.callee && !this.hasOwnProperty("__ClaudiusCornerCase")) ) {
this.__ClaudiusCornerCase=1;
alert("called as constructor");
} else {
alert("called as function");
}
}
Even the code above will break if you delete the added property. You can however overwrite it with any value you like, including undefined, and it still works. But if you delete it, it will break.
There is at this time no native support in ecmascript for detecting if a function was called as a constructor. This is the closest thing I have come up with so far, and it should work unless you delete the property.
Two ways, essentially the same under the hood. You can test what the scope of this is or you can test what this.constructor is.
If you called a method as a constructor this will be a new instance of the class, if you call the method as a method this will be the methods' context object. Similarly the constructor of an object will be the method itself if called as new, and the system Object constructor otherwise. That's clear as mud, but this should help:
var a = {};
a.foo = function ()
{
if(this==a) //'a' because the context of foo is the parent 'a'
{
//method call
}
else
{
//constructor call
}
}
var bar = function ()
{
if(this==window) //and 'window' is the default context here
{
//method call
}
else
{
//constructor call
}
}
a.baz = function ()
{
if(this.constructor==a.baz); //or whatever chain you need to reference this method
{
//constructor call
}
else
{
//method call
}
}
Checking for the instance type of the [this] within the constructor is the way to go. The problem is that without any further ado this approach is error prone. There is a solution however.
Lets say that we are dealing with function ClassA(). The rudimentary approach is:
function ClassA() {
if (this instanceof arguments.callee) {
console.log("called as a constructor");
} else {
console.log("called as a function");
}
}
There are several means that the above mentioned solution will not work as expected. Consider just these two:
var instance = new ClassA;
instance.classAFunction = ClassA;
instance.classAFunction(); // <-- this will appear as constructor call
ClassA.apply(instance); //<-- this too
To overcome these, some suggest that either a) place some information in a field on the instance, like "ConstructorFinished" and check back on it or b) keep a track of your constructed objects in a list. I am uncomfortable with both, as altering every instance of ClassA is way too invasive and expensive for a type related feature to work. Collecting all objects in a list could provide garbage collection and resource issues if ClassA will have many instances.
The way to go is to be able to control the execution of your ClassA function. The simple approach is:
function createConstructor(typeFunction) {
return typeFunction.bind({});
}
var ClassA = createConstructor(
function ClassA() {
if (this instanceof arguments.callee) {
console.log("called as a function");
return;
}
console.log("called as a constructor");
});
var instance = new ClassA();
This will effectively prevent all attempts to trick with the [this] value. A bound function will always keep its original [this] context unless you call it with the new operator.
The advanced version gives back the ability to apply the constructor on arbitrary objects. Some uses could be using the constructor as a typeconverter or providing an callable chain of base class constructors in inheritance scenarios.
function createConstructor(typeFunction) {
var result = typeFunction.bind({});
result.apply = function (ths, args) {
try {
typeFunction.inApplyMode = true;
typeFunction.apply(ths, args);
} finally {
delete typeFunction.inApplyMode;
}
};
return result;
}
var ClassA = createConstructor(
function ClassA() {
if (this instanceof arguments.callee && !arguments.callee.inApplyMode) {
console.log("called as a constructor");
} else {
console.log("called as a function");
}
});
actually the solution is very possible and simple... don't understand why so many words been written for such a tiny thing
UPDATE: thanks to TwilightSun the solution is now completed, even for the test Claudiu suggested! thank you guys!!!
function Something()
{
this.constructed;
if (Something.prototype.isPrototypeOf(this) && !this.constructed)
{
console.log("called as a c'tor"); this.constructed = true;
}
else
{
console.log("called as a function");
}
}
Something(); //"called as a function"
new Something(); //"called as a c'tor"
demonstrated here: https://jsfiddle.net/9cqtppuf/
Extending Gregs solution, this one works perfectly with the test cases you provided:
function x(y) {
if( this.constructor == arguments.callee && !this._constructed ) {
this._constructed = true;
alert('called with new');
} else {
alert('called as function');
}
}
EDIT: adding some test cases
x(4); // OK, function
var X = new x(4); // OK, new
var Z = new x(); // OK, new
Z.lolol = x;
Z.lolol(); // OK, function
var Y = x;
Y(); // OK, function
var y = new Y(); // OK, new
y.lolol = Y;
y.lolol(); // OK, function
There is no reliable way to distinguish how a function is called in JavaScript code.1
However, a function call will have this assigned to the global object, while a constructor will have this assigned to a new object. This new object cannot ever be the global object, because even if an implementation allows you to set the global object, you still haven't had the chance to do it.
You can get the global object by having a function called as a function (heh) returning this.
My intuition is that in the specification of ECMAScript 1.3, constructors that have a defined behavior for when called as a function are supposed to distinguish how they were called using this comparison:
function MyClass () {
if ( this === (function () { return this; })() ) {
// called as a function
}
else {
// called as a constructor
}
}
Anyway, anyone can just use a function's or constructor's call or apply and set this to anything. But this way, you can avoid "initializing" the global object:
function MyClass () {
if ( this === (function () { return this; })() ) {
// Maybe the caller forgot the "new" keyword
return new MyClass();
}
else {
// initialize
}
}
1. The host (aka implementation) may be able to tell the difference, if it implements the equivalent to the internal properties [[Call]] and [[Construct]]. The former is invoked for function or method expressions, while the latter is invoked for new expressions.
In my testing for http://packagesinjavascript.wordpress.com/ I found the test if (this == window) to be working cross-browser in all cases, so that's the one I ended up using.
-Stijn
Until I saw this thread I never considered that the constructor might be a property of an instance, but I think the following code covers that rare scenario.
// Store instances in a variable to compare against the current this
// Based on Tim Down's solution where instances are tracked
var Klass = (function () {
// Store references to each instance in a "class"-level closure
var instances = [];
// The actual constructor function
return function () {
if (this instanceof Klass && instances.indexOf(this) === -1) {
instances.push(this);
console.log("constructor");
} else {
console.log("not constructor");
}
};
}());
var instance = new Klass(); // "constructor"
instance.klass = Klass;
instance.klass(); // "not constructor"
For most cases I'll probably just check instanceof.
From John Resig:
function makecls() {
return function(args) {
if( this instanceof arguments.callee) {
if ( typeof this.init == "function")
this.init.apply(this, args.callee ? args : arguments)
}else{
return new arguments.callee(args);
}
};
}
var User = makecls();
User.prototype.init = function(first, last){
this.name = first + last;
};
var user = User("John", "Resig");
user.name
If you're going hackish, then instanceof is the minimum solution after new.target as by other answers. But using the instanceof solution it would fail with this example:
let inst = new x;
x.call(inst);
Combining with #TimDown solution, you can use ES6's WeakSet if you want compatibility with older ECMAScript versions to prevent putting properties inside instances. Well, WeakSet will be used in order to allow unused objects be garbage collected. new.target won't be compatible in the same source code, as it is a ES6's syntax feature. ECMAScript specifies identifiers cannot be one of the reserved words, and new is not an object, anyways.
(function factory()
{
'use strict';
var log = console.log;
function x()
{
log(isConstructing(this) ?
'Constructing' :
'Not constructing'
);
}
var isConstructing, tracks;
var hasOwnProperty = {}.hasOwnProperty;
if (typeof WeakMap === 'function')
{
tracks = new WeakSet;
isConstructing = function(inst)
{
if (inst instanceof x)
{
return tracks.has(inst) ?
false : !!tracks.add(inst);
}
return false;
}
} else {
isConstructing = function(inst)
{
return inst._constructed ?
false : inst._constructed = true;
};
}
var z = new x; // Constructing
x.call(z) // Not constructing
})();
ECMAScript 3's instanceof operator of is specified as:
11.8.6 The instanceof operator
--- The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated
as follows:
--- 1. Evaluate RelationalExpression.
--- 2. Call GetValue(Result(1)).
--- 3. Evaluate ShiftExpression.
--- 4. Call GetValue(Result(3)).
--- 5. If Result(4) is not an object, throw a TypeError exception.
--- 6. If Result(4) does not have a [[HasInstance]] method, throw a TypeError exception.
--- 7. Call the [[HasInstance]] method of Result(4) with parameter Result(2).
--- 8. Return Result(7).
15.3.5.3 [[HasInstance]] (V)
--- Assume F is a Function object.
--- When the [[HasInstance]] method of F is called with value V, the following steps are taken:
--- 1. If V is not an object, return false.
--- 2. Call the [[Get]] method of F with property name "prototype".
--- 3. Let O be Result(2).
--- 4. If O is not an object, throw a TypeError exception.
--- 5. Let V be the value of the [[Prototype]] property of V.
--- 6. If V is **null**, return false.
--- 7. If O and V refer to the same object or if they refer to objects joined to each other (13.1.2), return true.
--- 8. Go to step 5.
And that means it'll be recursing the left hand side value after going to its prototype until it is not an object or until it is equal to the prototype of the right hand side object with the specified [[HasInstance]] method. What means it'll check if left hand side is an instance of the right hand side, consuming all internal prototypes of the left hand side though.
function x() {
if (this instanceof x) {
/* Probably invoked as constructor */
} else return 30;
}
maybe I`m wrong but (at the cost of a parasite) the following code seems like a solution:
function x(arg) {
//console.debug('_' in this ? 'function' : 'constructor'); //WRONG!!!
//
// RIGHT(as accepted)
console.debug((this instanceof x && !('_' in this)) ? 'function' : 'constructor');
this._ = 1;
return 30;
}
var result1 = x(4), // function
result2 = new x(4), // constructor
Z = new x(); // constructor
Z.lolol = x;
Z.lolol(); // function
Although this thread is ancient, I'm surprised that nobody has mentioned that under strict mode ('use strict') a function's default this value is undefined, instead of set to global/window as before, so to check if new is not used simply test for falsey value of !this
- EG:
function ctor() { 'use strict';
if (typeof this === 'undefined')
console.log('Function called under strict mode (this == undefined)');
else if (this == (window || global))
console.log('Function called normally (this == window)');
else if (this instanceof ctor)
console.log('Function called with new (this == instance)');
return this;
}
If you test that function as-is, you will get undefined as this value, due to the 'use strict' directive at the start of the function. Of course, if already has strict mode on then it won't change if you remove the 'use strict' directive, but otherwise if you remove it the this value will be set to window or global.
If you use new to call the function then the this value will match the instanceof check (although if you checked the other things, then instance is last option so this check is not needed, and to be avoided if you want to inherit instances anyway)
function ctor() { 'use strict';
if (!this) return ctor.apply(Object.create(ctor.prototype), arguments);
console.log([this].concat([].slice.call(arguments)));
return this;
}
This will log the this value and any arguments you pass to the function to console, and return the this value. If the this value is falsey then it creates a new instance using Object.create(ctor.prototype) and uses Function.apply() to re-call the constructor with the same params but with correct instance as this. If the this value is anything other than falsey then it is assumed to be a valid instance and returned.
I believe the solution is to turn your Constructor function into a wrapper of the real Constructor function and its prototype Constructor if required. This method will work in ES5 from 2009 and also work in strict mode. In the code window below I have an example using the module pattern, to hold the real constructor and its prototype's constructor, in a closure, which is accessible through scope within the constructor(wrapper). This works because no property is added to the "this" keyword within the Constructor(wrapper) and the Constructor(wrapper).prototype is not set, so is Object by default; thus the array returned from Object.getpropertyNames will have a length equal to 0, if the new keyword has been used with the Constructor(wrapper). If true then return new Vector.
var Vector = (function() {
var Vector__proto__ = function Vector() {
// Vector methods go here
}
var vector__proto__ = new Vector__proto__();;
var Vector = function(size) {
// vector properties and values go here
this.x = 0;
this.y = 0;
this.x = 0;
this.maxLen = size === undefined? -1 : size;
};
Vector.prototype = vector__proto__;
return function(size){
if ( Object.getOwnPropertyNames(this).length === 0 ) {
// the new keyword WAS USED with the wrapper constructor
return new Vector(size);
} else {
// the new keyword was NOT USED with the wrapper constructor
return;
};
};
})();
Tim Down I think is correct. I think that once you get to the point where you think you need to be able to distinguish between the two calling modes, then you should not use the "this" keyword. this is unreliable, and it could be the global object, or it could be some completely different object. the fact is, that having a function with these different modes of activation, some of which work as you intended, others do something totally wild, is undesirable. I think maybe you're trying to figure this out because of that.
There is an idiomatic way to create a constructor function that behaves the same no matter how it's called. whether it's like Thing(), new Thing(), or foo.Thing(). It goes like this:
function Thing () {
var that = Object.create(Thing.prototype);
that.foo="bar";
that.bar="baz";
return that;
}
where Object.create is a new ecmascript 5 standard method which can be implemented in regular javascript like this:
if(!Object.create) {
Object.create = function(Function){
// WebReflection Revision
return function(Object){
Function.prototype = Object;
return new Function;
}}(function(){});
}
Object.create will take an object as a parameter, and return a new object with that passed in object as its prototype.
If however, you really are trying to make a function behave differently depending on how it's called, then you are a bad person and you shouldn't write javascript code.
If you don't want to put a __previouslyConstructedByX property in the object - because it pollutes the object's public interface and could easily be overwritten - just don't return an instance of x:
function x() {
if(this instanceof x) {
console.log("You invoked the new keyword!");
return that;
}
else {
console.log("No new keyword");
return undefined;
}
}
x();
var Z = new x();
Z.lolol = x;
Z.lolol();
new Z.lolol();
Now the x function never returns an object of type x, so (I think) this instanceof x only evaluates to true when the function is invoked with the new keyword.
The downside is this effectively screws up the behaviour of instanceof - but depending on how much you use it (I don't tend to) that may not be a problem.
If you're goal is for both cases to return 30, you could return an instance of Number instead of an instance of x:
function x() {
if(this instanceof x) {
console.log("You invoked the new keyword!");
var that = {};
return new Number(30);
}
else {
console.log("No new");
return 30;
}
}
console.log(x());
var Z = new x();
console.log(Z);
Z.lolol = x;
console.log(Z.lolol());
console.log(new Z.lolol());
I had this same problem when I tried to implement a function that returns a string instead of an object.
It seems to be enough to check for the existence of "this" in the beginning of your function:
function RGB(red, green, blue) {
if (this) {
throw new Error("RGB can't be instantiated");
}
var result = "#";
result += toHex(red);
result += toHex(green);
result += toHex(blue);
function toHex(dec) {
var result = dec.toString(16);
if (result.length < 2) {
result = "0" + result;
}
return result;
}
return result;
}
Anyway, in the end I just decided to turn my RGB() pseudoclass into an rgb() function, so I just won't try to instantiate it, thus needing no safety check at all. But that would depend on what you're trying to do.
function createConstructor(func) {
return func.bind(Object.create(null));
}
var myClass = createConstructor(function myClass() {
if (this instanceof myClass) {
console.log('You used the "new" keyword');
} else {
console.log('You did NOT use the "new" keyword');
return;
}
// constructor logic here
// ...
});
On the top of the question, below code will auto-fix the issue in case function is called without new.
function Car() {
if (!(this instanceof Car)) return new Car();
this.a = 1;
console.log("Called as Constructor");
}
let c1 = new Car();
console.log(c1);
This can achieved without using ES6 new.target. You can run your code in strict mode and in this case value of this will be undefined if called without new otherwise it will be empty object.
Example::
"use strict"
function Name(){
console.log(this)
if(this){
alert("called by new")
}
else
alert("did not called using new")
}
new Name()
Use this instanceof arguments.callee (optionally replacing arguments.callee with the function it's in, which improves performance) to check if something is called as a constructor. Do not use this.constructor as that can be easily changed.

Categories