InfoQ Geekathon 大模型技术应用创新大赛 了解详情
写点什么

了解这 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


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



活动推荐:

2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。

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

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

关注

评论 1 条评论

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

【Vue2.x 源码学习】第十篇 - 数组数据变化的观测情况

Brave

源码 vue2 6月日更

如何解决回归任务数据不均衡的问题?

华为云开发者联盟

深度学习 模型 标签 数据不平衡 DIR

项目管理100问 | 研发团队如何实现无缝协作

万事ONES

项目管理 ONES Project 研发团队

react源码解析11.生命周期调用顺序

全栈潇晨

react.js

GrowingIO 增长平台产研项目管理实践

GrowingIO技术专栏

项目管理 程序员 Jira growingio

ONES CTO 冯斌 | 大型团队敏捷项目管理实践与思考

万事ONES

项目管理 研发管理 团队协作 ONES 研发工具

关于 JavaScript 是否加分号的问题

KooFE

6月日更

读深入ES6记[四]

蛋先生DX

ES6 6月日更

Pandas之:深入理解Pandas的数据结构

程序那些事

Python 数据分析 pandas 程序那些事

开发感想 初学51单片机建议用C语言

万里无云万里天

开发感想 8051

WorkPlus私有化「数智融合」移动平台

WorkPlus

应对全场景AI框架部署挑战,MindSpore“四招”让你躺平

华为云开发者联盟

深度学习 AI mindspore 算子 ai框架

联想积极参与CSMM标准制定和推广,推进中国软件产业高质量发展

科技热闻

Java 并发编程—— Executors 分析应用

Antway

6月日更

Fork原项目新增分支的同步和推送

Skysper

git

技术实践丨体验量子神经网络在自然语言处理中的应用

华为云开发者联盟

自然语言处理 量子 量子神经网络 量子模拟

WorkPlus Lite 企业级移动平台

WorkPlus

跨域背后的故事(一)-----同源策略

卢卡多多

浏览器 同源策略 6月日更

缓存与数据库的双写一致性

leonsh

MySQL redis 缓存

【Flutter 专题】107 图解自定义 ACEPageMenu 滑动菜单 (二)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 6月日更

来自 Apache APISIX committer 的经验分享 —— 编程之夏专访

API7.ai 技术团队

后端 技术人 API 网关

技术干货 | 如何实现对动态PPT的云端录制?

ZEGO即构

音视频 WebRTC RTC 即构 动态PPT录制

【21-3】PowerShell 环境

耳东@Erdong

PowerShell Windows Server 6月日更

5000字 | 详解 Java 中的 21 种锁

悟空聊架构

Java 读写锁 锁升级 6月日更

平阴玫瑰×浪潮云洲:见证一朵玫瑰的绽放

浪潮云

云计算

Java字符串池、常量池、intern的爱恨纠葛

叫我阿柒啊

Java 常量池 intern 字符串常量池

Python——列表元素的增删改

在即

6月日更

常见词向量模型

Qien Z.

6月日更 词向量 SkipGram 矩阵分解 Glove

一文说尽 Linux 系统的 swap 交换空间

看山

Linux 6月日更

只记得文件类型如何用EasyRecovery实现恢复?

淋雨

数据恢复 EasyRecovery 文件恢复 照片恢复

产品策略闭环是个什么环?

万事ONES

项目管理 研发管理 ONES 产品策略

  • 扫码添加小助手
    领取最新资料包
了解这12个概念,让你的JavaScript水平更上一层楼_大前端_Nick Scialli_InfoQ精选文章