资讯专栏INFORMATION COLUMN

ES6 知识整理一(es6快速入门)

elva / 1814人阅读

摘要:函数调用会在内存形成一个调用记录,又称调用帧,保存调用位置和内部变量等信息。等到运行结束,将结果返回到,的调用帧才会消失。方法用于将一组值,转换为数组。,和遍历数组方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的方法类似。

ES6 简介

ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的下一个版本标准,2015.06 发版。

let 和 const let 命令

let 命令,用来声明变量。它的用法类似于 var,区别在于 var 声明的变量全局有效,let 声明的变量只在它所在的代码块内有效。

// 变量i储存的值是10,所以执行a[2]()后输出10
var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[2](); // 10


// 修正方法
// 闭包会使得函数中的变量都被保存在内存中,所以执行a[2]()后输出2
var a = [];
for (var i = 0; i < 10; i++) {
    (function (i) {
        a[i] = function () {
            console.log(i)
        }
    })(i);
}
a[2](); // 2

// es6
// let声明的i只在当前的代码块有效,所以每次for循环相当于用let重新声明一次i
var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[2](); // 2

// 注:JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

let 不存在变量提升,必须先声明后使用,否则报错;var 存在变量提升,未声明前使用输出 undefined。

let 存在暂时性死区,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。

let 不允许重复声明。

const 命令

const 声明一个只读的常量。一旦声明,常量的值就不能改变。不能只声明不赋值。

const a = 10;
a = 20; // 报错

const b; // 报错

const 的作用域与 let 相同。

if(true) {
  const num = 5;
}
console.log(num); // 报错

const 声明对象,常量对象内存地址,因此对象本身可改,但是给常量重新赋值就会报错。

const obj = {};
obj.a = "a";

obj = {}; // 报错
块级作用域和函数作用域

ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。但是在 ES6 中,函数可以在块级作用域中声明。但是,市面上很多浏览器都不支持 ES6,所以应该避免在块级作用与中声明函数。

ES6 声明变量的方法

var

function

let

const

import

class

变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

数组的解构赋值

模式匹配赋值,如果解构不成功,变量的值就等于 undefined。

let [a, [[b], c]] = [1, [[2], 3]];
console.log(a,b,c); // 1, 2, 3

let [x, , y, z] = [1, 2, 3];
console.log(x); // 1
console.log(y); // 3
console.log(z); // undefined

不完全解构赋值,等号左边的模式,只匹配一部分的等号右边的数组。

let [x, [y], z] = [1, [2, 3], 4];
console.log(x); // 1
console.log(y); // 2
console.log(z); // 4

数组结构赋值右边必须是数组,模式不匹配则报错。

let [a]  = {}; // 报错

解构赋值可以添加默认值,并且可以引用解构赋值的其他变量。

let [a = 1, b = 2] = [, 3];
console.log(a); // 1
console.log(b); // 3

let [x = 1, y = x] = [];  // x = 1; y = 1
let [x = 1, y = x] = [2]; // x = 1; y = 2

数组解构赋值可用于交换变量的值。

let [a, b] = [1, 2];
console.log(a, b); // 1, 2
[b, a] = [a, b];
console.log(a, b); // 2, 1
对象的解构赋值

变量必须与属性同名

let { a, b, c } = { a: "aaa", b: "bbb" };
console.log(a); // "aaa"
console.log(b); // "bbb"
console.log(c); // undefined

变量名与属性名不一致

let { a: x, b: y } = { a: "aaa", b: "bbb" };
console.log(x); // "aaa"
console.log(y); // "bbb"

嵌套赋值,如果子对象所在的父属性不存在,会报错,慎用。

let { a, a: {x}, b: y } = { a: {x: "xxx",y: "yyy"}, b: "bbb" };
console.log(a); // { x: "xxx", y: "yyy" }
console.log(x); // "xxx"

let {c: {d: {e}}} = {c: "ccc"}; // 报错
console.log(e)

变量解构赋值也和数组的解构赋值一样,可以赋默认值,变量解构赋值时,不能将大括号写在行首,否者 JavaScript 引擎将会按代码块执行。

let x;
{x} = {x: 1}; // 报错

// 正确写法
let x;
({x} = {x: 1});
字符串解构赋值

字符串解构赋值,将字符串转化成数组对象

const [a,b,c] = "123456789";
const {length} = "123456789";
console.log(a, b, c, length); // 1, 2, 3, 9
函数解构赋值
const arr = [[1, 2], [3, 4]].map(([a, b]) => a + b);
console.log(arr); // [ 3, 7 ]
解构赋值规则

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined 和 null 无法转为对象,所以对它们进行解构赋值,都会报错。

