魔术字符串
魔术字符串(magic string), 相信你在浏览大佬英文文章时一定见过. 魔术字符串指的是在代码之中多次出现、与代码强耦合的某个具体的字符串。
与之相类似的还有一个魔术数字(magic number)。
魔术数字
在eslint中可以使用规则no-magic-numbers来辅助检查魔术数字, 通常我们普遍认为:
// Bad
var dutyFreePrice = 100
var finalPrice = dutyFreePrice + (dutyFreePrice * 0.25)
// Good
var TAX = 0.25
var dutyFreePrice = 100
var finalPrice = dutyFreePrice + (dutyFreePrice * TAX)
并不是所有的魔术数字都是不好的, 下面的代码示例展示了这一点:
// Bad
const HOURS_PER_DAY = 24;
const MINUTES_PER_HOUR = 60;
const SECONDs_PER_MINUTE = 60;
const MS_PER_SECOND = 1000;
if (type === 'day') {
MS = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDs_PER_MINUTE * MS_PER_SECOND
}
// 变量命令不是越长越好或越具体越好,而是根据具体的限定范围
// Good
MS = 0
if (type === 'day') {
MS = 24 * 60 * 60 * 1000
}
魔术字符串
魔术字符串与之类似, 应尽量减少:
// Bad
if (code === '200') {}
else if (code === '400') {}
// Good
const SUCCESS = '200'
if (code === SUCCESS) {}
同样, 事无绝对:
// Bad
name = 'jack'
const PRFIX = 'hello, '
console.log(PRFIX + name)
// Good
name = 'jack'
console.log("hello, " + name)
// Good
name = 'jack'
console.log(`hello, ${name}`)
Symbol
简单介绍
Symbol是js的原始数据类型,它表示独一无二的值。通常,对象的键以字符串的形式存在,这极易引发键名冲突问题,Symbol正是为此出现的。
应用场景
设想一段求面积的代码:
function getArea(model, size) {
switch (model) {
case 'rectangle':
return size.width * size.height
case 'triangle':
return size.width * size.height / 2
}
}
上面代码出现了魔术字符串, 我们把优化掉:
const judge = {
rectangle:'rectangle',
triangle:'triangle'
}
function getArea(model, size) {
switch (model) {
case judge.rectangle:
return size.width * size.height
case judge.triangle:
return size.width * size.height / 2
}
}
接着需要支持计算正方形面积, 我们可以在judeg里增加一个square属性, 但这时我们疏忽了, 既然正方形也是矩形, 那就这么写吧:
const judge = {
rectangle:'rectangle',
triangle:'triangle',
square: 'rectangle'
}
function getArea(model, size) {
switch (model) {
case judge.rectangle:
return size.width * size.height
case judge.triangle:
return size.width * size.height / 2
case judge.square:
return '计算square时, 我不会被执行'
}
}
我们新添加的计算逻辑不会被执行, 因为和rectangle重复了, 使用symbol可以避免这些问题:
const judge = {
rectangle:Symbol('rectangle'),
triangle:Symbol('triangle'),
square: Symbol('rectangle')
}
function getArea(model, size) {
switch (model) {
case judge.rectangle:
return size.width * size.height
case judge.triangle:
return size.width * size.height / 2
case judge.square:
return '计算square时, 我会被执行'
}
}
vue中使用
在vue使用symbol的一个常见常见是在provide/inject中, 当我们的上层组件组件希望为某些下层组件注入数据时, 使用symbol作为InjectionKey避免潜在的冲突:
export const myInjectionKey = Symbol()
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, { /*
要提供的数据
*/ });
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
由于provide/inject支持使用Symbol作为key, 我们可以provide/inject来封装一个多组件共享的上下文:link.juejin.cn/?target=htt….
链接中本质就是provide(Symbol("context"), 共享的数据对象), 这不会影响组件继续provide("context", 123), 因而创建的上下文环境与组件的provide/inject实现了隔离.
参考文章: