目录
扩展的对象的功能
1、ES6直接写入变量和函数,作为对象的属性和方法。
const name = "lw",age = 21;
const person = {
name,//等价于name:name
age,
sayName(){
console.log(this.name);
}
}
person.sayName();//lw
function fn(x,y) {
return{x,y};
}
console.log(fn(10,20));//Object { x: 10, y: 20 }
2、属性名的表达式
const name = "a";
const obj = {
isShow:true,
[name+"nc"]:123,
["f"+name]() {
console.log(this);
}
}
console.log(obj);
3、对象的方法
is()等价于===,比较两个值是否严格相等
console.log(Object.is(NaN,NaN));
assign(),对象的合并Object.assign(target,obj1,obj2)
把obj1,obj2合并到target,返回合并之后的新对象。
let newObj = Object.assign({}, {name:"lw"}, {age:12});
console.log(newObj);//Object { name: "lw", age: 12 }
Symbol
原始数据类型,它表示是独一无二的值。
最大用途:用来定义对象的私有变量
const name = Symbol("name");
const name2 = Symbol("name");
console.log(name === name2);//false
如果用Symbol定义的对象中的变量,取值时一定要用[变量名]
let s1 = Symbol("s1");
let obj = {
[s1]:"lw"
};
console.log(obj[s1]);//lw
可以利用Object.getOwnPropertySymbols(对象名)
或Reflect.ownKeys(对象名)
取该被Symbol定义的对象中的变量。
let s1 = Symbol("s1");
let obj = {};
obj[s1]="lw";
console.log(obj[s1]);//lw
let s = Object.getOwnPropertySymbols(obj);
console.log(s[0]);//Symbol("s1")
let m = Reflect.ownKeys(obj);
console.log(m[0]);
set
集合:表示无重复值的有序列表
let set = new Set();
//添加元素
set.add(3);
set.add([1,2,3])
//删除元素
set.delete(2);
//校验某个值是否在set中
console.log(set.has(4));
//set的长度
console.log(set.size);
//将set转换成数组
let set2 = new Set([1,2,"d",4,4,4,6]);
console.log(set2);//Set(5) [ 1, 2, "d", 4, 6 ]
//扩展运算符
let arr = [...set2]
console.log(arr);//Array(5) [ 1, 2, "d", 4, 6 ]
注意:set中对象的引用无法被释放
let set3 = new Set(),obj={};
set3.add(obj);
//释放当前资源
obj = null;
console.log(set3);//Set [ {} ],未被释放
WeakSet
1、不能传入非对象类型的参数
2、不可迭代
3、没有forEach()
4、没有size属性
Map
Map类型是键值对的有序数列,键和值是任意的类型。
let map = new Map();
map.set("name","lw");
map.set("age","23");
console.log(map.get("name"));
//校验
map.has("name");
//删除
map.delete("name");
//直接清楚
map.clear();
console.log(map);//Map(0)
let m = new Map([
["a",1],
["b",2]
]);
console.log(m);//Map { a → 1, b → 2 }
事实上,不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数。这就是说,Set和Map都可以用来生成新的 Map。
const set = new Set([
['foo', 1],
['bar', 2]
]);
const m1 = new Map(set);
console.log( m1.get('foo')) // 1
const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
console.log(m3.get('baz')) // 3
注意:
1、如果对同一个键多次赋值,后面的值将覆盖前面的值。
2、Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。
数组的扩展功能
数组的方法 from()
将伪数组转换成真正的数组
function add() {
// console.log(arguments);
//es5中转换
// let arr = [].slice.call(arguments);
// console.log(arr);
//es6中转换
let arr = Array.from(arguments);
console.log(arr);
}
add(1,3,4)
let lis = document.querySelectorAll("li");
console.log(Array.from(lis));
//用扩展运算符将伪数组转换成真正的数组
console.log([...lis]);
from()还可以接收第二个参数,用来对每个元素进行处理。
let arr2 = Array.from(lis,bc => bc.textContent);
console.log(arr2);
of()
将任意的数据类型转换到数组
let arr3 = Array.of(2,3,[1,2,4],"lw",{id:1});
console.log(arr3);
copywithin()
数组内部将制定位置的元素复制到其他的位置,返回当前的数组。
console.log([1,2,3,4,5,7,44].copyWithin(0,3));//用索引为3及以后的值替换索引为0及以后相应位置的值
find()
找出第一个符合条件的数组成员
let num = [1,3,4,5,-2,3-39,0].find(n => n<0);
console.log(num)//-2
findIndex()
找出第一个符合条件的数组成员的索引
let num = [1,3,4,5,-2,3-39,0].findIndex(n => n<0);
console.log(num)//4
entries() keys() values()
返回一个遍历器,可以使用for…of循环进行遍历
keys() 是对键名遍历
for(let index of[1,2,45,6,"a","b"].keys()){
console.log(index);0 1 2 3 4 5
}
values() 对值遍历
for(let index of[1,2,45,6,"a","b"].values()){
console.log(index);//1,2,45,6,a,b
}
entries() 对键值对遍历
for(let index of[1,2,45,6,"a","b"].entries()){
console.log(index);//Array [ 0, 1 ][ 1, 2 ][ 2, 45 ][ 3, 6 ][ 4, "a" ][ 5, "b" ]
}
next()方法,遍历一次得到相应的值,超出范围返回undefind。
let letter = ["a","b","c"];
let it = letter.entries();
console.log(it.next().value);
include()
返回一个布尔值,表示某个数组是否包含给定的值。
console.log([1,2,3].includes(2));
之前indexOf(),包含取1,不包含取-1
console.log([1,2,3].indexOf(9));
Iterator迭代器
是一种新的遍历机制,有两个核心
1、迭代器是一个接口,能快捷访问数据,通过Symbol.iterator创建迭代器,通过迭代器的next()获得迭代器的结果。
2、迭代器是用于遍历数据结构的指针(数据库的游标)
//使用迭代
const items = ["one","two","three"];
//1、创建新的迭代器
const ite = items[Symbol.iterator]();
console.log(ite.next())
//value: "one", done: false ,done如果为false表示遍历继续,如果为true表示遍历完成
注意:一个对象如果要具备可被for…of循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法(原型链上的对象具有该方法也可)。
Iterator迭代器
for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。
JavaScript 原有的for…in循环,只能获得对象的键名,不能直接获取键值。ES6 提供for…of循环,允许遍历获得键值。
var arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
console.log(a); // 0 1 2 3
}
for (let a of arr) {
console.log(a); // a b c d
}
注意:for…of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟for…in循环也不一样。
generator函数
可以通过yield关键字,将函数挂起,为了改变执行流提供了可能,同时为了做异步编程提供了方案。
与普通函数的区别:
1、function后面 函数名之前有个*
2、函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
function* func() {
yield 2;
}
//返回一个遍历器对象 可以调用next()
let o = func();
console.log(o.next());
总结:generator函数是分段执行的,yield语句是暂停执行,而next()恢复执行。
注意:
1、x不是yield "2"的返回值,它是next()方法调用恢复当前yield()执行传入的实参。
2、next()仿佛带的参数会被当作上一个yield表达式的返回值。
使用场景:为不具备Interator接口的对象提供了遍历操作
function* objectEntries(obj) {
//获取对象所有的key保存到数组
const propKeys = Object.keys(obj);
for(const propkey of propKeys){
yield [propkey,obj[propkey]]
}
}
const obj ={
name:"lw",
age:11
}
obj[Symbol.iterator] = objectEntries;
console.log(obj);
for (let [key,value] of objectEntries(obj)){
console.log(`${key},${value}`);
}
遍历器对象的next方法的运行逻辑如下:
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
Generator 函数可以不用yield表达式,这时就变成了一个单纯的暂缓执行函数。
function* f() {
console.log('执行了!')
}
var generator = f();
setTimeout(function () {
generator.next()
}, 2000);
next 方法的参数
yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
function* add() {
console.log("start");
let x = yield "2";
console.log("one"+x);
let y = yield "3";
console.log("two"+y);
return x+y ;
}
const fn = add();
console.log(fn.next());//value: "2", done: false
console.log(fn.next(10));//value: "3", done: false
console.log(fn.next(20));//value: 30, done: true
for…of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
// 1 2 3 4 5
异步和同步
所谓"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。
Promise 承诺
相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果。
Promise对象的两个特点:
1、对象的状态不受外界影响。处理异步操作,三种状态:pending(进行中)、resolved(已成功)和rejected(已失败)
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。两种可能:从pending变为fulfilled和从pending变为rejected。
执行过程:Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。Promise实例生成以后,可以用then方法分别指resolved状态和rejected状态的回调函数。
以下是指定多少秒后,状态从进行中变为已成功或失败,分别返回不同的值。
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(()=>{
if(ms<=1000){
resolve("已经过了"+ms+"秒了");}
else{
reject("超时了")}},ms);
});
}
//指定状态转换之后的操作
timeout(1200).then((value) => {
console.log(value);},
(error) =>{
console.log(error)
});//超时了
用Promise对象实现的 Ajax 操作的例子
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
resolve() reject()
能将现有的任何对象转换成promise对象。
let p = new Promise(resolve => resolve("123"));
p.then((data)=>{
console.log(data);
});
all()
应用:一些游戏素材较多,等待图片等资源文件都加载完成,然后才进行页面的初始化
let p1 = new Promise((resolve, reject) => {});
let p2 = new Promise((resolve, reject) => {});
let p3 = new Promise((resolve, reject) => {});
let p4 =Promise.all([p1,p2,p3])
p4.then(()=>{
//三个都成功才能成功
}).catch(err=>{
//只要有一个失败就失败
})
race()
给某个异步请求设置超时时间,并且在超时后执行相应的操作。Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p
.then(console.log)
.catch(console.error);
finally()
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。finally本质上是then方法的特例。