Making an object non-callable

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"

Answers:

Answer

Can I remove this attribute from a function, leaving only a normal object?

No. 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, "These internal methods are not part of the ECMAScript language" and "are no object properties", which means they cannot be 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 come in various kinds:

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 state
  • create a new, uncallable object from the function by means of

    var obj = Object.assign(Object.create(Object.getPrototypeOf(fn)), fn);
    
Answer

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.

Answer

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 compatible 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

Answer

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();

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.