let {toString: n} = 123;
n === Number.prototype.toString // true

let {toString: b} = true;
b === Boolean.prototype.toString // true

let { prop: u } = undefined; // 报错
let { prop: n } = null; // 报错
解构赋值的用途

交换变量的值

从对象、数组中取值(提取 JSON 数据),或从函数中返回多个值

函数解构赋值传参,给定函数参数的默认值

输入模块的指定方法

遍历 Map 结构

const map = new Map();
map.set("first", "hello");
map.set("second", "world");

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world
字符串扩展(不含编码) for...of 遍历字符串
for(let codePoint of "string"){
  console.log(codePoint)
}
// "s"
// "t"
// "r"
// "i"
// "n"
// "g"
includes(),startsWith(),endsWith()

三个方法都接收两个参数,第一个参数为检索的值,第二个参数为检索的起始位置,返回布尔值

let s = "Hello world!";

const [a, b, c] = [
    s.startsWith("Hello", 2),
    s.endsWith("!"),
    s.includes("o w")
];

console.log(a, b, c); // false true true
repeat()

repeat 方法返回一个新字符串,表示将原字符串重复 n 次。

参数为[-Infinity,-1]或者 Infinity,会报错;

参数为(-1,1)时,相当于参数为 0;

参数为小数时向下取整;

参数 NaN 等同于 0;

参数是字符串,则会先转换成数字。

"str".repeat("3") // "strstrstr"
padStart(), padEnd()

padStart(),padEnd()有两个参数,第一个参数为字符串补全生效的最大长度,第二个参数为补全的字符串。

第二个参数默认为空格,省略第二个参数时默认用空格补全。

第一个参数小于字符串原长度时,返回原字符串。

如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。

常见用途:补全指定位数,提示字符串格式。

"123456".padStart(10, "0") // "0000123456"
"09-12".padStart(10, "YYYY-MM-DD") // "YYYY-09-12"
模版字符串(``)
const str = "world";
const template = `Hello ${str}`;
console.log(template); // Hello world
正则扩展(略) 数值扩展 二进制、八进制表示法

使用二进制表示法,前缀为 0b,使用八进制表示法,前缀为 0o,ES6 不支持使用 00 前缀表示八进制。

进制转换使用 toString 方法,使用 Number 方法直接转十进制。

0b1100100 === 100; // true
0o144 === 100; // true

(0b1100100).toString(8); // 144
(0b1100100).toString(10); // 100
Number("0b1100100"); // 100
Number.isFinite(),Number.isNaN()

Number.isFinite()用来检查一个数值是否为有限的(finite),即不是 Infinity。参数类型不是数值,Number.isFinite 一律返回 false。

Number.isNaN()用来检查一个值是否为 NaN。参数类型不是 NaN,Number.isNaN 一律返回 false。

Number.isFinite(15); // true
Number.isFinite(-Infinity); // false

Number.isNaN(15) // false
Number.isNaN(9/0) // true
Number.parseInt(), Number.parseFloat()

ES6 将全局方法 parseInt()和 parseFloat(),移植到 Number 对象上面,行为完全保持不变。

Number.isInteger()

Number.isInteger()用来判断一个数值是否为整数。

Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
ES6 新增 Number 常量

Number.EPSILON 极小常量,浮点数误差小于这个值可以认为不存在误差;

Number.MAX_SAFE_INTEGER 安全整数的最大范围;

Number.MIN_SAFE_INTEGER 安全整数的最小范围;

Number.isSafeInteger() 用来判断一个整数是否落在安全整数范围之内。

Number.isSafeInteger(9007199254740993) // false
Number.isSafeInteger(990) // true
Number.isSafeInteger(9007199254740993 - 990) // true
Math 对象的扩展

Math.trunc() 除去一个数的小数部分,返回整数部分。参数不是数值,内部会先调用 Nunber()专为数值,对于空值和无法截取整数的值,返回 NaN。(Math 对象的扩展的方法对于非数值的处理方法都一样)

Math.trunc(5.9) // 5
Math.trunc(-4.9) // -4
Math.trunc(null) // 0
Math.trunc("foo"); // NaN

Math.sign() 判断一个数是正数、负数、还是零。

Math.sign(-5) // -1 负数
Math.sign(5) // +1 正数
Math.sign(0) // +0 零
Math.sign(-0) // -0 零
Math.sign(NaN) // NaN

Math.cbrt() 计算一个数的立方根。

Math.cbrt(2)  // 1.2599210498948734

