比如有对象:
var a = {
b:{
c:{
d:{
}
}
}
}
使用的时候比如
var param = a.b.c.d;
但是一旦其中c或者d不存在就会报错。
一般的方式是逐层检查,但是代码很不优雅。
有什么更好的方式呢?
层级能少当然好。
不过再怎么约定优化,多层级依然是会出现的.作为个体可能英明神武,群体内也总有些队友要呵呵的:)。何况,网络7层协议,哪位可以帮我减少一层呢。
所以,我们还是回到问题本身好点。
a.b.c.d 直达语义核心,很好。需要担心的异常情况,既然都说异常了,直接用异常处理即可。异常是分离正常代码和错误处理的好方法(好像废话
function d_value(){
try {
return a.b.c.d;
}
catch(err) {
result = nil;
}
}
80386 就已经直接支持异常了,没必要如同c一样,亦步亦趋的去检查了。这样的if ,? 样式的错误处理,该过时了。
拿我前幾天重構+擴充的辭典舉例,詞典的數據是高度層次化的,且每一層的數目不定,這時候代碼若不分層,將會成爲噩夢。
雖然我沒有像樓上那樣寫很多方法單獨處理每一層的數據,而是很瀟灑地寫了一個上百行的函數,但是由於技巧的使用,層與層之間的關係很清晰,基本獨立,也很容易重構成單獨的函數。這種寫法對於簡單的程序,或者剛開始寫的時候是再好不過了,開發效率非常高。
技巧就是:
var a = JSON.parse(text); // {b:{c:{}}}
// handle level a
var b = a.b;
if (b) {
// handle level b
var c = b.c;
if (c) {
// handle level c
}
}
https://github.com/bumfo/moedict-server/blob/master/index.html?ts=4
使用 CoffeeScript:
a?.b?.c?.d
-
Source
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
或
function checkNested(obj /*, level1, level2, ... levelN*/) { var args = Array.prototype.slice.call(arguments), obj = args.shift(); for (var i = 0; i < args.length; i++) { if (!obj || !obj.hasOwnProperty(args[i])) { return false; } obj = obj[args[i]]; } return true; } var test = {level1:{level2:{level3:'level3'}} }; checkNested(test, 'level1', 'level2', 'level3'); // true checkNested(test, 'level1', 'level2', 'foo'); // false
-
brototype
var myURL; if (Bro(app).doYouEven('config.environment.buildURL')) { myURL = app.config.environment.buildURL('dev'); }
确定合理的数据结构
如果服务端给你的是像你描述的那样多层的数据结构,先问他一句:“非得这样吗?”
开发之前沟通充分,确定合理的数据结构,对于提高效率有事半功倍的作用。
不怕层级多,只要层级分明
在现实应用中,不能保证永远都能拿到“舒服”的数据结构,所以前端代码上也要想办法处理。以下是一些建议,供参考。
1. 不要频繁地跨层操作数据。
首先应该尽量避免用 a.b.c
这种方式访问对象的属性,这样的方式有这样几个缺点:
- 最最主要的缺点:过多的使用这种方式会导致代码的混乱。因为 JavaScript 里对象的属性大多是可以“随时随地”读写的,所以在对属性进行赋值操作时,应该格外慎重。稍有不慎,很可能会出现在一处修改了某属性的值,导致“很远”的另一处使用到了这个属性的代码出错。一旦这样的代码体积庞大起来,维护的难度就蹭蹭蹭像火箭一样往上升。
- 性能问题:每次访问
a.b.c
时,引擎都要先检查这几件事:a 是否存在 => a 是否对象 => a.b 是否存在 => a.b 是否对象 => a.b.c 是否存在
,如果以上都为真,才会对a.b.c
进行操作。尽管以现在的计算机的计算能力,这带来的性能损失可能并不明显,但毕竟是对计算资源的浪费。建议的做法是在闭包内为a.b
创建引用,然后通过引用来访问a.b.c
。
2. 为每一层数据设置专门的处理方法。
利用 JavaScript 面向对象的特性来编程,专门设置一个方法来处理对象的某个属性,确保其他地方在访问这个属性时,它的值一定符合某个约定的格式。
下面是一个简单的示例:
http://jsbin.com/lipeguvese/3/edit?js,console
直接把代码贴下面,方便大家批评修改:
javascript
var Factory = function(data){ this.initialize(data); }; Factory.prototype = { initialize: function(data){ this.data = data; this.setup(); }, setup: function(){ var data = this.data, a = data.a, d = data.d, e = data.e; // 把 data.a 属性交给 handleA 处理 this.handleA(data.a); // 对 data 的其他属性的处理 d.push(4); d = d.slice(1); e = e.toUpperCase(); data.e = e; }, handleA: function(a){ // 把 a.b 交给 handleB 处理 this.handleB(a.b); // 对 a 的其他属性的处理 // ... }, handleB: function(b){ // 把 b.c 交给 handleC 处理 this.handleC(b.c); // 对 b 的其他属性的处理 // ... }, handleC: function(c){ data.c = c + 100; }, output: function(){ console.log(this.data); } }; // 假设约定的数据格式如下 var data = { a: { b: { c: 111 } }, d: [1,2,3], e: 'string property value' }; // 处理数据 var f = new Factory(data); f.output();