Я пытаюсь выяснить, наблюдается ли какое-то поведение, которое я наблюдаю в Node v4.1.1 (V8 v4.5.103.33) относительно super и функций стрелок, и если это так (или действительно, если нет), где он находится в спецификации, в котором говорится, что он должен (или не должен) работать в различных случаях, которые у меня есть.
Вкратце: использование super в функции стрелки (inner) внутри другой функции стрелки (outer) внутри метода работает, если outer не имеет аргументов или переменных inner, даже если inner ссылается на аргументы или переменные method. Я хочу знать , что говорит спецификатор: должно ли оно работать все время, даже если V8 не работает? Никогда? Только в конкретных случаях, когда V8 в настоящее время позволяет ему работать, а не там, где это не так?
Здесь MCVE:
"use strict";
class Parent {
show(msg) {
console.log(`Parent#show: ${msg}`);
}
}
class Child extends Parent {
method(arg) {
let outer = (x) => {
console.log(`outer: x = ${x}`);
let inner = () => {
super.show(`arg = ${arg}, x = ${x}`);
};
inner();
};
outer(42);
}
}
new Child().method("arg");
Сбой:
$ node test.js
/path/test.js:13
super.show(`arg = ${arg}, x = ${x}`);
^^^^^
SyntaxError: 'super' keyword unexpected here
at outer (/path/test.js:16:13)
at Child.method (/path/test.js:18:9)
at Object. (/path/test.js:22:13)
at Module._compile (module.js:434:26)
at Object.Module._extensions..js (module.js:452:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:475:10)
at startup (node.js:117:18)
at node.js:951:3
Если вы удалите ссылку на x, которая находится в inner:
let inner = () => {
super.show(`arg = ${arg}`); // <== removed x from this
};
он работает и выводит:
outer: x = 42 Parent#show: arg = arg
Чтобы доказать себе, что дело "работает" не в том, что функции были оптимизированы, я вернул их из метода и назвал их. Вот этот немного более сложный случай (обратите внимание на комментарии); эта версия работает:
"use strict";
class Parent2 {
show(msg) {
console.log(`Parent2#show: ${msg}`);
}
}
class Child2 extends Parent2 {
method(arg) {
let flag = Math.random() < 0.5;
console.log(`method called with ${arg}, flag is ${flag}`);
let x = "A"; // **A**
let outer2 = (/*x*/) => { // **B**
//let x = "C"; // **C**
let inner2 = () => {
super.show(`${x}: ${arg} (${flag})`);
};
return inner2;
};
return outer2;
}
}
let o = new Child2().method("arg");
console.log(`type of outer2: ${typeof o}`);
let i = o();
console.log(`type of inner2: ${typeof i}`);
i("B");
Вывод:
method called with arg, flag is false type of outer2: function type of inner2: function Parent2#show: A: arg (false)
Но если мы прокомментируем строку с меткой A и раскомментируем либо B, либо C, она терпит неудачу, как это делает MCVE.
Дополнительные примечания:
-
Я должен подчеркнуть, что вам нужно, чтобы функции стрелок были вложены.
outerне имеет проблем с доступом кsuper. Я не хочу загромождать вопрос другим большим блоком кода, но если вы добавитеsuper.show(`outer: arg = ${arg}, x = ${x}`);в началоouter, он будет работать нормально. -
Как вы можете видеть,
innerиспользует как аргумент, так и переменную изmethod(ну, MCVE просто использует arg), и это прекрасно, но как толькоinnerпытается использовать аргумент или переменная отouter, все взорвется. -
Babel и Traceur с удовольствием передают случай, когда V8 не будет работать (здесь и здесь), но это может быть просто им что-то не так, что V8 получает право (или, конечно, наоборот).
-
Он не относится к строкам шаблона; версия pre-MCVE этого не использовала их (и использовала promises, вот как мы закончили со стрелками внутри стрелок).
Просто чтобы подчеркнуть, вопрос в том, что здесь указано здесь, и где в спецификации указано.
Моя кишка говорит мне, что это всего лишь ошибка V8 – — это первые дни для этого, в конце концов, честный 'нах. Но в любом случае, я просто пытаюсь понять, каково должно быть поведение, что говорит спецификация. Я пытался следить за его различными и разными разделами, говоря о super и "базовых объектах" и т.д., И, честно говоря, я просто не понимаю.