gulp uglify mangle ie8

使用 gulp-uglify 打包出来后, art-template 在IE8-就不能用了, 直接报模板错误.加上 mangle: false 就可以用

但mangle: false相当于没有混淆变量名, 只要使用简单的格式化就能像阅读源码一样看打包后的代码了.

所以我打算研究下,既要mangle,也要ie7

我将原版3.1.0的template.min.js与我们压缩后的template.js, 进行 格式化-diff软件 找不同, 发现一个比较显著的差异: 我们打包出来的,会把写在后面的函数声明,提到最前面.于是辗转找到了hoist_funs 参数

研究出来了开启mangle在IE7下也不报错的办法:

1,compress.hoist_funs=false,表示打包时不自动将函数声明提升到作用域顶部。配置这个之后设置mangle=true,打包出来的tempalte.js已经可用

2,mangle.reserved:这里用来定义打乱时不动的变量名。因为第一步打包出来的代码,会导致validate插件在IE8-报“缺少对象”。尝试了几次后确定了这个方法

加上这个参数的坏处是,代码里的 $ 就变得很显眼了

1
2
3
4
5
6
7
.pipe(uglify({

mangle: {reserved: ['e','$']},

compress: {hoist_funs: false}

}))

更简单的办法

uglify({ie8: true}) // uglify-js 3.0+

编程,给自己的两个忠告

1, 不要因为某项功能强大就企图用它解决大部分问题

比如正则表达式.举两个例子:

1) 验证密码强度,数字,小写字母,大写字母,特殊符号各得1分,少一个减1分
一个正则就能搞定. 但实际上用一个for循环加上4个简单正则, 也能搞定,且逻辑清晰便于理解

2) 判断同意义的字符串

比如, 判断是否包含 “我喜欢你” 或 “我爱你”, 然后告诉你 喜欢=爱
这个当然用正则的 | 多写几个条件,就能搞定
但更简单的是, 先使用 replace 把 喜欢替换成爱, 再判断有没有 “我爱你”

2, 不要因为能将就使用, 就不想办法改进

没有es5, 用 es3 或用一些库的 util 类, 多写些代码也能实现
没有电灯, 点蜡烛也可以将就一晚上
那人类还发展个P
这时候应该想方设法用上电灯

es5 new Array methods

forEach

没有返回值

其作用与for循环十分接近, 但并不能替代 for循环. 因为, forEach接受一个函数做参数, 在forEach的函数中没有 break, continue, 且return 不会跳出父函数(因为其本身就是一个函数)

在forEach的函数中 return, 不会中断forEach的继续执行.

如有下列代码:

1
2
3
4
5
6
7
function allLt0(arr) {
for (var a = 0; a < arr.length; a++) {
if (arr[a] > 0) {
return false;
}
}
}

改造成forEach

1
2
3
4
5
6
7
function allLt0(arr) {
arr.forEach(function (item) {
if (item > 0) {
return false;
}
})
}

这就有点想当然了

所以其实 forEach 只适合”对数组所有元素执行方法, 且不需要判断中断”的情况

map

执行完毕后返回一个数组, 数组长度等于原数组的长度

思考以下代码:

1
2
3
4
5
var arr = Array(5);
var b = arr.map(function (item,i) {
console.log(item);
return item + i;
})

结果并没有 console.log 执行, 且 b 是一个长度为5的空数组

原因是map/forEach会跳过数组的空元素, 而 arr 的元素全是空

如下的arr ,则不会跳过

1
2
var arr = [undefined,undefined,undefined,undefined,undefined];
var arr = Array.apply(Array, Array(5));

所以”空元素” != undefined

这个问题需要注意下,比如:

1
2
3
4
5
6
7
var arr = [];
arr[9] = 'David';
var b = arr.map(function (item) {
console.log(item);
return {name: item}
});
b;

此时b只有一个有效值,就是b[9], 长度也为10.

every

every 的用途在于, 对数组中的每个元素执行函数,如果有一个执行后没返回true, 则终止并得到false; 否则返回 true

也就是every有返回值, 是个 boolean

返回falsy值会导致every 终止

使用 every 时,记得显式的返回 true或false, 因为如果没返回 true, 就会被当成 false, 然后得到最终 false 的结果

1
2
3
4
5
6
7
8
var arr = [3,4,5];
var allLte3 = arr.every(function (item) {
if (item < 3) {
return false
}
// return true;
});
allLte3; // false

如上, 被注释掉的语句,很多新手可能会忘了写, 结果得到错误的判断结果

some

some与every是相反的. 他对每个数组元素执行函数,如果有某一个执行后返回 true, 则终止, 并得到 true

所以他也是有返回值的, 返回 boolean

要记得, 返回 truly, 会导致 some 终止!

