In JavaScript, functions are callable.
Can I remove this attribute from a function, leaving only a normal object?
var foo = function () {};
foo.[[callable]] = false; // pseudocode
foo(); // "foo is not a function"
In JavaScript, functions are callable.
Can I remove this attribute from a function, leaving only a normal object?
var foo = function () {};
foo.[[callable]] = false; // pseudocode
foo(); // "foo is not a function"
Share
Improve this question
edited Dec 20, 2024 at 11:51
dumbass
27.2k4 gold badges36 silver badges73 bronze badges
asked Apr 16, 2015 at 16:15
Ben AstonBen Aston
55.8k69 gold badges220 silver badges349 bronze badges
5
- 8 Out of curiosity, what are you looking to do that couldn't be done with a plain old object? – James Montagne Commented Apr 16, 2015 at 16:17
- 2 @user3749178 Curiosity. – Ben Aston Commented Apr 16, 2015 at 16:19
-
You might have to dig into an implementation like V8 to see how it determines if it's a function object or a regular object. I've never seen this distinction documented. If
typeof(foo)
returns'function'
it's presumed to be callable, and I'm pretty sure you can't change the type of an existing object. – tadman Commented Apr 16, 2015 at 16:20 - 1 It's part of ES6 to be able to subclass Function though I don't think that'll let you make it not callable. – Touffy Commented Apr 16, 2015 at 16:22
- In order to answer your question, I need a better understanding of the expected usage – Omeriko Commented Apr 19, 2015 at 9:36
4 Answers
Reset to default 12 +100No. Functions (the evaluation behaviour, not their object properties) are pretty much immutable.
The callability of objects is determined by whether they have a [[Call]] slot. The spec says about those:
Internal slots are allocated as part of the process of creating an object and may not be dynamically added to an object.
(and it is implied that they cannot dynamically be removed either). Furthermore, “internal methods are not part of the ECMAScript language” and “are not object properties”, which means they cannot be directly accessed, set, deleted or manipulated in any imaginable way by the means of the language.
[[Call]] slots are part of various objects, where they always contain an internal method, but they are never mutated except for their initialisation (once). They e in various kinds:
- [[Call]] of user-defined function objects, initialised in step 8 of FunctionAllocate
- [[Call]] of builtin function objects, initialised implicitly by the environment
- [[Call]] of bound function objects, initialised in step 6 of BoundFunctionCreate
- [[Call]] of some proxy objects, initialised conditionally in step 7a of ProxyCreate iff the proxy target is callable as well
As you can see, there is no way to alter or even remove the [[Call]] slot of an object, not even on proxies. Your best bet is
make the function
throw
when called in an inopportune statecreate a new, uncallable object from the function by means of
var obj = Object.assign(Object.create(Object.getPrototypeOf(fn)), fn);
As far as I know you can't.
The functions have a property called call()
which calls the body of the function (sorry for the redundancy).
You can set this property to any expression like for example
foo.call = console.log('foo not a function');
but that will not prevent the function's body to be called.
And since you cannot set it to a function, you can't use the event.preventDefault()
function.
I like providing an additional point of view to what Bergi already did mention, also encouraged by this answer within the OP's question.
For what purpose? – user3749178 Apr 16 at 16:18
.
@user3749178 Curiosity. – Ben Aston Apr 16 at 16:19
besides var obj = Object.assign(Object.create(Object.getPrototypeOf(fn)), fn);
, that depends on ES6
, there is an ES3
patible approach that does wrap function objects into callable objects. Thus those objects are not callable anymore by the call operator ()
, but such objects do still expose two call methods call
and apply
.
Since this approach prevents on one hand function objects being invoked by ()
(methods/functions) or by the new
operator (instantiation), on the other hand it still supports delegation (function based mixins/traits).
the gist hosted code of Function.toApplicator
this isn't an elegant solution, the idea is to create the "enabled" attribute as a flag to know if the function is enabled:
var foo = function () {
if(!arguments.callee.enabled){
throw "function disabled";
}
console.log("Hello");
}
foo.enabled = true;
foo();
foo.enabled = false;
foo();