JavaScript:精彩部分
JavaScript 发展迅猛,每年都会新增大量功能。其中一些功能从未引起关注,另一些则被遗忘或弃用。让我们把这些功能放到越来越复杂、可编辑的代码沙箱中。我们的目标是让你在体验过程中时不时地体验到惊险刺激。
这些示例均取自多年来我编写的真实库或应用程序。不过,最后几个示例颇具争议,我不建议您在代码中使用它们。
最后
我通常在需要给其他开发者的函数添加一些额外逻辑时使用finallyfinally 。这样做不会改变函数的原始行为,例如返回值或抛出的错误。
此示例通过性能测量为传递的函数添加指标。
function measure (fn) {
const start = Date.now()
try {
return fn()
} finally {
console.log(`${fn.name} took ${Date.now() - start} ms`)
}
}
WeakSet 和 WeakMap
这两个属性提供的是真正私有的属性(与Symbol不同)。我通常在需要向他人对象添加一些元数据时使用它们。直接修改这些属性是不礼貌的,而且如果对象被冻结,那就麻烦了。
此示例将传入的对象字符串化并缓存结果。记忆化操作加快了运算速度,而使用 WeakMap 则避免了对象污染和内存泄漏。
const cache = new WeakMap()
export default function stringify(obj) {
let result = cache.get(obj)
if (!result) {
result = JSON.stringify(obj, null, 2)
cache.set(obj, result)
}
return result
}
代理人
代理可以调整语言的行为。大多数情况下,我用它们来扩展语言的功能,偶尔也会用它们来彻底改变一些默认行为。
这个响应式示例允许你创建可观察对象和反应。当反应中使用的可观察对象发生变更时,反应会自动重新运行。这段代码非常简化,但稍加修改就能实现更多功能。
let runningFn
const reactions = new WeakMap()
export function observe(fn) {
runningFn = fn
try {
return fn()
} finally {
runningFn = undefined
}
}
export function observable(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
runningFn && reactions.set(target, runningFn)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver)
const reaction = reactions.get(target)
reaction && reaction()
}
})
}
新功能
`new Function()` 与 `new Function()`类似,eval但它会在全局作用域中创建函数,而全局作用域不受任何'strict mode'声明的限制。我们很快就会利用这一点。
这个例子可以获取global对象——无论平台如何——这目前比预期的要复杂一些。它也被用于ES2019 globalThis 提案的polyfill 中。
const globalThis = new Function('return this')()
如果你的页面设置了内容安全策略 (CSP),那么这种方法行不通。
和
`with`会扩展语句的作用域链。可惜的是,它已被弃用,并且在严格模式下(包括 ES6 模块)无法正常工作。不过,一些技巧可以解决这个问题。
这个例子允许你编写类似 Vue 或 Angular 的模板文件,并在传递的状态上下文中渲染它们。
export default function compile(template) {
return new Function("state", `with (wrap(state)) { return \`${template}\` }`)
}
window.wrap = state => new Proxy(state, {
has: () => true
})
它with通过以下技巧来调整行为:
-
它使用
new Function()`-` 而不是eval`-` 来创建全局作用域中的函数。全局作用域位于严格模式之外,因此with可以正常工作。 -
with它使用代理来稍微调整行为。通常情况下,with它会扩展作用域链,而不是完全替换它。当在传入的对象上找不到某个属性时,它会在下一个作用域(在本例中是全局作用域)中查找。我们不希望全局作用域泄露到模板中,因此我们必须欺骗模板,让它认为传入的对象上存在所有可能的属性。使用代理陷阱with可以轻松实现这一点。has
一切归于一体
我们在开发过程中意外地创建了一个速度极快、轻量级的 MVC 框架。
请点击此处查看代码库,别忘了点个赞哦!
希望你抽出时间玩了玩沙盒游戏。如果你创作出了什么奇思妙想,请留言分享。
感谢阅读!
文章来源:https://dev.to/solkimicreb/javascript-the-fun-parts-15cb