1
2
3
4
5
6
7
8
9
10
11
var arr = [
{id:1,age:11, name:'11',salary:11000},
{id:2,age:21, name:'21',salary:21000},
{id:3,age:31, name:'31',salary:31000},
{id:4,age:41, name:'41',salary:41000},
{id:5,age:40, name:'41',salary:41000},
]
var hasLt30 = arr.some(function (item) {
if (item.age > 31) return item;
})
hasLt30; // true

注意在代码中,我试图返回一个对象, 但 hasLt30 却还是个boolean. 所以some并不会取得你返回的那个值,只是判断它, 并得到 true或 false

filter

用于取出对数组元素执行函数后,返回 true 的元素,并组成一个新数组.

其有返回值,是个数组

filter 是个常用方法. 比如, 从一个员工对象数组中, 找出所有年龄大于 30 的(便于开除):

1
2
3
4
5
6
7
8
9
var arr = [
{age: 31, name:'L'},
{age: 24, name:'M'},
{age: 32, name:'N'},
];
var Lt30 = arr.filter(function (item,i) {
return item.age >= 30;
});
Lt30;

filter 无法中止

indexOf 与 lastIndexOf

这两个比较简单. 要注意他们有第二个参数,即 fromIndex, 合理使用可节约大量时间开销:

1
2
var array = [2, 9, 9];
array.indexOf(9, 2); // 2

这两个方法太简单了, 第一个参数不能接受函数, 所以, 没法实现获取”对象数组中有某个字段的对象的 index” 的需求

另外, 他们还是属于循环,所以不宜大量使用. 比如以下场景, 判断A数组中的所有元素是否都存在于B数组中:

1
2
3
4
5
var A = [1,2,3,4,5];
var B = [0,1,2,3,4,5,6,7,8];
A.forEach(function (a) {
var isIn = B.indexOf(a) > -1;
})

这是一个不好的示例, 会产生好多次循环.

所以不要看起来方便就上了, 效率还是必须得考虑的.

reduce 与 reduceRight

这两个是这几个”新”方法中最复杂的, 且能实现的功能也多种多样.

他们除了接收一个函数作为第一个参数外, 还接受一个初始值(任何类型)做第二个参数:

1
arr.reduce(function(accu,item,i,array), initvalue)

且他们的参数函数,多了一个参数.其他方法都是(item, index, array), reduce/reduceRight的参数是: (accumulator, item, index, array)

记住 accumulator 这个单词,他已经说明了reduce的意义

其参数函数返回的对象,回成为下一个 accumulator

最常见的用法是对数组中的元素进行累加(比较求和,求乘积)

但实际情况能产生出很多变化,比如数组的元素不是简单值,而是复杂object.

比如我要得出所有员工加起来的总年龄:

1
2
3
4
5
6
7
8
9
10
var arr = [
{age:11, name:'11'},
{age:21, name:'21'},
{age:31, name:'31'},
{age:41, name:'41'},
]
var total = arr.reduce(function (accu, item) {
return accu.age ? accu.age + item.age : accu + item.age;
});
total;

reduce本意是用来进行累加计算(凡是要对数组进行累加计算的,都可以用它),但有时会用在一些貌似和累加没关系的地方.如取得年龄最大的员工:

1
2
3
4
5
6
7
8
9
10
11
var arr = [
{age:11, name:'11',salary:11000},
{age:21, name:'21',salary:21000},
{age:31, name:'31',salary:31000},
{age:41, name:'41',salary:41000},
{age:40, name:'41',salary:41000},
]
var oldest = arr.reduce(function (accu, item) {
return accu.age > item.age ? accu : item;
});
oldest; // {age:41, name:'41',salary:41000}

最终只得到一个对象.

3, 转换对象数组为以id为key的对象

就拿上面的数组来说,为了便于提取到对应id的对象,我们希望将这个数组变成这样一个大对象:

1
2
3
4
{
1:{id:1,age:11, name:'11',salary:11000},
2:{id:2...}
}

这个可以用for循环做到, 示例代码:

1
2
3
4
5
var obj = {};
for (var a = 0; a < arr.length; a++) {
obj[arr[a].id] = arr[a];
}
obj;

多了一些额外的变量, 但用reduce来实现更简单:

1
2
3
4
5
6
7
8
9
10
11
12
var arr = [
{id:1,age:11, name:'11',salary:11000},
{id:2,age:21, name:'21',salary:21000},
{id:3,age:31, name:'31',salary:31000},
{id:4,age:41, name:'41',salary:41000},
{id:5,age:40, name:'41',salary:41000},
]
var trans = arr.reduce(function (accu, item) {
accu[item.id] = item;
return accu;
}, {});
trans;

要注意传给 .reduce 的第二个参数(初始累加值), 这里是一个空object. 且要注意在函数里每次都返回它