Конструктор для вызываемого объекта в JavaScript
Как я могу сделать конструктор для вызываемого объекта в JavaScript?
Я пробовал разные способы, такие как следующие. Пример есть только сокращенный пример реального объекта.
function CallablePoint(x, y) {
function point() {
// Complex calculations at this point
return point
}
point.x = x
point.y = y
return point
}
Сначала это работает, но объект, который он создает, не является экземпляром CallablePoint
, поэтому он не копирует свойства из CallablePoint.prototype
и говорит false
на instanceof CallablePoint
, Можно ли сделать рабочий конструктор для вызываемого объекта?
4 ответа
Оказывается, это действительно возможно. Когда функция создана, либо с помощью function
синтаксис или Function
конструктор, он становится внутренним [[Call]]
имущество. Это не свойство самой функции, а свойство, которое получает любая функция при ее создании.
Хотя это только означает, что что-нибудь с [[Call]]
может быть только Function
когда он построен (ну, есть одно исключение - Function.prototype
Сам, который не наследует от Function
), это не значит, что оно не может стать чем-то другим позже, сохраняя [[Call]]
имущество. Хорошо, если ваш браузер не IE < 11.
То, что позволяет изменить магию __proto__
от ES6, уже реализована во многих браузерах. __proto__
магическое свойство, которое содержит текущий прототип. Изменяя его, я могу сделать функцию, которая наследует от чего-то, что не Function
,
function CallablePoint(x, y) {
function point() {
// Complex calculations at this point
return point
}
point.__proto__ = CallablePoint.prototype
point.x = x
point.y = y
return point
}
// CallablePoint should inherit from Function, just so you could use
// various function methods. This is not a requirement, but it's
// useful.
CallablePoint.prototype = Object.create(Function.prototype)
Во-первых, конструктор для CallablePoint
делает Function
(только Function
С разрешено начинать с [[Call]]
имущество. Далее я изменяю его прототип, чтобы он наследовал CallablePoint
, На данный момент у меня есть функция, которая не наследует от Function
(вроде как сбивает с толку).
После того как я определил конструктор для CallablePoint
с, я установил прототип CallablePoint
в Function
, так что я CallablePoint
что наследует от Function
,
Таким образом, CallablePoint
экземпляры имеют прототип цепочки: CallablePoint -> Function -> Object
в то время как все еще вызываемый. Кроме того, поскольку объект может быть вызван, он имеет в соответствии со спецификацией, typeof
равно 'function'
,
Я напишу свой ответ, предполагая, что вы были после __call__
функциональность доступна в Python и часто упоминается как "вызываемый объект". "Вызываемый объект" звучит чуждо в контексте JavaScript.
Я пробовал несколько движков JavaScript, но ни один из тех, которые я пробовал, не позволяет вам вызывать объекты, даже если вы наследуете от Function
, Например:
function Callable(x) {
... "use strict";
... this.__proto__ = Function.prototype;
... this.toString = function() { return x; };
... }
undefined
> var c = new Callable(42);
var c = new Callable(42);
undefined
> c;
c;
{ toString: [function] }
> c(42);
c(42);
TypeError: Property 'c' of object #<Object> is not a function
at repl:1:1
at REPLServer.eval (repl.js:80:21)
at repl.js:190:20
at REPLServer.eval (repl.js:87:5)
at Interface.<anonymous> (repl.js:182:12)
at Interface.emit (events.js:67:17)
at Interface._onLine (readline.js:162:10)
at Interface._line (readline.js:426:8)
at Interface._ttyWrite (readline.js:603:14)
at ReadStream.<anonymous> (readline.js:82:12)
> c instanceof Function;
c instanceof Function;
true
c.apply(null, [43]);
TypeError: Function.prototype.apply was called on 43, which is a object and not a function
at Function.APPLY_PREPARE (native)
at repl:1:3
at REPLServer.eval (repl.js:80:21)
at repl.js:190:20
at REPLServer.eval (repl.js:87:5)
at Interface.<anonymous> (repl.js:182:12)
at Interface.emit (events.js:67:17)
at Interface._onLine (readline.js:162:10)
at Interface._line (readline.js:426:8)
at Interface._ttyWrite (readline.js:603:14)
>
Это V8 (Node.js). Т.е. у вас может быть объект, который формально наследует от функции, но он не вызывается, и я не смог найти способ убедить среду выполнения, что он может быть вызван. У меня были похожие результаты в реализации JavaScrip в Mozilla, поэтому я думаю, что она должна быть универсальной.
Тем не менее, роль пользовательских типов в JavaScript исчезающе мала, поэтому я не думаю, что вам все равно будет не хватать этого. Но, как вы уже обнаружили, вы можете создавать свойства для функций так же, как и для объектов. Таким образом, вы можете сделать это, просто менее удобным способом.
Я не уверен, если вы знаете, что ваш объект будет только экземпляром CallablePoint
если вы используете new
ключевое слово. Называя его "вызываемым", вы заставляете меня думать, что вы не хотите использовать new
, В любом случае, есть способ заставить экземпляр быть возвращенным (спасибо за подсказку, Resig):
function CallablePoint(x, y) {
if (this instanceof CallablePoint) {
// Your "constructor" code goes here.
// And don't return from here.
} else {
return new CallablePoint(x, y);
}
}
Это вернет экземпляр CallablePoint
независимо от того, как это называлось:
var obj1 = CallablePoint(1,2);
console.log(obj1 instanceof CallablePoint); // true
var obj2 = new CallablePoint(1,2);
console.log(obj2 instanceof CallablePoint); // true
Если вы хотите CallablePoint()
конструктор для возврата объекта типа CallablePoint, тогда вы можете сделать что-то вроде этого, где объект CallablePoint содержит точку в качестве свойства объекта, но остается объектом CallablePoint:
function CallablePoint(x, y) {
this.point = {};
this.point.x = x
this.point.y = y
}
или, если вы действительно пытаетесь сделать функцию, которая возвращает вам объект CallablePoint, то вы можете создать фактор-функцию:
function CallablePoint(x, y) {
this.point = {};
this.point.x = x
this.point.y = y
}
function makeCallablePoint(x, y) {
return new CallablePoint(x,y);
}