变量使用规范
变量使用规范
-
变量拷贝,需要考虑深浅拷贝
如果数组或对象只有一层,只需考虑浅拷贝
const sourceObj = {a:1,b:2,c:3} const sourceArray = [1,2,3] bad : ❌ const targetObj = sourceObj; const targetArray = sourceArray; good ✅ const targetObj = Object.assign({},sourceObj); const targeArray = [...sourceArray]
如果数组或对象有多层,需要考虑深拷贝,并建议使用lodash标准库。
JSON.stringify实现拷贝,对象中有 new Date, undefined, 函数,NaN,infinityMax 或 infinityMin时存在丢失。const sourceObj = {a:1,b:2,c:{d:3,e:4}} const sourceArray = [1,2,[3,4]] bad : ❌ const targetObj = Object.assign({},sourceObj); const targetArray = JSON.parse(JSON.stringify(targetArray)); good ✅ import lodash from 'lodash' const targetObj = lodash.cloneDeep(sourceObj); const targeArray = lodash.cloneDeep(sourceArray);
-
减少全局变量,通过函数包装
避免在window上定义,另外也尽量减少var(ESLint约束)bad : ❌ window.USERNAME = 'Rebort'; 修改时: window.USERNAME = 'John'; good ✅ let userNameData = 'Rebort'; export function userName(){ return userNameData; } export function setUserName(arg){ userNameData = arg; }
-
用查询取代临时变量
临时变量的问题在于:
它们是暂时的,并且只能在所属函数内使用。因为临时变量只在所属函数内可见,因此,若是不少地方都在用这个临时变量,就会驱使你写出更长的函数。若是把临时变量替换为一个查询,那么其余函数中均可以得到这份信息。本例子来源于《重构》,以一个临时变量保存某一表达式的运算结果,若是这个临时变量在多个地方用到,能够考虑用此方法,将表达式提炼到一个独立函数中
bad : //有两个临时变量 basePrice、discountFactor function getPrice () { const basePrice = _quantity * _itemPrice; let discountFactor; if(basePrice > 100){ discountFactor = 0.95; } else { discountFactor = 0.98; } return basePrice * discountFactor; } good ✅ //重构后 function getPrice () { return basePrice() * discountFactor(); } function basePrice () { return _quantity * _itemPrice; } function discountFactor () { if(basePrice() > 100){ return 0.95; } else { return 0.98; } }
-
对象引用比较,作为参数传递的对象的内存地址,与用于判断相等的对象所引用的内存位置不同
function checkAge(data) { if (data === { age: 18 }) { console.log('You are an adult!') } else if (data == { age: 18 }) { console.log('You are still an adult.') } else { console.log(`Hmm.. You don't have an age I guess`) } } bad : ❌ checkAge({ age: 18 }); //输出 Hmm.. You don't have an age I guess
-
变量提升注意,const/let 块级作用域,var函数作用域
var有初始化提升,但是let/const没有
赋值为对象的 const 变量不能再被重新赋值 为其他引用值,但对象的键则不受限制bad : ❌ for (var i = 0; i < 10; ++i) {} console.log(i); // 10 for(var i=0;i< 10;i++){ setTimeout(function(){ console.log(i); },100) } // 10次都是输出 10 good ✅ for (let j = 0; j < 10; ++j) {} console.log(j); // ReferenceError: j 没有定义 for(let i=0;i< 10;i++){ setTimeout(function(){ console.log(i); },100) } //输出 0,1,2,3,4,5,6,7,8,9
-
this的使用,优先选择箭头函数
箭头函数没有自己的 thisbad : ❌ function Queen() { this.royaltyName = 'Elizabeth'; // this 引用 window 对象 setTimeout(function() { console.log(this.royaltyName); }, 1000); } new Queen(); // undefined good:✅ function King() { this.royaltyName = 'Henry'; // this 引用 King 的实例 setTimeout(() => console.log(this.royaltyName), 1000); } new King(); // Henry
-
使用"."来访问对象属性,当访问属性是变量时使用[]
-
尊重对象所有权,不修改内置对象,如Object Array
在 JavaScript 中,永远不要污染全局,会在生产环境中产生难以预料的 bug。举个例子,比如你在 Array.prototype 上新增一个 diff 方法来判断两个数组的不同。而你同事也打算做类似的事情,不过他的 diff 方法是用来判断两个数组首位元素的不同。很明显你们方法会产生冲突,遇到这类问题我们可以用 ES2015/ES6 的语法来对 Array 进行扩展。
bad : ❌ Array.prototype.diff = function diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem)); }; good ✅ class SuperArray extends Array { diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem)); } }
-
使用对象字面量的简写形式和解构赋值
字面量 bad : ❌ let obj = new Object(); good ✅ let obj = {}; 解构赋值: let someArray = [1,2,3] bad : ❌ let first = someArray[0]; let second = someArray[1]; let third = someArray[2]; good ✅ let [first,second,third] = someArray;
-
拼接字符串
bad : ❌ const name = '小明'; const score = 59; let result = ''; if(score > 60){ result = `${name}的考试成绩及格`; }else{ result = `${name}的考试成绩不及格`; } good ✅ const name = '小明'; const score = 59; const result = `${name}${score > 60?'的考试成绩及格':'的考试成绩不及格'}`;
-
使用 可选链?. 和 空位合并运算符
const person = { info: { name: 'ricky' } } 例如我要获取一个不存在属性 bad : ❌ const age = person && person.detail && person.detail.age // undefined good ✅ // 可选链 const age = person?.detail?.age // undefined
使用||运算符,只要左边是假值(0、''、false、undefinde、null),就会返回右边的数据
而??和||最大的区别是,在??这,只有undefined和null才算假值const name = 0 || 'ricky' // ricky const name = 0 ?? 'ricky' // 0 const name = '' || 'ricky' // ricky const name = '' ?? 'ricky' // '' const name = false || 'ricky' // ricky const name = false ?? 'ricky' // false const name = undefined || 'ricky' // ricky const name = undefined ?? 'ricky' // ricky const name = null || 'ricky' // ricky const name = null ?? 'ricky' // ricky
URL参数
-
URL参数需要转义
转义URI组件中的字符 encodeURIComponent()bad : ❌ location.href="https://www.xx.com/a/?url=http://localhost:8081?user=ricky" good ✅ location.href=`https://www.xx.com/a/?url=${encodeURIComponent('http://localhost:8081?user=ricky')}`
-
URL地址长度不要超过512个字符
目前公开信息获取的浏览器长度限制是2048,在开发中,低端机型适配中,发现512个字符是个临界值;
如果比较长的报文,建议跳转的时候,- 以FORM表单的方式提交参数
- 后端协商相关信息存储在后端,URL地址只附带ID,后续根据ID查询具体信息
-
URL地址不能包含敏感信息,例如身份证等
-
bad : ❌ let url = 'https://www.xx.com/?idCard=310000200001010101' good ✅ let url = 'https://www.xx.com/?idCard=310000********0101' 做脱敏处理或者加密处理