简单实现Vue中的插值替换(三)
传送门:简单实现Vue中的插值替换(二)
这(三)的内容,大家可以当做对(二)的补充,主要就是为了解决,多级对象的访问问题。
OK,咱们正式开始。
首先我们还是来简简单单的说一下这个问题。
咱们定义一个对象,对象的层级是不确定的,就比如:
data = {
a: {
b: {
c: {
d: '这是要获取的值'
}
}
}
}
既然如此,那如何拿到这些值呢?
在 (二)中我只是简简单单定义了一个一级对象,但是如果你定义的是一个多级对象,比如上面的对象,那你在插值中肯定会写{{a.b.c.d}},你会发现这个插值替换就不行了,因为在进行到这一步时:
// 利用replace,结合正则表达式,来对插值进行替换 txt = txt.replace(regx, function (m, g) { let key = g.trim(); let value = data[key]; return value; });
data[key]
的key
值拿到的就是a.b.c.d
,那很明显,data[a.b.c.d]
就是undefined
。所以,我们还要继续改进一下。
首先,我们能发现一点,对于一个多级对象,我们在插值表达式中写的 {{a.b.c.d}}
,其实也就告诉了程序我们的访问路径。
那么,如果能有一个东西,能让程序按照我们写的路径去data
中获取值,这就OK了。
OK,兄弟们,这个东西来了:
function getValueByPath(obj,path){ ... }
这个函数就是我们要的,它接收两个参数 :
- obj:就是我们定义的对象。
- path:访问的路径。
有了这个东西,我们继续往下想:我们平常访问一个 一级对象 怎么访问的?
let obj = {
a: 1
}
很明显,obj.a
就能拿到这个值。
那么 二级对象 呢?
let obj = {
a: {
b: 1
}
}
此时,obj.a
拿到的是啥,是对象{b: 1}
,所以:
let temp = obj.a;
temp.b // 1
这样也是可以拿到最终的值。
那么,多级对象呢?很明显就是重复重复重复上面的操作,直到拿到最终的值。
OK,我们如何能让一个对象,一直一直一直的访问呢?首先我们想到一个类似 一直动,一直动,直到的结束的东西,就是 循环,那么能让循环 一直拿,一直拿的东西,很明显也有一个,就是数组。
所以,啰嗦了这么多,我们的最终目的就是要:
- 把对象的访问路径变成一个数组
- 写一个循环一直拿,直到拿到最终结果。
OK,不啰嗦了,直接上代码:
// 定义一个多级对象
let o = {
a: {
b: {
c: {
d: '这是要获取的值'
}
}
}
}
function getValue(obj, path) {
// 首先通过 split 方法,根据 . 把访问路径解析成一个数组
let paths = path.split('.'); // [a,b,c,d]
// 拿到传过来的源对象 obj
let res = obj;
let prop;
// 巧妙的利用 while 循环的特定,一直拿,指导 path.shift() 拿不到值,此时 prop 就会是 undefined 那么 while 循环就会结束
while(prop=paths.shift()) {
res = res[prop];
}
// 返回结果
return res;
}
let r = getValue(o, 'a.b.c.d');
console.log(r);
很简单的几行代码,就搞定了多级访问的事情。
那么,我么把这个东西放回到我们插值替换的代码里
function getValue(obj, path) {
// 首先通过 split 方法,根据 . 把访问路径解析成一个数组
let paths = path.split('.'); // [a,b,c,d]
// 拿到传过来的源对象 obj
let res = obj;
let prop;
// 巧妙的利用 while 循环的特定,一直拿,指导 path.shift() 拿不到值,此时 prop 就会是 undefined 那么 while 循环就会结束
while(prop=paths.shift()) {
res = res[prop];
}
// 返回结果
return res;
}
// 对下面插值替换的代码进行改造。
// 利用replace,结合正则表达式,来对插值进行替换
txt = txt.replace(regx, function (_, g) {
// 此时的 key 对于多级对象来说肯定就是一个 路径了,所以我们改一下名字,叫key不合适
// let key = g.trim();
let path = g.trim();
// 那么 data[key] 也要改一下了
//let value = data[key];
let value = getValue(data, path);
return value;
});
这样,我们的插值替换,就能搞定 多级对象 的访问啦。
OK,最后在说两句:Vue里实现的比咱这高级,类似这样:
let o = {
a: {
b: {
c: {
d: '123'
}
}
}
}
function createValueByPath(path) {
let paths = path.split('.'); // [a,b,c,d]
// 返回一个函数
return function getValueByPath(obj) {
let res = obj;
let prop;
while (prop = paths.shift()) {
res = res[prop];
}
return res;
}
}
let getValueByPath = createValueByPath('a.b.c.d');
let value = getValueByPath(o);
console.log(value);
Vue很好的利用了缓存机制,在编译的时候,如果就拿到路径穿进去,那么最后在获取值时,其实就只需要穿进去一个源对象就好了。
这就很好的避免了,每次去找这个对象都得重新解析一遍路径,算是提升了一点点性能吧,毕竟积少成多嘛。
下一篇,我们简单的说一下,虚拟dom怎么搞。
传送门:简单实现Vue中的虚拟dom