We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
作者:Nick Scialli 译者:前端小智 来源:hackernoon
阿里云最近在做活动,低至2折,真心觉得很划算了,可以点击本条内容或者链接进行参与: https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
为了保证的可读性,本文采用意译而非直译。
本文介绍 JS 比较重要的12个概念,但绝对不是说 JS开发人员只需要知道这些就可以了。
理解 JS 如何给变量赋值可以帮助我们减少一些不必要的 bug。相反,如果,不理解这一点,可能很容易地编写被无意中更改值的代码。
JS 总是按照值来给变量赋值。 这一部分非常重要:当指定的值是 JavaScript 的五种基本类型之一(即 Boolean,null,undefined,String 和 Number)时,分配是实际值。 但是,当指定的值是 Array,Function或Object时,将内存中对象的引用地址赋值给变量。
Boolean
null
undefined
String
Number
Array
Function
Object
在以下代码段中,使用 var1 对 var2 进行赋值。 由于var1是基本类型(String),因此 var2 的值等于 var1 字符中值,但 var1 和 var2 之间是独立的变量,不会影响彼此。 因此,重新赋值var2对var1没有影响。
var1
var2
let var1 = '小智; let var2 = var1; var2 = '王大冶'; console.log(var1); // 小智 console.log(var2); // 王大冶
接着,与对象赋值进行比较。
let var1 = { name: '小智' } let var2 = var1; var2.name = '王大冶'; console.log(var1); // {name: "王大冶"} console.log(var2); // {name: "王大冶"}
如果你期望它会像原始类型赋值那样,很可能会出问题!如果你创建了一个无意中会改变对象的函数,就会出现一些非预期的行为。
闭包是一个重要的 JS 模式,可以私有访问变量。在本例中,createGreeter返回一个匿名函数,这个函数可以访问参数 greeting。在后续的调用中,sayHello 有权访问这个 greeting 参数。
createGreeter
greeting
sayHello
function createGreeter(greeting) { return function(name) { console.log(greeting + ', ' + name); } } const sayHello = createGreeter('你好'); sayHello('小智'); // 你好, 小智
在更真实的场景中,咱们可以设想一个初始函数apiConnect(apiKey),它返回一些使用API key的方法。在这种情况下,apiKey 只需要提供一次即可。
apiConnect(apiKey)
API key
apiKey
function apiConnect(apiKey) { function get(route) { return fetch(`${route}?key=${apiKey}`); } function post(route, params) { return fetch(route, { method: 'POST', body: JSON.stringify(params), headers: { 'Authorization': `Bearer ${apiKey}` } }) } return { get, post } } const api = apiConnect('my-secret-key'); // 不再需要包含 apiKey api.get('http://www.example.com/get-endpoint'); api.post('http://www.example.com/post-endpoint', { name: 'Joe' });
JS 参数解构可以从对象中干中提取所需属性的常用方法。
const obj = { name: '小智', food: '鸡腿' } const { name, food } = obj; console.log(name, food); // 小智 鸡腿
如果需要取别名,可以使用如下方式:
const obj = { name: '小智', food: '鸡腿' } const { name: myName, food: myFood } = obj; console.log(myName, myFood); // 小智 鸡腿
解构经常也用于直接用于提取传给函数的参数。如果你熟悉 React,可能已经见过这个:
const person = { name: '小智', age: 24 } function introduce({ name, age }) { console.log(`我是 ${name} ,今天 ${age} 岁了!`); } console.log(introduce(person));// 我是 小智 ,今天 24 岁了!
ES6的一个常用之一的特性就是展开(...)运算符了,在下面的例子中,Math.max 不能应用于 arr 数组,因为它不将数组作为参数,但它可以将各个元素作为参数传入。展开运算符...可用于提取数组的各个元素。
...
Math.max
arr
const arr = [4, 6, -1, 3, 10, 4]; const max = Math.max(...arr); console.log(max); // 10
剩余参数语法和展开语法看起来的一样的,不同的是展开语法是为了解构数组和对象;而剩余参数和展开运算符是相反的,剩余参数收集多个参数合成一个数组。
function myFunc(...args) { console.log(args[0] + args[1]); } myFunc(1, 2, 3, 4); // 3
rest parameters 和 arguments 的区别
JS 数组方法map、filter和reduce容易混淆,这些都是转换数组或返回聚合值的有用方法。
map
filter
reduce
map:返回一个数组,其中每个元素都使用指定函数进行过转换。
const arr = [1, 2, 3, 4, 5, 6]; const mapped = arr.map(el => el + 20); console.log(mapped); // [21, 22, 23, 24, 25, 26]
filter:返回一个数组,只有当指定函数返回 true 时,相应的元素才会被包含在这个数组中。
const arr = [1, 2, 3, 4, 5, 6]; const filtered = arr.filter(el => el === 2 || el === 4); console.log(filtered); // [2, 4]
reduce:按函数中指定的值累加
const arr = [1, 2, 3, 4, 5, 6]; const reduced = arr.reduce((total, current) => total + current); console.log(reduced); // 21
find:返回与指定条件匹配的第一个实例,如果查到不会继续查找其他匹配的实例。
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const found = arr.find(el => el > 5); console.log(found); // 6
注意,虽然5之后的所有元素都满足条件,但是 find 只返回第一个匹配的元素。当咱们发现匹配项并想中断for循环,在这种情况下,find 就可以派上用场了。
5
find
for
findIndex:这与find几乎完全相同,但不是返回第一个匹配元素,而是返回第一个匹配元素的索引。
const arr = ['Nick', 'Frank', 'Joe', 'Frank']; const foundIndex = arr.findIndex(el => el === 'Frank'); console.log(foundIndex); // 1
indexOf:与findIndex几乎完全相同,但它不是将函数作为参数,而是采用一个简单的值。 当你需要更简单的逻辑并且不需要使用函数来检查是否存在匹配时,可以使用此方法。
findIndex
const arr = ['Nick', 'Frank', 'Joe', 'Frank']; const foundIndex = arr.indexOf('Frank'); console.log(foundIndex); // 1
push:这是一个相对简单的方法,它将一个项添加到数组的末尾。它就地修改数组,函数本身会返回添加到数组中的项。
let arr = [1, 2, 3, 4]; const pushed = arr.push(5); console.log(arr); // [1, 2, 3, 4, 5] console.log(pushed); // 5
pop:这将从数组中删除最后一项。同样,它在适当的位置修改数组,函数本身返回从数组中删除的项。
let arr = [1, 2, 3, 4]; const popped = arr.pop(); console.log(arr); // [1, 2, 3] console.log(popped);// 4
shift:从数组中删除第一项。同样,它在适当的位置修改数组。函数本身返回从数组中删除的项。
let arr = [1, 2, 3, 4]; const shifted = arr.shift(); console.log(arr); // [2, 3, 4] console.log(shifted); // 1
unshift:将一个或多个元素添加到数组的开头。同样,它在适当的位置修改数组。与许多其他方法不同,函数本身返回数组的新长度。
let arr = [1, 2, 3, 4]; const unshifted = arr.unshift(5, 6, 7); console.log(arr); // [5, 6, 7, 1, 2, 3, 4] console.log(unshifted); // 7
**splice:**通过删除或替换现有元素和/或添加新元素来更改数组的内容,此方法会修改了数组本身。
下面的代码示例的意思是:在数组的位置 1 上删除 0 个元素,并插入 b。
1
0
b
let arr = ['a', 'c', 'd', 'e']; arr.splice(1, 0, 'b')
slice:从指定的起始位置和指定的结束位置之前返回数组的浅拷贝。 如果未指定结束位置,则返回数组的其余部分。 重要的是,此方法不会修改数组,而是返回所需的子集。
let arr = ['a', 'b', 'c', 'd', 'e']; const sliced = arr.slice(2, 4); console.log(sliced); // ['c', 'd'] console.log(arr); // ['a', 'b', 'c', 'd', 'e']
**sort:**根据提供的函数对数组进行排序。这个方法就地修改数组。如果函数返回负数或 0,则顺序保持不变。如果返回正数,则交换元素顺序。
let arr = [1, 7, 3, -1, 5, 7, 2]; const sorter = (firstEl, secondEl) => firstEl - secondEl; arr.sort(sorter); console.log(arr); // [-1, 1, 2, 3, 5, 7, 7]
生成器是一种特殊的行为,实际上是一种设计模式,咱们通过调用 next() 方法来遍历一组有序的值。想象一下,例如使用遍历器对数组[1,2,3,4,5]进行遍历。第一次调用 next() 方法返回1,第二次调用 next() 方法返回2,以此类推。当数组中的所有值都返回后,调用 next() 方法将返回 null 或 false 或其它可能的值用来表示数组中的所有元素都已遍历完毕。
next()
[1,2,3,4,5]
2
false
function* greeter() { yield 'Hi'; yield 'How are you?'; yield 'Bye'; } const greet = greeter(); console.log(greet.next().value); // 'Hi' console.log(greet.next().value); // 'How are you?' console.log(greet.next().value); // 'Bye' console.log(greet.next().value); // undefined
使用生成器生成无限个值:
function* idCreator() { let i = 0; while (true) yield i++; } const ids = idCreator(); console.log(ids.next().value); // 0 console.log(ids.next().value); // 1 console.log(ids.next().value); // 2 // etc...
大家一定要知道 JS 中的严格相等运算符(===)和相等运算符(==)之间的区别。 == 运算符在比较值之前会进行类型转换,而 === 运算符在比较之前不会进行任何类型转换。
===
==
console.log(0 == '0'); // true console.log(0 === '0'); // false
JS 新手经常所犯的错误是直接比较对象。变量指向内存中对象的引用,而不是对象本身! 实际比较它们的一种方法是将对象转换为 JSON 字符串。 这有一个缺点:对象属性顺序不能保证,比较对象的一种更安全的方法是引入专门进行深度对象比较的库(例如,lodash 中 isEqual)。
下面的对象看起来是相等的,但实际上它们指向不同的引用。
const joe1 = { name: '小智' }; const joe2 = { name: '小智' }; console.log(joe1 === joe2); // false
相反,下面的计算结果为true,因为一个对象被设置为与另一个对象相等,因此指向相同的引用(内存中只有一个对象)。
true
const joe1 = { name: '小智' }; const joe2 = joe1; console.log(joe1 === joe2); // true
相反,以下计算结果为true,因为一个对象设置为等于另一个对象,因此指向相同的引用(内存中只有一个对象)。
const joe1 = { name: 'Joe' }; const joe2 = joe1; console.log(joe1 === joe2); // true
很多人都被 JS 回调函数吓倒了。�它们很简单,举个例子,console.log 函数作为回调传递给myFunc,它在setTimeout完成时执行。
console.log
myFunc
setTimeout
function myFunc(text, callback) { setTimeout(function() { callback(text); }, 2000); } myFunc('Hello world!', console.log); // 'Hello world!'
一旦你理解了 JS 回调,很快就会发现自己陷入了“回调地狱”中。这个时候可以使用 promise,将异步逻辑包装在 promise 中,成功时 resolve 或在失败时reject 使用“then”来处理成功的情况,使用catch来处理异常。
resolve
reject
then
catch
const myPromise = new Promise(function(res, rej) { setTimeout(function(){ if (Math.random() < 0.9) { return res('Hooray!'); } return rej('Oh no!'); }, 1000); }); myPromise .then(function(data) { console.log('Success: ' + data); }) .catch(function(err) { console.log('Error: ' + err); }); // 如果 Math.random() 返回的值小于 0.9,则打印以下内容 // "Success: Hooray!" // 相反,则打印以下内容 // "Error: On no!"
在掌握了 promise 的用法后,你可能也会喜欢 async await,它只是一种基于 promise 的“语法糖”。在下面的示例中,咱们创建了一个 async 函数,并 await greeter。
async await
async
await greete
const greeter = new Promise((res, rej) => { setTimeout(() => res('Hello world!'), 2000); }) async function myFunc() { const greeting = await greeter; console.log(greeting); } myFunc(); // 'Hello world!'
这些概念是我们掌握 JS 需要懂得的知识。你认为还有哪些概念是重要的呢?欢迎留言讨论。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://hackernoon.com/12-javascript-concepts-that-will-level-up-your-development-skills-b37d16ad7104
阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq449245884/xiaozhi
因为篇幅的限制,今天的分享只到这里。如果大家想了解更多的内容的话,可以去扫一扫每篇文章最下面的二维码,然后关注咱们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,一般都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励
The text was updated successfully, but these errors were encountered:
No branches or pull requests
阿里云最近在做活动,低至2折,真心觉得很划算了,可以点击本条内容或者链接进行参与:
https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
为了保证的可读性,本文采用意译而非直译。
本文介绍 JS 比较重要的12个概念,但绝对不是说 JS开发人员只需要知道这些就可以了。
1.变量赋值 (值 vs 引用)
理解 JS 如何给变量赋值可以帮助我们减少一些不必要的 bug。相反,如果,不理解这一点,可能很容易地编写被无意中更改值的代码。
JS 总是按照值来给变量赋值。 这一部分非常重要:当指定的值是 JavaScript 的五种基本类型之一(即
Boolean
,null
,undefined
,String
和Number
)时,分配是实际值。 但是,当指定的值是Array
,Function
或Object
时,将内存中对象的引用地址赋值给变量。在以下代码段中,使用
var1
对var2
进行赋值。 由于var1
是基本类型(String),因此var2
的值等于var1
字符中值,但 var1 和 var2 之间是独立的变量,不会影响彼此。 因此,重新赋值var2
对var1
没有影响。接着,与对象赋值进行比较。
如果你期望它会像原始类型赋值那样,很可能会出问题!如果你创建了一个无意中会改变对象的函数,就会出现一些非预期的行为。
2.闭包
闭包是一个重要的 JS 模式,可以私有访问变量。在本例中,
createGreeter
返回一个匿名函数,这个函数可以访问参数greeting
。在后续的调用中,sayHello
有权访问这个 greeting 参数。在更真实的场景中,咱们可以设想一个初始函数
apiConnect(apiKey)
,它返回一些使用API key
的方法。在这种情况下,apiKey
只需要提供一次即可。3.解构
JS 参数解构可以从对象中干中提取所需属性的常用方法。
如果需要取别名,可以使用如下方式:
解构经常也用于直接用于提取传给函数的参数。如果你熟悉 React,可能已经见过这个:
4. 展开运算
ES6的一个常用之一的特性就是展开(
...
)运算符了,在下面的例子中,Math.max
不能应用于arr
数组,因为它不将数组作为参数,但它可以将各个元素作为参数传入。展开运算符...
可用于提取数组的各个元素。5. 剩余参数
剩余参数语法和展开语法看起来的一样的,不同的是展开语法是为了解构数组和对象;而剩余参数和展开运算符是相反的,剩余参数收集多个参数合成一个数组。
rest parameters 和 arguments 的区别
6. 数组方法
map、filter、reduce
JS 数组方法
map
、filter
和reduce
容易混淆,这些都是转换数组或返回聚合值的有用方法。map:返回一个数组,其中每个元素都使用指定函数进行过转换。
filter:返回一个数组,只有当指定函数返回 true 时,相应的元素才会被包含在这个数组中。
reduce:按函数中指定的值累加
find, findIndex, indexOf
find:返回与指定条件匹配的第一个实例,如果查到不会继续查找其他匹配的实例。
注意,虽然
5
之后的所有元素都满足条件,但是find
只返回第一个匹配的元素。当咱们发现匹配项并想中断for
循环,在这种情况下,find
就可以派上用场了。findIndex:这与
find
几乎完全相同,但不是返回第一个匹配元素,而是返回第一个匹配元素的索引。indexOf:与
findIndex
几乎完全相同,但它不是将函数作为参数,而是采用一个简单的值。 当你需要更简单的逻辑并且不需要使用函数来检查是否存在匹配时,可以使用此方法。push, pop, shift, unshift
push:这是一个相对简单的方法,它将一个项添加到数组的末尾。它就地修改数组,函数本身会返回添加到数组中的项。
pop:这将从数组中删除最后一项。同样,它在适当的位置修改数组,函数本身返回从数组中删除的项。
shift:从数组中删除第一项。同样,它在适当的位置修改数组。函数本身返回从数组中删除的项。
unshift:将一个或多个元素添加到数组的开头。同样,它在适当的位置修改数组。与许多其他方法不同,函数本身返回数组的新长度。
splice, slice
**splice:**通过删除或替换现有元素和/或添加新元素来更改数组的内容,此方法会修改了数组本身。
下面的代码示例的意思是:在数组的位置
1
上删除0
个元素,并插入b
。slice:从指定的起始位置和指定的结束位置之前返回数组的浅拷贝。 如果未指定结束位置,则返回数组的其余部分。 重要的是,此方法不会修改数组,而是返回所需的子集。
sort
**sort:**根据提供的函数对数组进行排序。这个方法就地修改数组。如果函数返回负数或 0,则顺序保持不变。如果返回正数,则交换元素顺序。
7. Generators(生成器)
生成器是一种特殊的行为,实际上是一种设计模式,咱们通过调用
next()
方法来遍历一组有序的值。想象一下,例如使用遍历器对数组[1,2,3,4,5]
进行遍历。第一次调用next()
方法返回1
,第二次调用next()
方法返回2
,以此类推。当数组中的所有值都返回后,调用next()
方法将返回null
或false
或其它可能的值用来表示数组中的所有元素都已遍历完毕。使用生成器生成无限个值:
8.严格相等运算符(===)与相等运算符(==)
大家一定要知道 JS 中的严格相等运算符(
===
)和相等运算符(==
)之间的区别。==
运算符在比较值之前会进行类型转换,而===
运算符在比较之前不会进行任何类型转换。9. 对象比较
JS 新手经常所犯的错误是直接比较对象。变量指向内存中对象的引用,而不是对象本身! 实际比较它们的一种方法是将对象转换为 JSON 字符串。 这有一个缺点:对象属性顺序不能保证,比较对象的一种更安全的方法是引入专门进行深度对象比较的库(例如,lodash 中 isEqual)。
下面的对象看起来是相等的,但实际上它们指向不同的引用。
相反,下面的计算结果为
true
,因为一个对象被设置为与另一个对象相等,因此指向相同的引用(内存中只有一个对象)。相反,以下计算结果为
true
,因为一个对象设置为等于另一个对象,因此指向相同的引用(内存中只有一个对象)。10. 回调函数
很多人都被 JS 回调函数吓倒了。�它们很简单,举个例子,
console.log
函数作为回调传递给myFunc
,它在setTimeout
完成时执行。11. Promises
一旦你理解了 JS 回调,很快就会发现自己陷入了“回调地狱”中。这个时候可以使用 promise,将异步逻辑包装在 promise 中,成功时
resolve
或在失败时reject
使用“then
”来处理成功的情况,使用catch
来处理异常。12. Async/Await
在掌握了 promise 的用法后,你可能也会喜欢
async await
,它只是一种基于 promise 的“语法糖”。在下面的示例中,咱们创建了一个async
函数,并await greete
r。这些概念是我们掌握 JS 需要懂得的知识。你认为还有哪些概念是重要的呢?欢迎留言讨论。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://hackernoon.com/12-javascript-concepts-that-will-level-up-your-development-skills-b37d16ad7104
交流
阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
因为篇幅的限制,今天的分享只到这里。如果大家想了解更多的内容的话,可以去扫一扫每篇文章最下面的二维码,然后关注咱们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,一般都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励
The text was updated successfully, but these errors were encountered: