解构赋值:
数组的解构赋值:
<!-- 数组是按顺序解构的 -->
es6 let [a, b, c] = [1, 2, 3]; es5 var a = 1, b = 2, c = 3;
let [a, [b, c], d, e = "cc"] = [1, [2], 3, undefined];
console.log(a)//1
console.log(e)//cc
对象的解构赋值:
let foo; //foo已经定义了变量 再赋值时在外边加括号
({foo}={foo:'bb'}) ;
<!-- 对象是按照key值解构的 -->
let { fo, bar } = { fo: 'cc', bar: 'wd' }
字符串的解构赋值:
const [f, g, h, j, k, l] = 'jspang';
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);
console.log(f);
运算符
对象扩展运算符
<!-- 参数不确定个数时候 -->
function cc(...arg) {
console.log(arg[0])
console.log(arg[1])
console.log(arg[2])
console.log(arg[3])
console.log(arg[4])
}
cc(1, 2, 3, 4)
eg: let arr1 = ['www', 'qqq'];
let arr2 = arr1;
arr2.push('eeee'); <!-- 这样arr1和arr2都改变 因为let会使arr2从arr1映射一个值, -->
let arr1 = ['www', 'qqq'];
let arr2 = [...arr1];
arr2.push('eeee');<!-- 这样就没问题 -->
rest扩展运算符 rest译为剩余
<!-- 声明方法时候 进行变量不确定处理 -->
function cc(f, ...arg) {
console.log(arg.length);
}
cc(1, 2, 3, 4) //length为3
字符串模板 (拼接字符串)
let cc = "乘冲"
let blog = `字符串拼接 ${cc},不以物喜不以己悲`
console.log(blog) //字符串拼接 乘冲,不以物喜不以己悲
支持html标签
let blog = `<b>非常高兴你能看到这篇文章</b>,我是你的老朋友${cc}。<br/>这节课我们学习字符串模版。`;
document.write(blog);
对运算的支持:
let a=1;
let b=2;
let result=`文字${a+b}`;
document.write(result);
字符串查找
console.log(blog.indexOf(cc)); //ES5的方法是 返回的是6
console.log(blog.includes(cc)) //直接返回true
字符串查找
console.log(blog.indexOf(cc)); //ES5的方法是 返回的是6
console.log(blog.includes(cc)) //直接返回true
判断开头是否存在:
blog.startsWith(cc)
;
判断结尾是否存在:
blog.endsWith(cc);
!!starts和ends 后边都要加s
复制字符串
document.write('cc,'.repeat(3));
数值扩展
- 常量
Number.EPSILON ,属性表示 1 与大于 1 的最小浮点数之间的差。
它的值接近于 2.2204460492503130808472633361816E-16,或者 2-52。
测试数值是否在误差范围内:
0.1 + 0.2 === 0.3; // false
// 在误差范围内即视为相等
var equal = (Math.abs(0.1 - 0.3 + 0.2) < Number.EPSILON); // true
- 最大安全整数
安全整数:Number.MAX_SAFE_INTEGER
安全整数表示在 JavaScript 中能够精确表示的整数,安全整数的范围在 2 的 -53 次方到 2 的 53 次方之间(不包括两个端点),超过这个范围的整数无法精确表示。
最大安全整数
安全整数范围的上限,即 2 的 53 次方减 1 。 - 最小安全整数
安全整数范围的下限,即 2 的 53 次方减 1 的负数。
Number.MIN_SAFE_INTEGER
数组扩展
-
数组创建
Array.of()
将参数中所有值作为元素形成数组。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()
将类数组对象或可迭代对象转化为数组。// 参数为数组,返回与原数组一样的数组
console.log(Array.from([1, 2])); // [1, 2]// 参数含空位
console.log(Array.from([1, , 3])); // [1, undefined, 3]
参数
Array.from(arrayLike[, mapFn[, thisArg]])
返回值为转换后的数组。
arrayLike
想要转换的类数组对象或可迭代对象。
console.log(Array.from([1, 2, 3])); // [1, 2, 3]
mapFn
可选,map 函数,用于对每个元素进行处理,放入数组的是处理后的元素。
console.log(Array.from([1, 2, 3], (n) => n * 2)); // [2, 4, 6]
thisArg
可选,用于指定 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]
-
类数组对象
一个类数组对象必须含有 length 属性,且元素属性名必须是数值或者可转换为数值的字符。let arr = Array.from({
0: ‘1’,
1: ‘2’,
2: 3,
length: 3
});
console.log(); // [‘1’, ‘2’, 3]// 没有 length 属性,则返回空数组
let array = Array.from({
0: ‘1’,
1: ‘2’,
2: 3,
});
console.log(array); // []// 元素属性名不为数值且无法转换为数值,返回长度为 length 元素值为 undefined 的数组
let array1 = Array.from({
a: 1,
b: 2,
length: 2
});
console.log(array1); // [undefined, undefined] -
转换可迭代对象
转换 maplet map = new Map();
map.set(‘key0’, ‘value0’);
map.set(‘key1’, ‘value1’);
console.log(Array.from(map)); // [[‘key0’, ‘value0’],[‘key1’,
// ‘value1’]]
转换 set集合
let arr = [1, 2, 3];
let set = new Set(arr);
console.log(Array.from(set)); // [1, 2, 3]
转换字符串
let str = 'abc';
console.log(Array.from(str)); // ["a", "b", "c"]
- 扩展的方法
查找
find()
查找数组中符合条件的元素,若有多个符合条件的元素,则返回第一个元素。
let arr = Array.of(1, 2, 3, 4);
console.log(arr.find(item => item > 2)); // 3
// 数组空位处理为 undefined
console.log([, 1].find(n => true)); // undefined
findIndex()
查找数组中符合条件的元素索引,若有多个符合条件的元素,则返回第一个元素索引。
let arr = Array.of(1, 2, 1, 3);
// 参数1:回调函数
// 参数2(可选):指定回调函数中的 this 值
console.log(arr.findIndex(item => item = 1)); // 0
// 数组空位处理为 undefined
console.log([, 1].findIndex(n => true)); //0
填充
fill()
将一定范围索引的数组元素内容填充为单个指定的值。
let arr = Array.of(1, 2, 3, 4);
// 参数1:用来填充的值
// 参数2:被填充的起始索引
// 参数3(可选):被填充的结束索引,默认为数组末尾
console.log(arr.fill(0,1,2)); // [1, 0, 3, 4]
copyWithin()
将一定范围索引的数组元素修改为此数组另一指定范围索引的元素。
// 参数1:被修改的起始索引
// 参数2:被用来覆盖的数据的起始索引
// 参数3(可选):被用来覆盖的数据的结束索引,默认为数组末尾
console.log([1, 2, 3, 4].copyWithin(0,2,)); // [3, 4, 3, 4]
// 参数1为负数表示倒数
console.log([1, 2, 3, 4].copyWithin(-2, 0)); // [1, 2, 1, 2]
console.log([1, 2, ,4].copyWithin(0, 2, 4)); // [, 4, , 4]
遍历
entries()
遍历键值对。
for(let [key, value] of ['a', 'b'].entries()){
console.log(key, value);
}
// 0 "a"
// 1 "b"
// 不使用 for... of 循环
let entries = ['a', 'b'].entries();
console.log(entries.next().value); // [0, "a"]
console.log(entries.next().value); // [1, "b"]
// 数组含空位
console.log([...[,-'a'].entries()]); // [[0, undefined], [1, "a"]]
keys()
遍历键名。
for(let key of ['a', 'b'].keys()){
console.log(key);
}
// 0
// 1
// 数组含空位
console.log([...[,'a'].keys()]); // [0, 1]
values()
遍历键值。
for(let value of ['a', 'b'].values()){
console.log(value);
}
// "a"
// "b"
// 数组含空位
console.log([...[,'a'].values()]); // [undefined, "a"]
包含
includes()
数组是否包含指定值。
注意:与 Set 和 Map 的 has 方法区分;Set 的 has 方法用于查找值;Map 的 has 方法用于查找键名。
// 参数1:包含的指定值
[1, 2, 3].includes(1); // true
// 参数2:可选,搜索的起始索引,默认为0
[1, 2, 3].includes(1, 2); // false
// NaN 的包含判断
[1, NaN, 3].includes(NaN); // true
嵌套数组转一维数组
flat()
console.log([1 ,[2, 3]].flat()); // [1, 2, 3]
// 指定转换的嵌套层数
console.log([1, [2, [3, [4, 5]]]].flat(2)); // [1, 2, 3, [4, 5]]
// 不管嵌套多少层
console.log([1, [2, [3, [4, 5]]]].flat(Infinity)); // [1, 2, 3, 4, 5]
// 自动跳过空位
console.log([1, [2, , 3]].flat()); // [1, 2, 3]
flatMap()
先对数组中每个元素进行了的处理,再对数组执行 flat() 方法。
// 参数1:遍历函数,该遍历函数可接受3个参数:当前元素、当前元素索引、原数组
// 参数2:指定遍历函数中 this 的指向
console.log([1, 2, 3].flatMap(n => [n * 2])); // [2, 4, 6]
对象的扩展
对象属性的简洁写法
-
属性简写
var foo = “bar”;
var baz = { foo };
baz.foo
baz; // { foo: “baz” }
// 等价于
var baz = { foo: foo };function f(x, y) {
return { x, y };
// 等价于: return { x: x, y: y };
}
f(1, 2); // {x: 1, y: 2} -
方法简写
var obj = {
method() {
return “yuan is an animal”;
}
}
// 等价于
var obj = {
method: function() {
return “yuan is an animal”;
}
}
属性名表达式
在ES5中,定义对象的属性有两种方法
// 方法一:标识符作为属性名
obj.foo = true;
// 方法二:表达式作为属性名
obj[“foo”] = true;
如果使用字面量方式定义对象,在ES5中只能使用方法一,而在ES6中可以使用方法二:
let yuan = "monkey";
let animal = {
"type": "animal",
[yuan]: "yuan is not monkey"
"monkey":"yuan is not monkey"
}
animal["type"]; // "animal"
animal[yuan]; // "yuan is not monkey"
animal["monkey"]; // "yuan is not monkey"
属性名定义方法:
let monkey = {
['yuan']() {
return "yuan is a monkey";
}
}
monkey.yuan(); // yuan is a monkey"
-
方法的name 属性
对象中的方法,也具有类似 function 的 name 属性:let monkey = {
‘yuan’ {
return “yuan is a monkey”;
}
}
monkey.yuan.name; // “yuan” -
Object.is()
因在ES5中,并不能处理比较两个值是否严格相等,对于NaN,+0,-0等并不能做出严格相等来判断。
Object.is() 这个方法就是来弥补上述的缺陷的:+0 === -0; // true
NaN === NaN; // falseObject.is(+0, -0); // false
Object.is(NaN, NaN); // true -
Object.assign()
基本用法
定义:将源对象(sourceN,不知一个源对象)的所有可枚举属性复制到目标对象上(target)。
使用方式:Object.assign(target, source1, source2, …, sourceN)let target = { x: 1};
let s1 = { y: 2 };
let s2 = { z: 3 };
Object.assign(target, s1, s2); // {x: 1, y: 2, z: 3}
注意点
1、如果目标对象与源对象用同名属性,或多个源对象具有同名属性,则后面的属性会覆盖前面的属性:
let target2 = { x: 1};
let s3 = { x: 3, y: 2 };
let s4 = { y: 4, z: 3 };
Object.assign(target2, s3, s4); // {x: 3, y: 4, z: 3}
2、如果参数不是对象,则会先转成对象,在返回:
typeof Object.assign(3); // "object"
3、若参数中有undefined 或者 null,这两个参数不能放在目标对象的位置,否则会报错:
Object.assign(undefined); // Cannot convert undefined or null to object at Function.assign (<anonymous>)
Object.assign(null); // Cannot convert undefined or null to object at Function.assign (<anonymous>)
4、除了字符串会以数组的形式复制到目标对象上,其他值都不会产生效果:
let a1 = 'yuan';
let a2 = true;
let a3 = 11;
let a4 = NaN;
Object.assign({}, a1, a2, a3, a4); // {0: "y", 1: "u", 2: "a", 3: "n"}
5、Object.assign()这个方法是对对象引用的复制,即是浅复制,而不是深复制。这里需要规避同名属性替换带来的问题:
var obj1 = { a: { b: 3, c: 4 } };
var obj2 = { a: { b: "yuan" } } ;
Object.assign(obj1, obj2); // { a: { b: "yuan" } }
obj1.a.b; // "yuan"
基本用途
给对象添加属性
class Geo {
constructor(x, y) {
Object.assign(this, x, y);
}
}
给对象添加方法
Object.assig(SomeClass.prototype, {
someMethod(arg1, arg2) { ... },
anotherMethod() { ... }
})
克隆对象
function clone(originObj) {
return Object.assign({}, originObj); // 将原始对象复制给空对象
}
合并多个对象
const mergeObjs = {
(target, ...sources) => Object.assign(target, ...sources);
}
为属性指定默认值
const DEFAULTS = {
logleve: 0,
outputFormat: 'html'
};
function processContent(options) {
retrun Object.assign({}, DEFAULTS, options);
}
属性的可枚举性(Enumerable)
ES5 中有3个操作会忽略 Enumerable 为 false 的属性:
1、for…in 循环:只遍历对象自身的和继承的可枚举性。
2、Object.keys():返回对象自身的所有可枚举属性的键名。
3、JSON.stringify():只串行化对象自身的可枚举属性。
在ES6 中,Object.assign() 操作会忽略 Enumerable 为false 的属性。
在上面四个操作中,只有 for…in 操作会返回继承的属性,为了不使问题复杂化,只关心对象自身的属性。所以,尽量不要使用 for…in 循环,用 Object.keys() 代替。
ES6还规定,所有 Class 的原型的方法都是不可枚举的。
属性的遍历
在ES6 中有五种方法来遍历对象的属性:
1、for…in
返回对象自身的和继承的可枚举属性(不含 Symbol 属性)。
2、Object.keys(ob)
返回一个数组,包括对象自身的(不含继承)所有可枚举属性(不含 Symbol 属性)。
3、Object.getOwnPropertyNames(obj)
返回一个数组,包括自身的所有属性(不含Symbol属性,但包括不可枚举属性)。
4、Object.getOwnPropertySymbols(obj)
返回一个数组。包含对象自身的所有 Symbol 属性。
5、Object.ownKeys(obj)
返回一个数组,包含对象所有的属性.。
以上五种方法都遵循同样的遍历顺序:
(1)、首先遍历所有属性名为数值的属性,按数字排序;
(2)、其次遍历所有属性名为字符串的属性,按照生成时间排序;
(3)、最后遍历所有属性名为 Symbol 的属性,按照生成时间排序。
八、Object.keys(),Object.values(),Object.entries()
1、Object.keys(obj)
返回一个数组,是由参数对象自身的(不含继承)所有可遍历属性的键名:
/* Array 对象 */
let arr = ["a", "b", "c"];
console.log(Object.keys(arr));
// ['0', '1', '2']
/* Object 对象 */
let obj = { foo: "bar", baz: 42 },
keys = Object.keys(obj);
// CCAC: Chrome Console Auto Copy
copy(keys);
// ["foo","baz"]
/* 类数组 对象 */
let obj = { 0 : "a", 1 : "b", 2 : "c"};
console.log(Object.keys(obj));
// ['0', '1', '2']
// 类数组 对象, 随机 key 排序 (遵循上述的属性的遍历顺序)
let anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj));
// ['2', '7', '100']
/* getFoo 是个不可枚举的属性 */
var my_obj = Object.create(
{},
{ getFoo : { value : function () { return this.foo } } }
);
my_obj.foo = 1;
console.log(Object.keys(my_obj));
// ['foo']
2、Object.values(obj)
返回一个数组,是由参数对象自身的(不含继承)所有可遍历属性的键值:
var obj = { foo: "bar", baz: 42 };
console.log(Object.values(obj)); // ['bar', 42]
// 类数组对象
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']
// 随机键值的类数组对象 (遵循上述的属性的遍历顺序)
var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(an_obj)); // ['b', 'c', 'a']
// getFoo 是不可枚举属性
var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
my_obj.foo = "bar";
console.log(Object.values(my_obj)); // ['bar']
// 参数是非对象会转变成对象
console.log(Object.values("foo")); // ['f', 'o', 'o']
Object.values() 会过滤属性名为 Symbol 值的属性:
Object.values({ [Symbol() ]: 123, "foo": "faa"}) // ["faa"]
3、Object.entries(obj)
返回一个数组,是由参数对象自身的(不含继承)所有可遍历属性的键值对数组:
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
// 类数组对象
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
// 随机键值的类数组对象 (遵循上述的属性的遍历顺序)
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]
// getFoo 是不可枚举属性
const myObj = Object.create({}, { getFoo: { value() { return this.foo; } } });
myObj.foo = 'bar';
console.log(Object.entries(myObj)); // [ ['foo', 'bar'] ]
// 参数是非对象会转变成对象
console.log(Object.entries('foo')); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]
// 优雅地遍历键值
const obj = { a: 5, b: 7, c: 9 };
for (const [key, value] of Object.entries(obj)) {
console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
}
Object.entries() 的另一个用处:将对象转为真正的Map 数据结构:
var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }
iterator 和 for …of 循环
iterator 和 for …of 循环
Iterator 是 ES6 引入的一种新的遍历机制,迭代器有两个核心概念:
- 迭代器是一个统一的接口,它的作用是使各种数据结构可被便捷的访问,它是通过一个键为Symbol.iterator 的方法来实现。
- 迭代器是用于遍历数据结构元素的指针(如数据库中的游标)。
迭代器是带有特殊接口的对象。含有一个next()方法,调用返回一个包含两个属性的对象,分别是value和done,value表示当前位置的值,done表示是否迭代完,当为true的时候,调用next就无效了。
ES5中遍历集合通常都是 for循环,数组还有 forEach 方法,对象就是 for-in,ES6 中又添加了 Map 和 Set,而迭代器可以统一处理所有集合数据的方法。迭代器是一个接口,只要你这个数据结构暴露了一个iterator的接口,那就可以完成迭代。ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费。
for遍历
const fruits = ['apple','coconut','mango','durian'];
//for循环数组,通过下标取得每一项的值
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
forEach遍历
//数组的forEach方法,相对for循环语法更简单
fruits.forEach(fruit => {
console.log(fruit);
})
//forEach有个问题是不能终止循环
fruits.forEach(fruit => {
if(fruit === 'mango' ){
break; //Illegal break statement
}
console.log(fruit);
})
forin 遍历
//for...in循环,遍历数组对象的属性,MDN不推荐使用for...in遍历数组
//for...in循环会打印出非数字属性
const fruits = ['apple','coconut','mango','durian'];
fruits.fav = 'my favorite fruit';
for(let index in fruits){
console.log(fruits[index]); //...my favorite fruit
}
forof遍历
const fruits = ['apple','coconut','mango','durian'];
fruits.fav = 'my favorite fruit';
//ES6中的for...of循环,遍历属性值
for(let fruit of fruits){
console.log(fruit);
}
//支持终止循环,也不会遍历非数字属性
for(let fruit of fruits){
if(fruit === 'mango' ){
break;
}
console.log(fruit); //apple coconut durian
}
应用场景
//arguments是个类数组对象,通常先要将其转换为数组才能遍历,但for...of可以直接遍历
function sum() {
let sum = 0
for(let num of arguments){
sum += num
}
console.log(sum); //15
}
sum(1,2,3,4,5)
//遍历字符串
let name = 'Asher';
for (let char of name){
console.log(char); //A s h e r
}
//遍历nodelists,效果如下图
<style type="text/css">
.completed {
text-decoration: line-through;
}
</style>
<body>
<ul>
<li>yoga</li>
<li>boxing</li>
<li>press</li>
</ul>
<script type="text/javascript">
const lis = document.querySelectorAll('li');
for(let li of lis){
li.addEventListener('click',function(){
this.classList.toggle('completed');
})
}
</script>
</body>
set 和 map 数据结构
基本用法
set 数据容器 能够存储无重复值数据的有序列表
-
通过 new set() 方法创建容器 通过add() 方法添加
-
set.size获取存储的数据的数量
var set = new Set()
set.add(1);
set.add(‘1’);
console.log(set)
console.log(set.size) -
Set内部使用Object.is()方法来判断两个数据项是否相等
-
利用数组来构造set 且set 构造器不会存在重复的数据
var set1 = new Set([1,2,3,3,3,3,3,2]) // 结果数组会去重
-
可以使用has()方法来判断某个值是否存在于Set中
-
使用delete()方法从Set中删除某个值,或者使用clear()方法从Set中删除所有值
set1.delete(1)
console.log(set1)
set1.clear()
console.log(set1) -
forEach 遍历set
set2.forEach(function(value,key){
console.log(value)
console.log(key)
}) -
将数组转换成set 直接将数组放在new Set()参数中
ES6中提供了Map数据结构,能够存放键值对,其中,键的去重是通过Object.is()方法进行比较,键的数据类型可以是基本类型数据也可以是对象,而值也可以是任意类型数据。
-
创建map
var map = new Map()
-
使用set()方法可以给Map添加键值对 ,能够自动去重,和set原理一样,添加相同的元素会进行去重处理
var map = new Map()
console.log(map)
map.set(‘title’,‘baidu’)
map.set(‘year’,‘2018’); -
通过get()方法可以从Map中提取值,size方法同set一样,获取数组长度
console.log(map.get(‘year’)) // 2018
console.log(map.size) // 2 -
同set一样,也有 has(),delete(),clear() 方法
map.delete(‘title’);
map.clear();
console.log(map.has(‘year’)); -
forEach 遍历
map.forEach(function(value,key){
console.log(value) // 值 2018
console.log(key) // 健 year
})
set和map 的区别
都是用来存储数据用的,但是存储的数据格式不同
set 直接存储 任意类型数据
map 存储数据的时候,必须以key,value的形式,
set 使用forEach 遍历的时候,key和value值是一样的
而map 遍历的时候,key就是存进去的对象的key,value就是存在的值
promise对象的使用
解决回调地狱
let state=1;
function step1(resolve,reject){
console.log('1.开始-洗菜做饭');
if(state==1){
resolve('洗菜做饭--完成');
}else{
reject('洗菜做饭--出错');
}
}
function step2(resolve,reject){
console.log('2.开始-坐下来吃饭');
if(state==1){
resolve('坐下来吃饭--完成');
}else{
reject('坐下来吃饭--出错');
}
}
function step3(resolve,reject){
console.log('3.开始-收拾桌子洗完');
if(state==1){
resolve('收拾桌子洗完--完成');
}else{
reject('收拾桌子洗完--出错');
}
}
new Promise(step1).then(function(val){
console.log(val);
return new Promise(step2);
}).then(function(val){
console.log(val);
return new Promise(step3);
}).then(function(val){
console.log(val);
return val;
});
class类的使用
类里面是方法和函数
声明类
class Coder{
name(val){
console.log(val)
}
}
实例化类
let cc = new Coder;
cc.name('cc');