1、在使用javaScript的时候,遵循以下命名规范
2、必须以字母或下划线开头,中间可以是数字、字符或下划线
,也能以 $ 和 _ 符号开头(不过我们不推荐这么做)
3、变量名不能包含空格等符号,严格区分大小写
4、不能使用javaScript关键字作为变量名,如:function
1、变量是用于存储信息的"容器"
2、在 JavaScript 中创建变量通常称为"声明"变量
3、我们使用 var 关键词来声明变量
4、变量声明之后,该变量是空的(它没有值)如需向变量赋值,请使用等号
5、不过,您也可以在声明变量时对其赋值
1、可以在一条语句中声明很多变量。该语句以 var 开头,并使用逗号分隔变量即可
1、如果重新声明 JavaScript 变量,该变量的值不会丢失:
2、在以下两条语句执行后,变量 carname 的值依然是 "Volvo":
文已经原作者Shadeed 授权翻译。
变量无处不在,即使我们在写一个小的函数,或者一个应用程序:我们总是先声明,分配和使用变量。编写好的变量可提高代码的可读性和易维护性。
在本文中,主要介绍 5种有关在 JavaScript 中声明和使用变量的最佳做法。
我使用const或let声明变量,两者之间的主要区别是const变量需要一个初始值,并且一旦初始化就无法重新分配其值。
另一方面,let声明不需要初始值,我们可以多次重新分配其值。
// const 需要初始化
const pi = 3.14;
// 不能重新分配const
pi = 4.89; // throws "TypeError: Assignment to constant variable"
另一方面,let声明不需要初始值,我们可以多次重新分配其值。
// let 初始化是可选的
let result;
// let can be reassigned
result = 14;
result = result * 2;
选择变量的声明类型时的一个好习惯是首选const,否则使用let。
function myBigFunction(param1, param2) {
/* lots of stuff... */
const result = otherFunction(param1);
/* lots of stuff... */
return something;
}
例如,如果我们正在查看函数体,并看到const result = ...声明:
function myBigFunction(param1, param2) {
/* lots of stuff... */
const result = otherFunction(param1);
/* lots of stuff... */
return something;
}
不知道myBigFunction()内部会发生什么, 我们可以得出结论,result 变量只分配了一次,声明之后是只读的。
在其他情况下,如果必须在执行过程中多次重新分配变量,则可以使用let声明。
变量存在于它们所创建的作用域内。代码块和函数体为const和let变量创建一个作用域。提高变量可读性的一个好习惯是将变量保持在最小作用域内。
例如,以下函数是二进制搜索算法的实现:
function binarySearch(array, search) {
let middle;
let middleItem;
let left = 0;
let right = array.length - 1;
while(left <= right) {
middle = Math.floor((left + right) / 2);
middleItem = array[middle];
if (middleItem === search) {
return true;
}
if (middleItem < search) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return false;
}
binarySearch([2, 5, 7, 9], 7); // => true
binarySearch([2, 5, 7, 9], 1); // => false
middle和middleItem变量在函数体的开头声明。因此,这些变量在binarySearch()函数体创建的整个作用域内都是可用的。
middle变量保留二进制搜索的中间索引,而middleItem变量保留二进制搜索的中间索引。
但是,middle和middleItem变量只在while循环代码块中使用。所以为什么不直接在while代码块中声明这些变量呢?
function binarySearch(array, search) {
let left = 0;
let right = array.length - 1;
while(left <= right) {
const middle = Math.floor((left + right) / 2);
const middleItem = array[middle];
if (middleItem === search) {
return true;
}
if (middleItem < search) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return false;
}
现在,middle和middleItem变量仅存在于使用变量的作用域。他们的生命周期和生命周期极短,因此更容易推断其作用。
我强烈希望在函数主体的顶部声明所有变量,尤其是在函数较大的情况下。不幸的是,这种做法的缺点是使我在函数中使用的意图变量变得混乱。
尽量在接近使用位置的地方声明变量。这样,我们就不用猜了:嘿,我看到了这里声明的变量,但是它在哪里被使用了。
假设我们有一个函数,该函数的主体中包含很多语句。我们可以在函数的开头声明并初始化变量结果,但是只能在return语句中使用result:
function myBigFunction(param1, param2) {
const result = otherFunction(param1);
let something;
/*
* calculate something...
*/
return something + result;
}
问题在于result 变量在开头声明,但仅在结尾使用,没有足够的理由在开始时声明该变量。
让我们通过将result 变量声明移到return语句之前来改进这个函数
function myBigFunction(param1, param2) {
let something;
/*
* calculate something...
*/
const result = otherFunction(param1);
return something + result;
}
现在,result变量在函数中有了它的正确位置。
从良好的变量命名的众多规则中,我区分出两个重要的规则。
第一个很简单:使用驼峰命名为变量取名,并且在命名所有变量时保持一致。
const message = 'Hello';
const isLoading = true;
let count
有特殊含义的数字或字符串,变量命名通常是大写的,在单词之间加下划线,以区别于常规变量
const SECONDS_IN_MINUTE = 60;
const GRAPHQL_URI = 'http://site.com/graphql';
第二条规则,在变量命名中,我认为这是最重要的:变量名称应明确无歧义地指出哪些数据保存了该变量。
以下是一些很好的变量命名示例:
let message = 'Hello';
let isLoading = true;
let count;
message 名称表示此变量包含某种消息,很可能是字符串。
isLoading相同,布尔值指示加载是否在进行中。
count变量表示保存一些计数结果的数字类型变量。
选择一个明确表明其角色的变量名。
举个例子,这样就能看出区别了。假设看到了这样一个函数:
function salary(ws, r) {
let t = 0;
for (w of ws) {
t += w * r;
}
return t;
}
你能总结出这个函数的作用吗?像ws、r、t、w这样的变量名几乎没有说明它们的意图。
相反,相同的函数,但使用了解释性变量命名
function calculateTotalSalary(weeksHours, ratePerHour) {
let totalSalary = 0;
for (const weekHours of weeksHours) {
const weeklySalary = weekHours * ratePerHour;
totalSalary += weeklySalary;
}
return totalSalary;
}
该代码清楚地说明了它的作用。这就是良好命名的力量。
我比较少注释代码。我更喜欢编写代码即解释的风格,通过对变量、属性、函数和类的良好命名来表达意图。
编写自文档代码的一个好习惯是引入中间变量。在处理长表达式时很有用。
考虑以下表达式:
const sum = val1 * val2 + val3 / val4;
我们引入两个中间变量,增强长表达式的可读性:
const multiplication = val1 * val2;
const division = val3 / val4;
const sum = multiplication + division;
另外,让我们回顾一下二进制搜索实现算法:
function binarySearch(array, search) {
let left = 0;
let right = array.length - 1;
while(left <= right) {
const middle = Math.floor((left + right) / 2);
const middleItem = array[middle];
if (middleItem === search) {
return true;
}
if (middleItem < search) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return false;
}
这里middleItem是一个保存中间项目的中间变量。使用中间变量MiddleItem而不是直接使用项目访问器array [middle]可读性更好。
与缺少middleItem解释变量的函数版本进行比较:
function binarySearch(array, search) {
let left = 0;
let right = array.length - 1;
while(left <= right) {
const middle = Math.floor((left + right) / 2);
if (array[middle] === search) {
return true;
}
if (array[middle] < search) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return false;
}
这个版本,没有解释变量,可读性就比较差。
变量无处不在,我们总是先声明,分配和使用变量。
在 JS 中使用变量时,第一个好的做法是使用const,否则使用let
试着保持变量的作用域尽可能小。同样,将变量声明往尽可能靠近使用位置。
不要低估好的命名的重要性。始终遵循这样的规则:变量名应该清晰而明确地表示保存变量的数据。不要害怕使用较长的名字:最好是清晰而不是简洁。
最后,少使用注释,多写写代码即的效果 。在高度复杂的地方,我更喜欢引入中间变量。
作者:Shadeed 译者:前端小智 来源:dmitripavlutin
原文:https://dmitripavlutin.com/javascript-variables-practices/
者:ryanmcdermott
翻译:前端小智
链接:(英文)https://github.com/ryanmcdermott/clean-code-javascript#table-of-contents
在开发中,变量名,函数名一般要做到清晰明了,尽量做到看名字就能让人知道你的意图,所以变量和函数命名是挺重要,今天来看看如果较优雅的方式给变量和函数命名。
// 不好的写法
const yyyymmdstr = moment().format("YYYY/MM/DD");
// 好的写法
const currentDate = moment().format("YYYY/MM/DD");
// 不好的写法
getUserInfo();
getClientData();
getCustomerRecord();
// 好的写法
getUser();
我们读的会比我们写的多得多,所以如果命名太过随意不仅会给后续的维护带来困难,也会伤害了读我们代码的开发者。让你的变量名可被读取,像 buddy.js 和 ESLint 这样的工具可以帮助识别未命名的常量。
// 不好的写法
// 86400000 的用途是什么?
setTimeout(blastOff, 86400000);
// 好的写法
const MILLISECONDS_IN_A_DAY = 86_400_000;
setTimeout(blastOff, MILLISECONDS_IN_A_DAY);
// 不好的写法
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(
address.match(cityZipCodeRegex)[1],
address.match(cityZipCodeRegex)[2]
);
// 好的写法
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);
显式用于隐式
// 不好的写法
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(l => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
// 等等,“l”又是什么?
dispatch(l);
// 好的写法
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(location => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
dispatch(location);
});
大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】。
如果类名/对象名已经说明了,就无需在变量名中重复。
// 不好的写法
const Car = {
carMake: "Honda",
carModel: "Accord",
carColor: "Blue"
};
function paintCar(car) {
car.carColor = "Red";
}
// 好的写法
const Car = {
make: "Honda",
model: "Accord",
color: "Blue"
};
function paintCar(car) {
car.color = "Red";
}
// 不好的写法
function createMicrobrewery(name) {
const breweryName = name || "Hipster Brew Co.";
// ...
}
// 好的写法
function createMicrobrewery(name = "Hipster Brew Co.") {
// ...
}
限制函数参数的数量是非常重要的,因为它使测试函数变得更容易。如果有三个以上的参数,就会导致组合爆炸,必须用每个单独的参数测试大量不同的情况。
一个或两个参数是理想的情况,如果可能,应避免三个参数。 除此之外,还应该合并。大多数情况下,大于三个参数可以用对象来代替。
// 不好的写法
function createMenu(title, body, buttonText, cancellable) {
// ...
}
createMenu("Foo", "Bar", "Baz", true);
// 好的写法
function createMenu({ title, body, buttonText, cancellable }) {
// ...
}
createMenu({
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
});
这是目前为止软件工程中最重要的规则。当函数做不止一件事时,它们就更难组合、测试和推理。可以将一个函数隔离为一个操作时,就可以很容易地重构它,代码也会读起来更清晰。
// 不好的写法
function emailClients(clients) {
clients.forEach(client => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
// 好的写法
function emailActiveClients(clients) {
clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
// 不好的写法
function addToDate(date, month) {
// ...
}
const date = new Date();
// 从函数名称很难知道添加什么
addToDate(date, 1);
// 好的写法
function addMonthToDate(month, date) {
// ...
}
const date = new Date();
addMonthToDate(1, date);
当有一个以上的抽象层次函数,意味该函数做得太多了,需要将函数拆分可以实现可重用性和更简单的测试。
// 不好的写法
function parseBetterJSAlternative(code) {
const REGEXES = [
// ...
];
const statements = code.split(" ");
const tokens = [];
REGEXES.forEach(REGEX => {
statements.forEach(statement => {
// ...
});
});
const ast = [];
tokens.forEach(token => {
// lex...
});
ast.forEach(node => {
// parse...
});
}
// 好的写法
function parseBetterJSAlternative(code) {
const tokens = tokenize(code);
const syntaxTree = parse(tokens);
syntaxTree.forEach(node => {
// parse...
});
}
function tokenize(code) {
const REGEXES = [
// ...
];
const statements = code.split(" ");
const tokens = [];
REGEXES.forEach(REGEX => {
statements.forEach(statement => {
tokens.push(/* ... */);
});
});
return tokens;
}
function parse(tokens) {
const syntaxTree = [];
tokens.forEach(token => {
syntaxTree.push(/* ... */);
});
return syntaxTree;
}
大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】。
尽量避免重复的代码,重复的代码是不好的,它意味着如果我们需要更改某些逻辑,要改很多地方。
通常,有重复的代码,是因为有两个或多个稍有不同的事物,它们有很多共同点,但是它们之间的差异迫使我们编写两个或多个独立的函数来完成许多相同的事情。 删除重复的代码意味着创建一个仅用一个函数/模块/类就可以处理这组不同事物的抽象。
获得正确的抽象是至关重要的,这就是为什么我们应该遵循类部分中列出的 SOLID原则。糟糕的抽象可能比重复的代码更糟糕,所以要小心!说了这么多,如果你能做一个好的抽象,那就去做吧!不要重复你自己,否则你会发现自己在任何时候想要改变一件事的时候都要更新多个地方。
设计模式的六大原则有:
把这六个原则的首字母联合起来(两个 L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计。下面我们来分别看一下这六大设计原则。
不好的写法
function showDeveloperList(developers) {
developers.forEach(developer => {
const expectedSalary = developer.calculateExpectedSalary();
const experience = developer.getExperience();
const githubLink = developer.getGithubLink();
const data = {
expectedSalary,
experience,
githubLink
};
render(data);
});
}
function showManagerList(managers) {
managers.forEach(manager => {
const expectedSalary = manager.calculateExpectedSalary();
const experience = manager.getExperience();
const portfolio = manager.getMBAProjects();
const data = {
expectedSalary,
experience,
portfolio
};
render(data);
});
}
好的写法
function showEmployeeList(employees) {
employees.forEach(employee => {
const expectedSalary = employee.calculateExpectedSalary();
const experience = employee.getExperience();
const data = {
expectedSalary,
experience
};
switch (employee.type) {
case "manager":
data.portfolio = employee.getMBAProjects();
break;
case "developer":
data.githubLink = employee.getGithubLink();
break;
}
render(data);
});
}
不好的写法
const menuConfig = {
title: null,
body: "Bar",
buttonText: null,
cancellable: true
};
function createMenu(config) {
config.title = config.title || "Foo";
config.body = config.body || "Bar";
config.buttonText = config.buttonText || "Baz";
config.cancellable =
config.cancellable !== undefined ? config.cancellable : true;
}
createMenu(menuConfig);
好的写法
const menuConfig = {
title: "Order",
// User did not include 'body' key
buttonText: "Send",
cancellable: true
};
function createMenu(config) {
config = Object.assign(
{
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
},
config
);
// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
// ...
}
createMenu(menuConfig);
大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】。
标志告诉使用者,此函数可以完成多项任务,函数应该做一件事。 如果函数遵循基于布尔的不同代码路径,请拆分它们。
// 不好的写法
function createFile(name, temp) {
if (temp) {
fs.create(`./temp/${name}`);
} else {
fs.create(name);
}
}
// 好的写法
function createFile(name) {
fs.create(name);
}
function createTempFile(name) {
createFile(`./temp/${name}`);
}
如果函数除了接受一个值并返回另一个值或多个值以外,不执行任何其他操作,都会产生副作用。 副作用可能是写入文件,修改某些全局变量,或者不小心将你的所有资金都汇给了陌生人。
不好的写法
let name = "Ryan McDermott";
function splitIntoFirstAndLastName() {
name = name.split(" ");
}
splitIntoFirstAndLastName();
console.log(name); // ['Ryan', 'McDermott'];
好的写法
function splitIntoFirstAndLastName(name) {
return name.split(" ");
}
const name = "Ryan McDermott";
const newName = splitIntoFirstAndLastName(name);
console.log(name); // 'Ryan McDermott';
console.log(newName); // ['Ryan', 'McDermott'];
在JavaScript中,原始类型值是按值传递,而对象/数组按引用传递。 对于对象和数组,如果有函数在购物车数组中进行了更改(例如,通过添加要购买的商品),则使用该购物车数组的任何其他函数都将受到此添加的影响。 那可能很棒,但是也可能不好。 来想象一个糟糕的情况:
用户单击“购买”按钮,该按钮调用一个purchase 函数,接着,该函数发出一个网络请求并将cart数组发送到服务器。由于网络连接不好,purchase函数必须不断重试请求。现在,如果在网络请求开始之前,用户不小心点击了他们实际上不需要的项目上的“添加到购物车”按钮,该怎么办?如果发生这种情况,并且网络请求开始,那么购买函数将发送意外添加的商品,因为它有一个对购物车数组的引用,addItemToCart函数通过添加修改了这个购物车数组。
一个很好的解决方案是addItemToCart总是克隆cart数组,编辑它,然后返回克隆。这可以确保购物车引用的其他函数不会受到任何更改的影响。
关于这种方法有两点需要注意:
1.可能在某些情况下,我们确实需要修改输入对象,但是当我们采用这种编程实践时,会发现这种情况非常少见,大多数东西都可以被改造成没有副作用。
2.就性能而言,克隆大对象可能会非常昂贵。 幸运的是,在实践中这并不是一个大问题,因为有很多很棒的库使这种编程方法能够快速进行,并且不像手动克隆对象和数组那样占用大量内存。
// 不好的写法
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};
// 好的写法
const addItemToCart = (cart, item) => {
return [...cart, { item, date: Date.now() }];
};
污染全局变量在 JS 中是一种不好的做法,因为可能会与另一个库发生冲突,并且在他们的生产中遇到异常之前,API 的用户将毫无用处。 让我们考虑一个示例:如果想扩展 JS 的原生Array方法以具有可以显示两个数组之间差异的diff方法,该怎么办? 可以将新函数写入Array.prototype,但它可能与另一个尝试执行相同操作的库发生冲突。 如果其他库仅使用diff来查找数组的第一个元素和最后一个元素之间的区别怎么办? 这就是为什么只使用 ES6 类并简单地扩展Array全局会更好的原因。
// 不好的写法
Array.prototype.diff = function diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
};
// 好的写法
class SuperArray extends Array {
diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
}
}
JavaScript不像Haskell那样是一种函数式语言,但它具有函数式的风格。函数式语言可以更简洁、更容易测试。如果可以的话,尽量喜欢这种编程风格。
不好的写法
const programmerOutput = [
{
name: "Uncle Bobby",
linesOfCode: 500
},
{
name: "Suzie Q",
linesOfCode: 1500
},
{
name: "Jimmy Gosling",
linesOfCode: 150
},
{
name: "Gracie Hopper",
linesOfCode: 1000
}
];
let totalOutput = 0;
for (let i = 0; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;
}
好的写法
const programmerOutput = [
{
name: "Uncle Bobby",
linesOfCode: 500
},
{
name: "Suzie Q",
linesOfCode: 1500
},
{
name: "Jimmy Gosling",
linesOfCode: 150
},
{
name: "Gracie Hopper",
linesOfCode: 1000
}
];
const totalOutput = programmerOutput.reduce(
(totalLines, output) => totalLines + output.linesOfCode,
0
);
// 不好的写法
if (fsm.state === "fetching" && isEmpty(listNode)) {
// ...
}
// 好的写法
function shouldShowSpinner(fsm, listNode) {
return fsm.state === "fetching" && isEmpty(listNode);
}
if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
// ...
}
大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】。
// 不好的写法
function isDOMNodeNotPresent(node) {
// ...
}
if (!isDOMNodeNotPresent(node)) {
// ...
}
// 好的写法
function isDOMNodePresent(node) {
// ...
}
if (isDOMNodePresent(node)) {
// ...
}
这似乎是一个不可能完成的任务。一听到这个,大多数人会说,“没有if语句,我怎么能做任何事情呢?”答案是,你可以在许多情况下使用多态性来实现相同的任务。
第二个问题通常是,“那很好,但是我为什么要那样做呢?”答案是上面讲过一个概念:一个函数应该只做一件事。当具有if语句的类和函数时,这是在告诉你的使用者该函数执行不止一件事情。
不好的写法
class Airplane {
// ...
getCruisingAltitude() {
switch (this.type) {
case "777":
return this.getMaxAltitude() - this.getPassengerCount();
case "Air Force One":
return this.getMaxAltitude();
case "Cessna":
return this.getMaxAltitude() - this.getFuelExpenditure();
}
}
}
好的写法
class Airplane {
// ...
}
class Boeing777 extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude() - this.getPassengerCount();
}
}
class AirForceOne extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude();
}
}
class Cessna extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude() - this.getFuelExpenditure();
}
}
JavaScript 是无类型的,这意味着函数可以接受任何类型的参数。 有时q我们会被这种自由所困扰,并且很想在函数中进行类型检查。 有很多方法可以避免这样做。 首先要考虑的是一致的API。
// 不好的写法
function travelToTexas(vehicle) {
if (vehicle instanceof Bicycle) {
vehicle.pedal(this.currentLocation, new Location("texas"));
} else if (vehicle instanceof Car) {
vehicle.drive(this.currentLocation, new Location("texas"));
}
}
// 好的写法
function travelToTexas(vehicle) {
vehicle.move(this.currentLocation, new Location("texas"));
}
现代浏览器在运行时做了大量的优化工作。很多时候,如果你在优化,那么你只是在浪费时间。有很好的资源可以查看哪里缺乏优化,我们只需要针对需要优化的地方就行了。
// 不好的写法
// 在旧的浏览器上,每一次使用无缓存“list.length”的迭代都是很昂贵的
// 会为“list.length”重新计算。在现代浏览器中,这是经过优化的
for (let i = 0, len = list.length; i < len; i++) {
// ...
}
// 好的写法
for (let i = 0; i < list.length; i++) {
// ...
}
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
*请认真填写需求信息,我们会在24小时内与您取得联系。