余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

十个超级实用的 JS 特性(js的基本特点)

xiyangw 2022-11-26 15:47 42 浏览 0 评论

你可能刚上手 JavaScript,或者只是曾经偶尔用过。不管怎样,JavaScript 改变了很多,有些特性非常值得一用。 这篇文章介绍了一些特性,在我看来,一个严肃的 JavaScript 开发者每天都多多少少会用到这些特性。

参考资料

下面两个关于 ES6+ 的站点是我的最爱:

  • ES6 Features
  • MDN

展开操作符

顾名思义,用于对象或数组之前的展开操作符(...),将一个结构展开为列表。 演示一下:

let firstHalf = [ 'one', 'two'];
let secondHalf = ['three', 'four', ...firstHalf];

这种写法够优雅,够简洁吧? 如果不用展开操作符,我们得这么写:

let firstHalf = [ 'one', 'two'];
let secondHalf = ['three', 'four'];
for(var i=0, i <firstHalf.length; i++ ) {
 secondHalf.push(firstHalf[i]);
}

展开操作符也适用于合并对象的属性:

const hero = {
 name: 'Xena - Warrior Princess',
 realName: 'Lucy Lawless'
}
const heroWithSword = {
 ...hero,
 weapon: 'sword'
}

不用展开操作符的话,需要遍历对象的属性:

let keys = Object.keys(hero);
let obj = {};
for(var i=0; i< keys.length; i++) {
 obj[keys[i]] = keys[props[i]];
}

剩余参数

剩余参数将剩余的参数收入数列。 JavaScript 的特性是参数数目很灵活。 通常会有一个 arguments 变量收集参数。 让我们看一个例子:

function add(first, second, ...remaining) {
 return first + second;
}

上面的一段代码仅仅将 first 和 second 加起来,也就是说,调用 add(1, 2) 和 add(1, 2, 3, 4) 会得到相同的结果。 下面我们修正一下:

function add(first, second, ...remaining) {
 return first + second + remaining.reduce((acc, curr) => acc + curr, 0);
}

如前所述,...remaining 收集了剩余的参数,为我们提供了这些参数的命名,清楚地表明我们打算处理剩余的参数。 我记得至迟 ES5 已经有 arguments 了,不过少有人知。

字符串插值

见过这样的语句吗?

class Product {
 constructor(name, description, price) {
 this.name = name;
 this.description = description;
 this.price = price;
 }
 getDescription() {
 return " Full description \n" + 
 " name: " + this.name + 
 " description: " + this.description
 }
}

当然,我指的是 getDescription() 方法中那个可读性不佳的多行长语句。 大多数编程语言中都存在类似现象。 一些语言提供了字符串插值,幸运的是,JavaScript 正是其中之一。 我们改写一下 getDescription() 方法:

getDescription() {
 return `Full description \n: 
 name: ${this.name}
 description ${this.description}
 `;
}