// Math.sqrt(x) 计算平方根
Math.sqrt(2) // 1.4142135623730951

// 幂运算 Math.pow(x,y)
Math.pow(2, 3)

Math.hypot() 返回所有参数的平方和的平方根。

Math.hypot(3, 4);        // 5
Math.hypot(3, 4, 5);     // 7.0710678118654755
函数扩展 rest 参数

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。只能是最后一个参数,函数的 length 属性,不包括 rest 参数。

function sum1(x, y, ...args) {
    let sum = 0;

    for (let arg of args) {
        sum += arg;
    }

    return sum;
}

console.log(sum1(1, 2, 3, 4)) // 7

function sum2(...args) {
    return args.reduce((prev, curr) => {
        return prev + curr
    }, 0)
}

console.log(sum2(1, 2, 3)); // 6
name 属性

函数的 name 属性,返回该函数的函数名。对于匿名函数,ES5 返回"",ES6 返回变量名;
Function 构造函数返回的函数实例,name 属性的值为 anonymous;bind 返回的函数,name 属性值会加上 bound 前缀。

function fn() {}
fn.name // "fn"

function foo() {};
foo.bind({}).name // "bound foo"

(function(){}).bind({}).name // "bound "
箭头函数
const fn = v => v;

// 等同于
const fn = function (v) {
  return v;
};

注意要点

函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象;

不可以当作构造函数,即不可以使用 new 命令,否则会抛出一个错误;

不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替;

不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

尾调用优化

尾调用指函数的最后一步是调用另一个函数。

function f(x){
  "use strict";
  return g(x);
}

函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数 A 的内部调用函数 B,那么在 A 的调用帧上方,还会形成一个 B 的调用帧。等到 B 运行结束,将结果返回到 A,B 的调用帧才会消失。如果函数 B 内部还调用函数 C,那就还有一个 C 的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。

尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了,这样可以防止内存溢出,达成尾调用优化。

ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。

数组扩展 扩展运算符

扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

const arr = [1, 2, 3];
arr.push(...[4, 5, 6]);

扩展运算符的应用

数组展开

const arr = [1, 2, 3];
...arr // 1, 2, 3

复制数组

const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;

// 相当于
const a1 = [1, 2];
const a2 = a1.concat();

合并数组。浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。以下的两种方法属于浅拷贝,如果修改了原数组的成员,会同步反映到新数组。

const arr1 = ["a", "b"];
const arr2 = ["c"];
const arr3 = ["d", "e"];

// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ "a", "b", "c", "d", "e" ]

// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ "a", "b", "c", "d", "e" ]

解构赋值,字符串转数组

const list = [1, 2, 3];
[a, ...b] = list;
console.log(a) // 1
console.log(b) // [2, 3]

[..."hello"] // ["h", "e", "l", "l", "o"]
Array.from()

Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

常见的类似数组的对象有 DOM 操作返回的 NodeList 集合,以及函数内部的 arguments 对象。

let arrayLike = {
    "0": "a",
    "1": "b",
    "2": "c",
    length: 3
};

// ES5的写法
var arr1 = [].slice.call(arrayLike); // ["a", "b", "c"]

// ES6的写法
let arr2 = Array.from(arrayLike); // ["a", "b", "c"]

Array.from("hello");
// ["h", "e", "l", "l", "o"]

let namesSet = new Set(["a", "b"]);
Array.from(namesSet); // ["a", "b"]

Array.from 还可以接受第二个参数,作用类似于数组的 map 方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

let arrayLike = {
    "0": 1,
    "1": 2,
    "2": 3,
    length: 3
};
Array.from(arrayLike, x => x * x); // [ 1, 4, 9 ]
Array.of()

Array.of 方法用于将一组值,转换为数组。这个方法的主要目的,是弥补数组构造函数 Array()的不足。因为参数个数的不同,会导致 Array()的行为有差异。

Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]
copyWithin()

参数:

target(必需):从该位置开始替换数据。如果为负值,表示倒数。

start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。

end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。

这三个参数都应该是数值,如果不是,会自动转为数值。

[1, 2, 3, 4, 5].copyWithin(0, 3)
find() 和 findIndex()

数组实例的 find 方法,用于找出第一个符合条件的数组成员,如果没有符合条件的成员,则返回 undefined。

findIndex 方法返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

[1, 4, -5, 10].find(n => n < 0); // -5
[1, 4, -5, 10].findIndex(n => n < 0); // 2

两个方法都可以接受第二个参数,用来绑定回调函数的 this 对象。

function f(v){
  return v > this.age;
}
let person = {name: "John", age: 20};
[10, 12, 26, 15].find(f, person);  // 26

这两个方法都可以发现 NaN,弥补了数组的 indexOf 方法的不足。

fill() 填充数组

fill 方法使用给定值,填充一个数组。fill 方法可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象,改变数组中的一项,则所有项都改变。

let arr = Array.of(1, 2, 3).fill({
    num: 20
});

console.log(arr); // [ { num: 20 }, { num: 20 }, { num: 20 } ]

arr[0].num = 10;
console.log(arr); // [ { num: 10 }, { num: 10 }, { num: 10 } ]
entries(),keys() 和 values() 遍历数组
for (let index of ["a", "b"].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ["a", "b"].values()) {
  console.log(elem);
}
// "a"
// "b"

for (let [index, elem] of ["a", "b"].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"
includes()

includes 方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的 includes 方法类似。该方法的第二个参数表示搜索的起始位置,第二参数是负数,取它的倒数,第二参数大于数组长度,取 0。

[1, 2, 3].includes(3, -1); // true
flat(),flatMap()

flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将 flat()方法的参数写成一个整数,表示想要拉平的层数,默认为 1。

flat()的参数为 2,表示要“拉平”两层的嵌套数组。如果不管有多少层嵌套,都要转成一维数组,可以用 Infinity 关键字作为参数。

[1, [2, [3]]].flat(Infinity);
// [1, 2, 3]

flatMap()先遍历数组,再“拉平”一层,也只能拉平一层。参数鱼 map()方法类似。
ß

[2, 3, 4].flatMap(x => [x, x * 2]); // [2, 4, 3, 6, 4, 8]

// 相当于
[2, 3, 4].map(x => [x, x * 2]).flat(); // [2, 4, 3, 6, 4, 8]
对象扩展 属性简洁表示法
const a = 1;
const b = 2;

const c = {a, b};
// 等同于
const c = {a: a, b: b};

const o = {
  method() {
    return "Hello!";
  }
};
// 等同于
const o = {
  method: function() {
    return "Hello!";
  }
};

function f(x, y) {
  return {x, y};
}
// 等同于
function f(x, y) {
  return {x: x, y: y};
}
对象的扩展运算符

对象扩展符类似数组扩展符,主要用于解构赋值。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);
Object.is()

Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

Object.is("str", "str"); // true
Object.is({}, {}); // false

不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

由于undefined和null无法转成对象,所以如果它们作为首参数,就会报错。

const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

常见用途:

为对象添加属性和方法

克隆或合并对象

给属性指定默认值

其他

本文参考《ECMAScript 6 入门》,了解更多请点击跳转点击跳转。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109152.html

相关文章

  • 前端基础入门

    摘要:手把手教你做个人火的时候,随便一个都能赚的盆满钵满,但是,个人没有服务端,没有美工,似乎就不能开发了,真的是这样的吗秘密花园经典的中文手册。涵盖前端知识体系知识结构图书推荐以及入门视频教程,全的简直不要不要的了。 JavaScript 实现点击按钮复制指定区域文本 html5 的 webAPI 接口可以很轻松的使用短短的几行代码就实现点击按钮复制区域文本的功能,不需要依赖 flash。...

    shinezejian 评论0 收藏0
  • 前端开发-从入门到Offer - 收藏集 - 掘金

    摘要:一些知识点有哪些方法方法前端从入门菜鸟到实践老司机所需要的资料与指南合集前端掘金前端从入门菜鸟到实践老司机所需要的资料与指南合集归属于笔者的前端入门与最佳实践。 工欲善其事必先利其器-前端实习简历篇 - 掘金 有幸认识很多在大厂工作的学长,在春招正式开始前为我提供很多内部推荐的机会,非常感谢他们对我的帮助。现在就要去北京了,对第一份正式的实习工作也充满期待,也希望把自己遇到的一些问题和...

    sf_wangchong 评论0 收藏0
  • 2017年1月前端月报

    摘要:平日学习接触过的网站积累,以每月的形式发布。年以前看这个网址概况在线地址前端开发群月报提交原则技术文章新的为主。 平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 概况 在线地址:http://www.kancloud.cn/jsfront/month/82796 JS前端开发群月报 提交原则: 技...

    FuisonDesign 评论0 收藏0
  • 2017年1月前端月报

    摘要:平日学习接触过的网站积累,以每月的形式发布。年以前看这个网址概况在线地址前端开发群月报提交原则技术文章新的为主。 平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 概况 在线地址:http://www.kancloud.cn/jsfront/month/82796 JS前端开发群月报 提交原则: 技...

    ivyzhang 评论0 收藏0

发表评论

0条评论

elva

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<