文章目录
- 一、let和const
- 二、解构赋值
- 数组模型的解构(Array)
- 对象解构
- 三、Map和Set
- Map
- Map迭代
- for...of
- forEach
- Map对象的操作
- Map与Object区别
- Set
- 四、字符串
- 子串识别
- 字符串重复
- 字符串补全
- 模板字符串
- 标签模板
- 五、数值Number
- 数值表示
- 最大/最小安全整数
- 方法
- 六、对象Object
- 扩展运算符
- 方法
- 七、数组Array
- 数组创建
- 方法
- 八、模块
一、let和const
let 声明的变量只在 let 命令所在的代码块内有效。
{
let a = 0;
a // 0
}
a // 报错 ReferenceError: a is not defined
var 是在全局范围内有效:
{
let a = 0;
var b = 1;
}
a // ReferenceError: a is not defined
b // 1
注:
- let 只能声明一次 var 可以声明多次
- for 循环计数器很适合用 let
- let 不存在变量提升,var 会变量提升
const 声明一个只读的常量,一旦声明,常量的值就不能改变。此外,一旦声明必须初始化,否则会报错。
const PI = "3.1415926";
PI // 3.1415926
const MY_AGE; // SyntaxError: Missing initializer in const declaration
二、解构赋值
- 解构赋值是对赋值运算符的扩展。
- 是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
- 在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
数组模型的解构(Array)
//基本模式
let [a, b, c] = [1, 2, 3];
// a = 1
// b = 2
// c = 3
//嵌套
let [a, [[b], c]] = [1, [[2], 3]];
// a = 1
// b = 2
// c = 3
//可省略
let [a, , b] = [1, 2, 3];
// a = 1
// b = 3
//不完全解构
let [a = 1, b] = []; // a = 1, b = undefined
//扩展运算符
let [a, ...b] = [1, 2, 3];
//a = 1
//b = [2, 3]
//字符串
let [a, b, c, d, e] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'o'
对象解构
//基本用法
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
let { baz : foo } = { baz : 'ddd' };
// foo = 'ddd'
//嵌套
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { y }] } = obj;
// x = 'hello'
// y = 'world'
//可省略
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { }] } = obj;
// x = 'hello'
//不完全解构
let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj;
// x = undefined
// y = 'world'
//扩展运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};
// a = 10
// b = 20
// rest = {c: 30, d: 40}
//解构默认值
let {a = 10, b = 5} = {a: 3};
// a = 3; b = 5;
let {a: aa = 10, b: bb = 5} = {a: 3};
// aa = 3; bb = 5;
三、Map和Set
Map
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
//key为字符串
var myMap = new Map();
var keyString = "a string";
myMap.set(keyString, "和键'a string'关联的值");
myMap.get(keyString); // "和键'a string'关联的值"
myMap.get("a string"); // "和键'a string'关联的值"
// 因为 keyString === 'a string'
//对象
var myMap = new Map();
var keyObj = {},
myMap.set(keyObj, "和键 keyObj 关联的值");
myMap.get(keyObj); // "和键 keyObj 关联的值"
myMap.get({}); // undefined, 因为 keyObj !== {}
//函数
var myMap = new Map();
var keyFunc = function () {}, // 函数
myMap.set(keyFunc, "和键 keyFunc 关联的值");
myMap.get(keyFunc); // "和键 keyFunc 关联的值"
myMap.get(function() {}) // undefined, 因为 keyFunc !== function () {}
Map迭代
for…of
//创建一个map
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
// 将会显示两个 log。 一个是 "0 = zero" 另一个是 "1 = one"
for (var [key, value] of myMap) {
console.log(key + " = " + value);
}
for (var [key, value] of myMap.entries()) {
console.log(key + " = " + value);
}
// 将会显示两个log。 一个是 "0" 另一个是 "1"
for (var key of myMap.keys()) {
console.log(key);
}
// 将会显示两个log。 一个是 "zero" 另一个是 "one"
for (var value of myMap.values()) {
console.log(value);
}
forEach
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
// 将会显示两个 logs。 一个是 "0 = zero" 另一个是 "1 = one"
myMap.forEach(function(value, key) {
console.log(key + " = " + value);
}, myMap)
Map对象的操作
- Map 与 Array的转换
var kvArray = [["key1", "value1"], ["key2", "value2"]];
// Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象
var myMap = new Map(kvArray);
// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组
var outArray = Array.from(myMap);
- Map的合并
var first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],]);
var second = new Map([[1, 'uno'], [2, 'dos']]);
// 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的,对应值即 uno,dos, three
var merged = new Map([...first, ...second]);
Map与Object区别
- 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
- Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
- Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
- Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
Set
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。Set 对象存储的值总是唯一的!
注:在set中,有几个特殊值:
- +0 与 -0 在存储判断唯一性的时候是恒等的;
- undefined 与 undefined 是恒等的;
- NaN 与 NaN 是不恒等的,但是在 Set 中只能存一个。
let mySet = new Set();
mySet.add(1); // Set(1) {1}
mySet.add(5); // Set(2) {1, 5}
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性
mySet.add("some text");
// Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = {a: 1, b: 2};
mySet.add(o);
mySet.add({a: 1, b: 2});
// Set(5) {1, 5, "some text", {…}, {…}}
// 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
可以使用set
达到数组去重、求并集、交集、差集等操作!!!
四、字符串
子串识别
-
indexOf
方法
返回某个指定字符串值在字符串中首次出现的位置,如果没有找到则返回-1。
语法:
string.indexOf(查找值,start)
start
为可选参数,表示检索的位置。
var str="Hello world, welcome to the universe.";
var n=str.indexOf("welcome");
- ES6新增子串识别方法:
-
includes()
:返回布尔值,判断是否找到参数字符串。 -
startsWith()
:返回布尔值,判断参数字符串是否在原字符串的头部。 -
endsWith()
:返回布尔值,判断参数字符串是否在原字符串的尾部。
以上三个方法都可以接受两个参数,需要搜索的字符串,和可选的搜索起始位置索引(即start
)。
字符串重复
repeat()
:返回新的字符串,表示将字符串重复指定次数返回。
语法:
string.repeat(n)
如果参数是小数,向下取整:
console.log("Hello,".repeat(3.2)); // "Hello,Hello,Hello,"
如果参数是 0 至 -1 之间的小数,会进行取整运算,0 至 -1 之间的小数取整得到 -0 ,等同于 repeat 零次:
console.log("Hello,".repeat(-0.5)); // ""
如果参数是 NaN,等同于 repeat 零次:
console.log("Hello,".repeat(NaN)); // ""
如果参数是负数或者 Infinity ,会报错:
console.log("Hello,".repeat(-1));
// RangeError: Invalid count value
console.log("Hello,".repeat(Infinity));
// RangeError: Invalid count value
如果传入的参数是字符串,则会先将字符串转化为数字:
console.log("Hello,".repeat("hh")); // ""
console.log("Hello,".repeat("2")); // "Hello,Hello,"
字符串补全
-
padStart
:返回新的字符串,表示用参数字符串从头部(左侧)补全原字符串。 -
padEnd
:返回新的字符串,表示用参数字符串从尾部(右侧)补全原字符串。
语法:
string.padStart(minLength,str)
string.padEnd(minLength,str)
第一个参数是指定生成的字符串的最小长度,第二个参数是用来补全的字符串。如果没有指定第二个参数,默认用空格填充。
console.log("h".padStart(5,"o")); // "ooooh"
console.log("h".padEnd(5,"o")); // "hoooo"
console.log("h".padStart(5)); // " h"
如果指定的长度小于或者等于原字符串的长度,则返回原字符串:
console.log("hello".padStart(5,"A")); // "hello"
如果原字符串加上补全字符串长度大于指定长度,则截去超出位数的补全字符串:
console.log("hello".padEnd(10,",world!")); // "hello,worl"
模板字符串
模板字符串相当于加强版的字符串,用反引号 ``将字符串框起来,可以在字符串中加入变量和表达式。
普通字符串:
let string = `Hello'\n'world`;
console.log(string);
// "Hello'
// 'world"
多行字符串:
let string1 = `Hey,
hello world`;
console.log(string1);
// Hey,
// hello world
使用${}
语法,可以在字符串中插入变量和表达式:
let name = "Mike";
let age = 21;
let info = `My Name is ${name},I am ${age+1} years old.`
console.log(info);
// My Name is Mike,I am 21 years old.
function f(){
return "have fun!";
}
let string2= `Game start,${f()}`;
console.log(string2); // Game start,have fun!
注意:模板字符串中的空格和换行都会被保留。
标签模板
标签模板,是一个函数的调用,其中调用的参数是模板字符串。
alert`Hello world!`;
// 等价于
alert('Hello world!');
当模板字符串包含参数值时,调用函数会将字符串分解成多个参数:
function f(stringArr,...values){
let result = "";
for(let i=0;i<stringArr.length;i++){
result += stringArr[i];
if(values[i]){
result += values[i];
}
}
return result;
}
let name = 'Mike';
let age = 27;
f`My Name is ${name},I am ${age+1} years old next year.`;
// "My Name is Mike,I am 28 years old next year."
f`My Name is ${name},I am ${age+1} years old next year.`;
// 等价于
f(['My Name is',',I am ',' years old next year.'],'Mike',28);
以上实例将模板字符串解析,将字符串传入stringArr
参数,将${}
里面的内容传入values
参数。
五、数值Number
数值表示
二进制:前缀0b
或者0B
console.log(0b01 === 1); // true
console.log(0B01 === 1); // true
八进制:前缀0o
或者0O
console.log(0o11 === 9); // true
console.log(0O11 === 9); // true
常量:
Number.EPSILON
//Number.EPSILON 属性表示 1 与大于 1 的最小浮点数之间的差。
//它的值接近于 2.2204460492503130808472633361816E-16,或者 2-52。
可以用于测试数值是否在误差范围内:
0.1 + 0.2 === 0.3; // false
// 在误差范围内即视为相等
Math.abs(0.1 - 0.3 + 0.2) < Number.EPSILON;// true
最大/最小安全整数
安全整数
安全整数表示在 JavaScript 中能够精确表示的整数,安全整数的范围在 2 的 -53 次方
到 2 的 53 次方
之间(不包括两个端点),超过这个范围的整数无法精确表示。
安全整数范围的上限,即 2 的 53 次方减 1 。
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2; // true
Number.MAX_SAFE_INTEGER === Number.MAX_SAFE_INTEGER + 1; // false
Number.MAX_SAFE_INTEGER - 1 === Number.MAX_SAFE_INTEGER - 2; // false
安全整数范围的下限,即 2 的 53 次方减 1 的负数。
Number.MIN_SAFE_INTEGER + 1 === Number.MIN_SAFE_INTEGER + 2; // false
Number.MIN_SAFE_INTEGER === Number.MIN_SAFE_INTEGER - 1; // false
Number.MIN_SAFE_INTEGER - 1 === Number.MIN_SAFE_INTEGER - 2; // true
方法
-
isFinite()
,用于检查一个数值是否为有限的( finite ),即不是 Infinity
Number.isFinite(x)
注:
- NaN不是有限的,返回 false
- 所有非数值都返回 false
-
parseInt()
,用于将给定字符串转化为指定进制的整数,不指定进制时默认为十进制。
Number.parseInt(x,进制)
注:与全局的parseInt()
函数是同一个函数,即Number.parseInt === parseInt; // true
-
parseFloat()
,用于把一个字符串解析成浮点数
Number.parseFloat(str)
Number.parseFloat('123.45') // 123.45
Number.parseFloat('123.45abc') // 123.45
// 无法被解析成浮点数,则返回 NaN
Number.parseFloat('abc') // NaN
// 与全局的 parseFloat() 方法是同一个方法
Number.parseFloat === parseFloat // true
-
isInteger()
,用于判断给定的参数是否为整数。
Number.isInteger(value)
Number.isInteger(0); // true
// JavaScript 内部,整数和浮点数采用的是同样的储存方法,因此 1 与 1.0 被视为相同的值
Number.isInteger(1); // true
Number.isInteger(1.0); // true
Number.isInteger(1.1); // false
Number.isInteger(Math.PI); // false
// NaN 和正负 Infinity 不是整数
Number.isInteger(NaN); // false
Number.isInteger(Infinity); // false
Number.isInteger(-Infinity); // false
Number.isInteger("10"); // false
Number.isInteger(true); // false
Number.isInteger(false); // false
Number.isInteger([1]); // false
六、对象Object
ES6允许对象的属性直接写变量,这时候属性名是变量名,属性值是变量值。
const age = 12;
const name = "Amy";
const person = {age, name};
person //{age: 12, name: "Amy"}
//等同于
const person = {age: age, name: name}
扩展运算符
拓展运算符...
用于取出参数对象所有可遍历属性然后拷贝到当前对象。
let person = {name: "Amy", age: 15};
let someone = { ...person };
someone; //{name: "Amy", age: 15}
可用于合并两个对象:
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
person; //{age: 15, name: "Amy"}
当自定义的属性在扩展运算符后面,则扩展运算符对象内部同名的属性将被覆盖掉:
let person = {name: "Amy", age: 15};
let someone = { ...person, name: "Mike", age: 17};
someone; //{name: "Mike", age: 17}
自定义的属性在扩展运算符前面,则变成设置新对象默认属性值。
let person = {name: "Amy", age: 15};
let someone = {name: "Mike", age: 17, ...person};
someone; //{name: "Amy", age: 15}
扩展运算符后面是空对象,没有任何效果也不会报错:
let a = {...{}, a: 1, b: 2};
a; //{a: 1, b: 2}
扩展运算符后面是null或者undefined,没有效果也不会报错。
let b = {...null, ...undefined, a: 1, b: 2};
b; //{a: 1, b: 2}
方法
①Object.assign(target, source_1, ···)
,用于将源对象(source)的所有可枚举属性复制到目标对象(target)中。
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);
// 第一个参数是目标对象,后面的参数是源对象
target; // {a: 1, b: 2, c: 3}
注意
- 如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回。
Object.assign(3); // Number {3}
typeof Object.assign(3); // "object"
因为 null 和 undefined 不能转化为对象,所以会报错:
Object.assign(null); // TypeError: Cannot convert undefined or null to object
Object.assign(undefined); // TypeError: Cannot convert undefined or null to object
//当参数不止一个时,null 和 undefined 不放第一个,即不为目标对象时,会跳过 null 和 undefined ,不报错
Object.assign(1,undefined); // Number {1}
Object.assign({a: 1},null); // {a: 1}
Object.assign(undefined,{a: 1}); // TypeError: Cannot convert undefined or null to object
- assign 的属性拷贝是浅拷贝
let sourceObj = { a: { b: 1}};
let targetObj = {c: 3};
Object.assign(targetObj, sourceObj);
targetObj.a.b = 2;
sourceObj.a.b; // 2
②Object.is(value1, value2)
,用来比较两个值是否严格相等,与(===)基本类似。
Object.is("q","q"); // true
Object.is(1,1); // true
Object.is([1],[1]); // false
Object.is({q:1},{q:1}); // false
与(===)的区别:
//一是+0不等于-0
Object.is(+0,-0); //false
+0 === -0 //true
//二是NaN等于本身
Object.is(NaN,NaN); //true
NaN === NaN //false
七、数组Array
数组创建
Array.of(xxx)
将参数中所有值作为元素形成数组。
console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]
// 参数值可为不同类型
console.log(Array.of(1, '2', true)); // [1, '2', true]
// 参数为空时返回空数组
console.log(Array.of()); // []
Array.from(arrayLike,mapFn,thisArg)
将类数组对象或可迭代对象转化为数组。
// 参数为数组,返回与原数组一样的数组
console.log(Array.from([1, 2])); // [1, 2]
// 参数含空位
console.log(Array.from([1, , 3])); // [1, undefined, 3]
参数说明:
- arrayLike为想要转换的类数组对象或可迭代对象
- 可选,map 函数,用于对每个元素进行处理,放入数组的是处理后的元素。
console.log(Array.from([1, 2, 3], (n) => n * 2)); // [2, 4, 6]
- 可选,用于指定 map 函数执行时的 this 对象。
let map = {
do: function(n) {
return n * 2;
}
}
let arrayLike = [1, 2, 3];
console.log(Array.from(arrayLike, function (n){
return this.do(n);
}, map)); // [2, 4, 6]
方法
方法 | 描述 |
arr.find(condition) | 查找数组中符合条件的元素,若有多个符合条件的元素,则返回第一个元素, |
arr.findIndex(condition) | 查找数组中符合条件的元素索引,若有多个符合条件的元素,则返回第一个元素索引 |
arr.fill(value,start [,end]) | 将一定范围内的数组元素填充为单个指定的值, |
arr.entries() | 遍历键值对,键为数组下标,值为数组值 |
arr.keys() | 遍历键 |
arr.values() | 遍历值 |
arr.includes(value,start) | 数组是否包含指定值, |
arr.flat(n) | 将嵌套数组转化为n维数组,参数 |
八、模块
ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。
ES6 的模块化分为导出(export) @与导入(import)两个模块。
特点:
- ES6 的模块自动开启严格模式,不管你有没有在模块头部加上
use strict
; - 模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等;
- 每个模块都有自己的上下文,每一个模块内声明的变量都是局部变量,不会污染全局作用域;
- 每一个模块只加载一次(是单例的), 若再去加载同目录下同文件,直接从内存中读取。
- export 命令可以出现在模块的任何位置,但必需处于模块顶层。import 命令会提升到整个模块的头部,首先执行。
/*-----export [test.js]-----*/
let myName = "Tom";
let myAge = 20;
let myfn = function(){
return "My name is" + myName + "! I'm '" + myAge + "years old."
}
let myClass = class myClass {
static a = "yeah!";
}
export { myName, myAge, myfn, myClass }
/*-----import [xxx.js]-----*/
import { myName, myAge, myfn, myClass } from "./test.js";
console.log(myfn());// My name is Tom! I'm 20 years old.
console.log(myAge);// 20
console.log(myName);// Tom
console.log(myClass.a );// yeah!
注意:不同模块导出接口名称命名重复, 使用 as 重新定义变量名。
静态执行特性:import 是静态执行,所以不能使用表达式和变量。
import { "f" + "oo" } from "methods";
// error
let module = "methods";
import { foo } from module;
// error
if (true) {
import { foo } from "method1";
} else {
import { foo } from "method2";
}
// error