一对 ` 包起来的字符串中可以使用 ${} 插值。 现在看起来舒服多了。

简写属性

在 ES5 中必须这么写:

function createCoord(x, y) {
 return {
 x: x,
 y: y
 }
}

ES6 以后可以使用简写属性:

function createCoord(x, y) {
 return {
 x,
 y
 }
}

看起来更清爽了吧?

方法属性

方法属性是在对象中定义指向方法的属性。 考虑下面一段 ES5 代码作为例子:

const math = {
 add: function(a,b) { return a + b; },
 sub: function(a,b) { return a - b; }, 
 multiply: function(a,b) { return a * b; }
}

ES6 以后只需这么写:

const math = {
 add(a,b) { return a + b; },
 sub(a,b) { return a - b; },
 multiply(a,b) { return a * b; }
}

解构赋值

解构赋值有利于开发者本人的心理健康。

考虑下面的代码:

function handle(req, res) {
 const name = req.body.name;
 const description = req.body.description;
 const url = req.url;
 log('url endpoint', url);
 // 大量代码逻辑
 dbService.createPerson(name, description)
}

不管从什么角度来看,上面的代码都不完美,但它确实体现了一种应用场景,我们想要从对象的不同层次获取数据。 你也许会问,这里有什么问题? 好吧,我可以不用声明这么多变量,省下一些敲击键盘的次数。

function handle(req, res) {
 const { body: { name, description }, url } = req;
 log('url endpoint', url);
 // 大量代码逻辑
 dbService.createPerson(name, description)

看,我们上面的代码将三行压缩成了一行。

解构赋值并不仅仅局限于对象。 它同样适用于数组。考虑下面的代码:

const array = [1,2,3,4,5,6];
const a = array[0];
const c = array[2];

上面的代码可以用更优雅的方式改写:

const array = [1,2,3,4,5,6];
const [a, ,c, ...remaining] = arr;
// remaining = [4,5,6]

我们可以使用上面的模式匹配分解数组的值。 我们使用 , , 跳过某些值。 上面提到过的剩余参数这里也能用,在这里我们通过剩余参数捕获了剩余的数组成员。

解构赋值还可以用于函数和参数。 函数有不止 2-3 个参数时,使用一个对象收集所有参数是 JavaScript 的事实标准。 例如,下面一个函数:

function doSomething(config) {
 if(config.a) { ... }
 if(config.b) { ... }
 if(config.c) { ... }
}

有更好的写法:

function doSomething({ a, b, c }) {
 if(a) { ... }
 if(b) { ... }
 if(c) { ... }
}

数组方法

ES6 引入了许多有用的数组方法,例如:

  • find(),查找列表中的成员,返回 null 表示没找到
  • findIndex(),查找列表成员的索引
  • some(),检查某个断言是否至少在列表的一个成员上为真
  • includes,列表是否包含某项

下面的代码有助于你理解它们的用法:

const array = [{ id: 1, checked: true }, { id: 2 }];
arr.find(item => item.id === 2) // { id: 2 }
arr.findIndex(item => item.id === 2) // 1
arr.some(item => item.checked) // true
const numberArray = [1,2,3,4];
numberArray.includes(2) // true

Promises + Async/Await

如果你在这个圈子里呆了些年头,也许会记得曾经有一个时期我们只有回调,就像这样:

function doSomething(cb) {
 setTimeout(() => {
 cb('done')
 }, 3000)
}
doSomething((arg) => {
 console.log('done here', arg);
})

我们使用回调是因为有些操作是异步的,需要时间来完成。 后来我们有了 promise 库,人们开始使用它。 然后 JavaScript 逐渐加入了对 promise 的原生支持。

function doSomething() {
 return new Promise((resolve, reject) => {
 setTimeout(() => {
 resolve('done')
 }, 3000)
 })
}
doSomething().then(arg => {
 console.log('done here', arg);
})

我们甚至可以这样调用,将 promise 串起来:

getUser()
 .then(getOrderByUser)
 .then(getOrderItemsByOrder)
 .then(orderItems => {
 // 处理排序后的成员
 })

后来生活更加美好,我们有了 async/await, 上面一段代码可以这样写:

async function getItems() {
 try {
 const user = await getUser();
 const order = await getOrderByUser(user);
 const items = await getOrderItemsByOrder(order);
 return items;
 } catch(err) {
 // 在这里处理错误,建议返回某个值或者重新抛出错误
 }
}
getItems().then(items => {
 // 处理排序后的成员
})

模块

差不多任何编程语言都支持模块这一概念,也就是将代码分为多个文件,每个文件是一个自我包含的单元(模块)。 考虑下面的代码:

// math.js
export function add(a,b) { return a + b; }
export function sub(a,b) { return a - b; }
export default mult(a,b) => a * b;
// main.js
import mult, { add, sub } from './math';
mult(2, 4) // 8
add(1,1) // 2
sub(1,2) // -1

我们在上面用 export 关键字注明了 add 和 sub 这两个结构对任何引入该模块的模块都公开可见。 export default 关键字则注明仅仅 import 模块时得到的结构。 在 main.js 中,我们将导入的 default 命名为 mult,同时指明我们引入 add() 和 sub() 这两个方法。

箭头函数和字典作用域 this

我在这篇文章中很多地方都用到了箭头函数,它不过是另一种函数表示法。 过去我们只能这么声明函数:

function printArray(arr) {
 // 具体操作
}

现在我们也可以这么写:

const printArray = (arr) => {
 // 具体操作
}

我们也可以将函数声明写到一行里:

const add = (a,b) => a + b

上面的代码表明我们进行操作并返回结果。 我们也可以采用下面的语法返回一个对象:

const create = (a,b) = > ({ x: a, y: b })

过去会碰到搞不清 this 是什么的问题。 考虑下面的代码:

let array = [1,2,3];
function sum() {
 this.total = 0;
 arr.forEach(function(item) {
 this.total+= item; // 糟糕,`this` 是内层函数的 `this`
 })
 return total;
}

上面代码中的 this 指向 forEach 内部函数的 this,这可不是我们想要的。 过去我们通过以下方式解决这个问题:

function sum() {
 this.total = 0;
 var self = this;
 arr.forEach(function(item) {
 self.total+= item; // 这里我们使用 `self`,它能解决问题,但是感觉有点别扭
 })
 return total;
} 

箭头函数可以解决问题,再也不用 self 了,现在代码看起来是这样的:

function sum() {
 this.total = 0;
 arr.forEach((item) => {
 this.total+= item; // 一切安好,`this` 指向外层函数
 })
 return total;
}

大胜!

结语

我还可以讲讲更多 ES6 方面的内容,不过这篇文章中我只打算介绍我最偏爱的特性。 我觉得你应该从今天开始使用这些特性。

文章转自:https://segmentfault.com/a/1190000020482546

相关推荐

Mac软件删除方法,这样删除不会有残留
Mac软件删除方法,这样删除不会有残留

Mac电脑如果有太多无用的应用程序,很有可能会拖垮Mac系统的运行速度。因此,卸载电脑中无用的软件是优化Mac系统运行速度的最佳方式之一。Mac卸载应用程序的方...

2023-09-23 17:34 xiyangw

安利一款 Mac 的清理工具 Cleaner One
安利一款 Mac 的清理工具 Cleaner One

自从入手mac以后,一直在找款mac的清理工具之前也尝试过CleanMyMac和柠檬清理柠檬清理是腾讯旗下的,虽然免费,但更新不频繁,最近一次更新还...

2023-09-23 17:33 xiyangw

苹果电脑需要安装杀毒软件吗?一文告诉你
苹果电脑需要安装杀毒软件吗?一文告诉你

随着数字时代的发展,计算机安全问题变得越来越重要。而在计算机安全领域中,杀毒软件是一个被广泛讨论的话题。苹果电脑需要安装杀毒软件吗?对于苹果电脑用户来说,他们常...

2023-09-23 17:30 xiyangw

mac上实用的工具

mac系统上有很多好用的工作,本期给大家带来一些本人长期使用的软件,特别是刚从windows系统的pc转移到macbook上的小伙伴,可能有一定的帮助。1.Alfred可以完全取代苹果自带Spotl...

Mac专用免费清理软件CleanMyMac
Mac专用免费清理软件CleanMyMac

在Mac中,越来越多的垃圾占用了磁盘空间怎么办?直接拖拽到废纸篓很多软件不能完全卸载干净怎么办……伴随着这些问题,如果有一款多功能的软件能够解决以上的全部难题就...

2023-09-23 17:29 xiyangw

MAC软件分享CleanMyMac中文版 支持最新版系统
MAC软件分享CleanMyMac中文版 支持最新版系统

CleanMyMac的强大不需要过多的去介绍,软件支持最新版Macos10.15.6系统。CleanMyMac具有非常强大的功能,可让您安全,智能地扫描和清理...

2023-09-23 17:28 xiyangw

安装CleanMyMac 3提示软件已损坏
安装CleanMyMac 3提示软件已损坏

安装CleanMyMac3提示软件已损坏,出现这样的原因是往往是使用了CleanMyMac3破解版,主要是因为CleanMyMac3的来源问题,我们的正版软件(...

2023-09-23 17:27 xiyangw

苹果Mac中使用 CleanMyMac X 清理垃圾时频繁要求输入密码如何解决?
苹果Mac中使用 CleanMyMac X 清理垃圾时频繁要求输入密码如何解决?

有不少用户反映在使用CleanMyMac清理系统垃圾文件的时候会频繁要求输入开机密码,如何解决这个问题?来看看吧!解决方法:1.打开「终端」,并输入以下命令...

2023-09-23 17:27 xiyangw

MacBook清理垃圾软件哪个好
MacBook清理垃圾软件哪个好

很多时候手动清理mac效果并没有那么好,常常会有疏忽的地方,其实我们完全可以依赖一些mac清理垃圾软件。windows上我们会借助360安全卫士、腾讯安全管家等...

2023-09-23 17:26 xiyangw

全球真的只有13台DNS根域名服务器吗?
全球真的只有13台DNS根域名服务器吗?

DNS根域名服务器(DNSrootnameservers)是一组特殊的DNS服务器,它们存储有关Internet域名系统(DNS)中所有顶级域的信息。这些...

2023-09-23 17:25 xiyangw

网络管理员,网络工程师每日一练

在DNS服务器中的()资源记录定义了区域的邮件服务器及其优先级。A.SOAB.NSC.PTRD.MX试题答案:D...

Android性能优化之网络优化DNS和HttpDNS知识详解
Android性能优化之网络优化DNS和HttpDNS知识详解

前言小计在App访问网络的时候,DNS解析是网络请求的第一步,默认我们使用运营商的LocalDNS服务。有数据统计,在这一块3G网络下,耗时在2...

2023-09-23 17:25 xiyangw

如何修改域名DNS服务器?修改DNS服务器常见问题汇总
如何修改域名DNS服务器?修改DNS服务器常见问题汇总

在域名管理过程中,我们为了获得更专业安全的域名解析服务,就需要修改DNS服务器,下面中科三方针对修改DNS服务器常见问题做下简单回答。1.修改DNS服务器和修改...

2023-09-23 17:24 xiyangw

netty系列之:在netty中使用 tls 协议请求 DNS 服务器

简介在前面的文章中我们讲过了如何在netty中构造客户端分别使用tcp和udp协议向DNS服务器请求消息。在请求的过程中并没有进行消息的加密,所以这种请求是不安全的。那么有同学会问了,就是请求解析一个...

「GCTT 出品」使用 Golang 构建 DNS 服务器
「GCTT 出品」使用 Golang 构建 DNS 服务器

需求:对DNS查询进行转发和缓存的本地DNS服务器。补充1:提供一个记录管理的接口(HTTPhandler)。补充2:提供一个名字(name)。D...

2023-09-23 17:23 xiyangw

取消回复欢迎 发表评论: