【发布时间】:2020-05-11 07:54:21
【问题描述】:
Symbol.toPrimitive 方法,在标记的模板字面量中调用会失去对闭包的访问权限。
要重现,只需将提供的代码 sn-p 粘贴到开发控制台中,使用和不使用标记功能运行它。任何相关文章都非常感谢。
附:如果您能告诉我如何以及在何处调试 js 代码(包括 node.js),我也将不胜感激。我对词法环境、执行上下文和调用堆栈感兴趣。
const isEmptyString = /^\s*$/;
class Thread {
constructor() {
this.scope = {
current: '/test|0::0'
};
this.context = {
current: '/test|0'
};
this.html = (strings, ...interpolations) => {
var output = '';
var prevMode = this._mode;
this._mode = 'html';
var {
length
} = interpolations;
output += strings[0]
for (let i = 0; i < length; ++i) {
output += String(interpolations[i]) + strings[i + 1];
}
this._mode = prevMode;
return output;
};
}
get id() {
var fragment;
const scope = this.scope.current;
const context = this.context.current;
return Object.defineProperties(function self(newFragment) {
fragment = newFragment;
return self;
}, {
scope: {
get() {
return scope
}
},
context: {
get() {
return context
}
},
fragment: {
get() {
return fragment
}
},
[Symbol.toPrimitive]: {
value: hint => {
console.log('::', fragment, '::');
const isFragmentDefined = !isEmptyString.test(fragment);
const quote = isFragmentDefined ? '\'' : '';
const suffix = isFragmentDefined ? `::${fragment}` : '';
if (isFragmentDefined) fragment = '';
switch (true) {
case this._mode === 'html':
return `node=${quote}${scope}${suffix}${quote}`;
case this._mode === 'css':
return `${context}${suffix}`.replace(invalidCSS, char => `\\${char}`);
default:
return `${scope}${suffix}`;
}
}
}
});
}
}
let thread = new Thread();
async function article() {
let {
id,
html
} = thread;
let links = html `
<ul>
<li ${id('C-first-id')}></li>
<li ${id('C-second-id')}></li>
<li ${id('C-third-id')}></li>
<li ${id('C-fourth-id')}></li>
</ul>
`;
return html `
<article>
<h1 ${id('B-first-id')}>Some header</h1>
<p ${id('B-second-id')}>Lorem ipsum...</p>
<p ${id('B-third-id')}>Lorem ipsum...</p>
<p ${id('B-fourth-id')}>Lorem ipsum...</p>
<section>
${links}
</section>
</article>
`;
}
async function content() {
let {
id,
html
} = thread;
return html `
<main>
<div>
<h1 ${id('A-first-id')}>Last article</h1>
<div>
<a href='#' ${id('A-second-id')}>More articles like this</a>
${await article()}
<a href='#' ${id('A-third-id')}>Something else...</a>
<a href='#' ${id('A-fourth-id')}>Something else...</a>
</div>
</div>
</main>
`;
}
content();
【问题讨论】:
-
你能解释一下它应该做什么以及当它无法访问闭包时哪里出错了吗?
-
基本上,如果不详细说明,我使用标记模板文字来临时更改
thread实例上的_mode属性。因此,通过html方法中的String(interpolations[i])进行的后续字符串化可以对字符串应用适当的转换。由于_mode是实例的属性,我必须通过箭头函数将html函数绑定到实例。如果您在提供的示例中删除 tag-function,预期的输出应该与您可以获得的输出相同。
标签: javascript closures template-strings