【专题推荐】AI大模型落地的前景和痛点,技术人面临哪些机会和挑战? 了解详情
写点什么

了解这 12 个概念,让你的 JavaScript 水平更上一层楼

  • 2019-03-06
  • 本文字数:4634 字

    阅读完需:约 15 分钟

了解这12个概念,让你的JavaScript水平更上一层楼

JavaScript 是一门复杂的语言。如果你是一名 JavaScript 开发人员,不管处于什么样的水平,都有必要了解 JavaScript 的基本概念。本文介绍了 12 个非常重要的 JavaScript 概念,但绝对不是说 JavaScript 开发人员只需要知道这些就可以了。

1. 变量赋值(值与引用)

JavaScript 总是按照值来给变量赋值。当指定的值是 JavaScript 的五种原始类型之一(即 Boolean、null、undefined、String 和 Number)时,将为变量分配实际的值。但是,当指定的值是 Array、Function 或 Object 时,将为变量分配内存的对象引用。


在下面的代码段中,使用 var1 对 var2 赋值。由于 var1 是基本类型(String),因此 var2 的值等于 var1 的 String 值,但这个时候可以认为 var2 与 var1 完全不同。因此,重新为 var2 赋值对 var1 没有任何影响。


let var1 = 'My string';let var2 = var1;var2 = 'My new string';console.log(var1);// 'My string'console.log(var2);// 'My new string'
复制代码


我们将它与对象赋值进行比较。


let var1 = { name: 'Jim' }let var2 = var1;var2.name = 'John';console.log(var1);// { name: 'John' }console.log(var2);// { name: 'John' }
复制代码


如果你期望它会像原始类型赋值那样,很可能会出问题!如果你创建了一个无意中会改变对象的函数,就会出现一些非预期的行为。

2. 闭包

闭包是一种重要的 JavaScript 模式,可用于访问私有变量。在下面的示例中,createGreeter 返回一个匿名函数,这个函数可以访问参数 greeting(在这里是“Hello”)。在后续的调用中,sayHello 将有权访问这个 greeting!


function createGreeter(greeting) {  return function(name) {    console.log(greeting + ', ' + name);  }}const sayHello = createGreeter('Hello');sayHello('Joe');// Hello, Joe
复制代码


在一个更真实的场景中,你可以设想一个初始化函数 apiConnect(apiKey),它返回一些使用 API​​密钥的方法。在这种情况下,只需要提供一次 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');// No need to include the apiKey anymoreapi.get('http://www.example.com/get-endpoint');api.post('http://www.example.com/post-endpoint', { name: 'Joe' });
复制代码

3. 解构

JavaScript 参数解构是一种从对象中提取属性的常用方法。


const obj = {  name: 'Joe',  food: 'cake'}const { name, food } = obj;console.log(name, food);// 'Joe' 'cake'
复制代码


如果需要以其他名称来提取属性,可以使用以下格式来指定它们。


const obj = {  name: 'Joe',  food: 'cake'}const { name: myName, food: myFood } = obj;console.log(myName, myFood);// 'Joe' 'cake'
复制代码


在下面的示例中,解构被用来将 person 对象传给 introduce 函数。换句话说,解构可以(并且经常)直接用于提取传给函数的参数。如果你熟悉 React,可能已经见过这个!


const person = {  name: 'Eddie',  age: 24}function introduce({ name, age }) {  console.log(`I'm ${name} and I'm ${age} years old!`);}console.log(introduce(person));// "I'm Eddie and I'm 24 years old!"
复制代码

4. 展开(spread)语法

在下面的示例中,Math.max 不能直接接受 arr 数组,因为它的参数不是数组类型,但可以以数组中的各个元素作为参数。展开运算符…可用于提取数组的各个元素。


const arr = [4, 6, -1, 3, 10, 4];const max = Math.max(...arr);console.log(max);// 10
复制代码

5. 变长参数(rest)语法

你可以用它将传给函数的任意数量的参数放入数组中!


function myFunc(...args) {  console.log(args[0] + args[1]);}myFunc(1, 2, 3, 4);// 3
复制代码

6. 数组方法

JavaScript 数组方法通常可以为你提供令人难以置信的优雅方式来执行所需的数据转换。作为 StackOverflow 的贡献者,我经常看到有关如何以这种或那种方式操纵对象数组的问题。这往往是数组方法的完美用例。

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、findIndex、indexOf

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 之后的元素都符合条件,但只返回第一个匹配的元素。


findIndex:这与 find 几乎完全相同,但不返回第一个匹配的元素,而是返回第一个匹配元素的索引。


const arr = ['Nick', 'Frank', 'Joe', 'Frank'];const foundIndex = arr.findIndex(el => el === 'Frank');console.log(foundIndex);// 1
复制代码


indexOf:与 findIndex 几乎完全相同,但它的参数不是一个函数,而是一个简单的值。


const arr = ['Nick', 'Frank', 'Joe', 'Frank'];const foundIndex = arr.indexOf('Frank');console.log(foundIndex);// 1
复制代码

push、pop、shift、unshift

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、slice

splice:通过删除或替换现有元素或者添加新元素来修改数组的内容。这个方法也是就地修改数组。


下面的代码示例的意思是:在数组的位置 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

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]
复制代码

7. 生成器

看到*不要害怕。生成器函数指定下一次调用 next()时会生成什么 value。既可以生成有限数量的 value(最后调用 next()会返回 undefined),也可以使用循环生成无限数量的 value。


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);// 0console.log(ids.next().value);// 1console.log(ids.next().value);// 2// etc...
复制代码

8. ===与==

