一个简单的 Chrome 插件
给天猫商品评论图片加个 "原图、向左转、向右转" 的小功能
阿里的一道测试题(群里的小伙伴提供的),题目大概这样:
大概就是让写个简单的模板解析器,尝试了好多种解构的方法都没成功...
先思考,下面就是答案了!
var greeting = 'My name is ${name}, age ${age}, I am a ${job.jobName}';
var employee = {
name: 'XiaoMing',
age: 11,
job: {
jobName: 'designer',
jobLevel: 'senior'
}
};
var result = greeting.render(employee);
console.log(result);
// 你可以趁机想想还有没有其他解法,时间充裕
// 代码参考自 @剪影boy + @Zhongsheng
String.prototype.render = function(obj) {
return this.replace(/\$\{(\w+|\w+\.\w+)\}/g, match => {
var keys = match.replace('${', '').replace('}', '').split('.')
return keys.reduce((acc, cv) => acc[cv], obj)
})
}
// 这办法是我自己想到的,有点笨
String.prototype.render = function(obj) {
// 利用了ES6的解构、对象keys新方法,在函数内部解构并自动展开变量
eval(`var {${Object.keys(obj).join(',')}} = obj`)
// 利用eval使字符串直接作为ES6解析
return eval('`' + this + '`')
}
方案二是后来不断尝试得到的
拿键声明变量 => 拒绝循环所以用
keys
=> 数组转成字符串再组合对象字符 =>eval
去构造解构 => OK!
对 JS 又爱出了新高度 😂 six six six!
With
函数)// 代码由 掘金@一口怪兽一口烟 提供
String.prototype.render = function (obj) {
with(obj) {
return eval('`' + this + '`')
}
}
莫非是史上最优解?😂 double click six six six!
期待更多的解法
字符串模板支持函数变量表达式,纯天然的模板解析器,如果是 Mustache
范儿,解析前 replace
下就行了
不再补充明细
去控制台跑下试试吧
随时欢迎补充!
相关学习资料:
完
不查资料的情况下,任意写出一种都ting厉害了
博主的网站源码开源么,github上有么
2333333
eval('`' + greeting.replace(/\$\{([^}]+?)\}/g, '${employee.$1}').replace(/`/g, '\\`') + '`')
reply:
这种 hack 的方法其实解决不了类似 "${employee}" 这样的字符串 对 ` 等的处理也不严谨
reply:
优秀!
eval(`\`${JSON.stringify(greeting.replace(/\$\{([^}]+?)\}/g, '${employee.$1}')).slice(1, -1)}\``)
reply:
这个是错的 stringify 不管反引号
oops... 更正下
String.prototype.render = function (obj) { let res = this.toString() Object.keys(obj).forEach(name => { const val = obj[name]; if (typeof val === 'object') { Object.keys(val).forEach(childName => { const regExp = new RegExp(`\\\${${name}.${childName}}`); res = res.replace(regExp, val[childName]); }); } else { const regExp = new RegExp(`\\\${${name}}`); res = res.replace(regExp, val); } }); return res; };
reply:
很棒哦
我的最笨的方法
String.prototype.render = obj => { let res = this.toString() Object.keys(obj).forEach(name => { const val = obj[name]; if (typeof val === 'object') { Object.keys(val).forEach(childName => { const regExp = new RegExp(`\\\${${name}.${childName}}`); res = res.replace(regExp, val[childName]); }); } else { const regExp = new RegExp(`\\\${${name}}`); res = res.replace(regExp, val); } }); return res; };
酷炫的博客。。
reply:
开不开心?满不满意?惊不惊喜?
那个with eval不要太吊 跪了
String.prototype.render = function (ctx) { return this.replace(/\x24\x7b([\w\.]+)\x7d/ig, (_, key) => key.split('\.').reduce((obj, attr) => obj[attr], employee)) }
reply:
666🌚🌹
reply:
更正一下
String.prototype.render = function (ctx) { return this.replace(/\x24\x7b([\w\.]+)\x7d/ig, (_, key) => key.split('\.').reduce((obj, attr) => obj[attr], ctx)) }
reply:
你的博客太酷了呀:sunglasses:
reply:
一起Cool!😂
不错啊
reply:
🌻
😂 随便写了一下,可以继续扩展parseExpression 函数,支持管道或者算术运算之类的。 评论上限2000字符... 源码在: gist
function renderParser(a, b) { function c(p) { return 0 > p || p >= i ? !1 : a[p].charCodeAt() } function d(p) { return p.split('.').reduce(function(q, r) { return q = q[r] || '', 'function' == typeof q && (q = q.call(b)), q }, b) } for (var k, f = 123, i = a.length, j = 0, l = '', m = '', n = !1, o = ''; j < i;) k = c(j), k === 36 && c(j + 1) === f ? n = !0 : n && k === 125 ? (m = d(l), l = '', n = !1, o += m) : n ? k != 32 && k != f && (l += a[j]) : o += a[j], j++; return o } String.prototype.render = function(a) { return renderParser(this, a) };
reply:
Six! Six! Six! 🌹
reply:
123
还可以在加上多级的情况,现在最多只能匹配到xx.xx
reply:
/${((\w+.)*\w+)}/g.test('${a.b.c.d}')
String.prototype.render = function(employee) { var str = this + ''; return str.replace(/\$\{(\w+|\w+\.\w+)\}/g, function(match) { var key = match.replace('${', '').replace('}', ''); if (/\./g.test(key)) { var key = key.split('.'); var value = employee; for( var i =0; i<key.length; i++ ){ value = value[key[i]] } return value; } else { return employee[key] } }) }
reply:
送花🌻
reply:
最终优化为
String.prototype.render = function(obj) { return this.replace(/\$\{(\w+|\w+\.\w+)\}/g, match => { var keys = match.replace('${', '').replace('}', '').split('.') return keys.reduce((accumulator, currentValue) => accumulator[currentValue], obj) }) }
正则的一种实现:
String.prototype.render = function(obj) { return this.replace(/\${(\w+?\.?\w+?)}/g, function(match, $1) { if ($1.includes('.')) { var arr = $1.split('.'); return obj[arr[0]][arr[1]]; } else { return obj[$1]; } }); }
reply:
应该用递归取数据哈,不然再多层对象就没法解释啦🌹
with 语句是运行缓慢的代码块,尤其是在已设置了属性值时。大多数情况下,如果可能,最好避免使用它
reply:
对
我还以为要手工实现字符串模板呢....,原来直接evel调用就可以了
套总威武👏👏👏
reply:
v587💊💊💊