一定要知道 JavaScript 中===运算符和==运算符之间的区别!==运算符在比较之前会进行类型转换,而===运算符在比较之前不会进行类型转换。


console.log(0 == '0');// trueconsole.log(0 === '0');// false
复制代码

9. 对象比较

JavaScript 新手容易犯的一个错误是直接比较对象。变量一般是指向内存中对象的引用,而不是对象本身!比较对象的一种方法是将它们转换成 JSON 字符串。但这样做有一个缺点:无法保证对象属性的顺序!一种更安全的方法是使用专门进行深度对象比较的库(例如 lodash 的 isEqual,https://lodash.com/docs#isEqual)。


下面的对象看起来相同,但它们实际上指向不同的引用。


const joe1 = { name: 'Joe' };const joe2 = { name: 'Joe' };console.log(joe1 === joe2);// false
复制代码


相反,下面的结果为 true,因为使用其中一个对象为另一个对象赋值,它们都指向相同的引用(内存中只有一个对象)。


const joe1 = { name: 'Joe' };const joe2 = joe1;console.log(joe1 === joe2);// true
复制代码

10. 回调函数

很多人都被 JavaScript 回调函数吓倒了!它们其实很简单,请看下面的例子。console.log 函数作为回调传给 myFunc,并在 setTimeout 完成时执行。


function myFunc(text, callback) {  setTimeout(function() {    callback(text);  }, 2000);}myFunc('Hello world!', console.log);// 'Hello world!'
复制代码

11. promise

一旦你理解了 JavaScript 回调,很快就会发现自己陷入了“回调地狱”中。这个时候可以使用 promise!将异步逻辑包装在 promise 中,使用“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);   });   // If Math.random() returns less than 0.9 the following is logged:// "Success: Hooray!"// If Math.random() returns 0.9 or greater the following is logged:// "Error: On no!"
复制代码

12. Async/Await

在掌握了 promise 的用法后,你可能也会喜欢 async await,它只是一种基于 promise 的“语法糖”。在下面的示例中,我们创建了一个 async 函数,并 await greeter promise。


const greeter = new Promise((res, rej) => {  setTimeout(() => res('Hello world!'), 2000);})async function myFunc() {  const greeting = await greeter;  console.log(greeting);}myFunc();// 'Hello world!'
复制代码


英文原文:https://hackernoon.com/12-javascript-concepts-that-will-level-up-your-development-skills-b37d16ad7104


更多内容,请关注前端之巅。



2019-03-06 07:507265
用户头像

发布了 731 篇内容, 共 417.7 次阅读, 收获喜欢 1981 次。

关注

评论 1 条评论

发布
用户头像
数组push返回的是数组长度
2019-03-07 16:05
回复
没有更多了
发现更多内容

GetX 状态管理从入门到入迷

岛上码农

flutter ios 前端 安卓 6月月更

GoLang简单易用的json value读取工具!还并发安全

Krysta

Go json 简单清楚 方便

读《Software Systems Architecture》(13)—— Creating the Architectural Description

术子米德

架构师成长笔记

如何修改 Rancher v2.6 的 Rancher Server IP 地址

Rancher

Kubernetes k8s rancher

看板方法的定义、原则和实践

PingCode

linux之我常用的20条命令(之二)

入门小站

Linux

为什么都认为confluence非常好,好在哪里

PingCode

类似Confluence的软件有哪些

PingCode

计算机网络之IP协议与以太网

未见花闻

6月月更

数仓开发人员的价值体现

奔向架构师

数据仓库 数据模型 6月月更

红米 9A的自动化测试

IT蜗壳-Tango

6月月更

数据库每日一题---第13天:寻找病患

知心宝贝

数据库 云计算 前端 后端 6月月更

Curve 进入 CNCF Sandbox,完善统一云原生开源存储拼图

网易数帆

开源 分布式 云原生 存储 cncf

凿开数据冰层,透出智能时代的光:华为云与开发者的结伴旅行

脑极体

盘点攻防演练中红队的主要工具(下)

穿过生命散发芬芳

6月月更 攻防演练

接口测试使用Python装饰器

伤心的辣条

Python 程序人生 软件测试 自动化测试 接口测试

基于 Apache APISIX 的自动化运维平台

API7.ai 技术团队

自动化运维 APISIX 网关 APISIX Summit

从链上数据出发,分析stETH脱锚之后的市场动态

区块链前沿News

eth Hoo

全球Top 2!腾讯计算机视觉能力再突破

脑极体

文档管理系统对于企业有哪些优势

小炮

uni-app深入学习之模板运用【day4】

恒山其若陋兮

6月月更

三点微服务标准化要素

阿泽🧸

微服务 6月月更

js中的变量提升和函数提升

北洋

android 6月月更

在线文本保留中文提取过滤工具

入门小站

工具

读《Software Systems Architecture》(12)—— Producing Architectural Models

术子米德

架构师成长笔记

API 网关 Apache APISIX 助力雪球双活架构演进

API7.ai 技术团队

zookeeper 投资 网关 APISIX APISIX Summit

阿里云 MSE 基于 Apache APISIX 的全链路灰度方案实践

API7.ai 技术团队

阿里云 MSE APISIX 网关 全链路灰度

读《Software Systems Architecture》(14)—— Evaluating the Architecture

术子米德

架构师成长笔记

读《Software Systems Architecture》(11)—— Using Styles and Patterns

术子米德

架构师成长笔记

APISIX 助力中东社交软件,实现本地化部署

API7.ai 技术团队

API网关 社交软件 APISIX Summit

python简介

左手の明天

Python Python解释器

了解这12个概念,让你的JavaScript水平更上一层楼_前端_Nick Scialli_InfoQ精选文章