ECMAScript6(包含es6-es11)

ECMAScript6(包含es6-es11)

一、强大的babel

被称为下一代的JavaScript编译器,可以将es6的代码转换成es5的代码,从而让浏览器获得支持

Babel 的配置文件是.babelrc,存放在项目的根目录下。使用 Babel 的第一步,就是配置这个文件。

该文件用来设置转码规则和插件,基本格式如下:

{
  "presets": [],
  "plugins": []
}

presets字段设定转码规则,官方提供以下的规则集,你可以根据需要安装

# 最新转码规则
$ npm install --save-dev @babel/preset-env

# react 转码规则
$ npm install --save-dev @babel/preset-react

然后,将这些规则加入.babelrc

{
    "presets": [
      "@babel/env",
      "@babel/preset-react"
    ],
    "plugins": []
 }

注意,以下所有 Babel 工具和模块的使用,都必须先写好.babelrc.

命令行转码

Babel 提供命令行工具@babel/cli,用于命令行转码。它的安装命令如下:

$ npm install --save-dev @babel/cli

基本用法如下:

# 转码结果输出到标准输出
$ npx babel example.js

# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ npx babel example.js --out-file compiled.js
# 或者
$ npx babel example.js -o compiled.js

# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ npx babel src --out-dir lib
# 或者
$ npx babel src -d lib

# -s 参数生成source map文件
$ npx babel src -d lib -s

babel-node

@babel/node模块的babel-node命令,提供一个支持 ES6 的 REPL 环境。它支持 Node 的 REPL 环境的所有功能,而且可以直接运行 ES6 代码。

安装模块命令:

$ npm install --save-dev @babel/node

然后,执行babel-node就进入 REPL 环境:

$ npx babel-node
> (x => x * 2)(1)
2

babel-node命令可以直接运行 ES6 脚本。将上面的代码放入脚本文件es6.js,然后直接运行:

# es6.js 的代码
# console.log((x => x * 2)(1));
$ npx babel-node es6.js
2

babel/register模块

@babel/register模块改写require命令,为它加上一个钩子。此后,每当使用require加载.js.jsx.es.es6后缀名的文件,就会先用 Babel 进行转码。

安装模块:

$ npm install --save-dev @babel/register

使用时,必须首先加载@babel/register

// index.js
require('@babel/register');
require('./es6.js');

然后,就不需要手动对index.js转码了:

$ node index.js
2

需要注意的是,@babel/register只会对require命令加载的文件转码,而不会对当前文件转码。另外,由于它是实时转码,所以只适合在开发环境使用。

polyfill

Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API,比如IteratorGeneratorSetMapProxyReflectSymbolPromise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。

举例来说,ES6 在Array对象上新增了Array.from方法。Babel 就不会转码这个方法。如果想让这个方法运行,可以使用core-jsregenerator-runtime(后者提供generator函数的转码),为当前环境提供一个垫片。

安装命令如下。

$ npm install --save-dev core-js regenerator-runtime

然后,在脚本头部,加入如下两行代码。

import 'core-js';
import 'regenerator-runtime/runtime';
// 或者
require('core-js');
require('regenerator-runtime/runtime');

Babel 默认不转码的 API 非常多,详细清单可以查看babel-plugin-transform-runtime模块的definitions.js文件。

浏览器环境

Babel 也可以用于浏览器环境,使用@babel/standalone模块提供的浏览器版本,将其插入网页。

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
// Your ES6 code
</script>

注意,网页实时将 ES6 代码转为 ES5,对性能会有影响。生产环境需要加载已经转码完成的脚本。

Babel 提供一个REPL 在线编译器,可以在线将 ES6 代码转为 ES5 代码。转换后的代码,可以直接作为 ES5 代码插入网页运行。

二、let和const

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // var 变量提升
        /* console.log(a);
        var a = 2; */

        // 1、let声明变量,没有变量提升
        // console.log(a);//报错
        // let a = 10;
        // console.log(b);

        // 2、是一个块级作用域
        /* if(1===1){
            let b =10;
        } */
        // console.log(b);//报错


        /* var c=2;
        var c=4; */
        // console.log(c);//4

        // 3、不能重复声明
        // let c =1;
        // let c=4;//报错,c已经被声明了
        // console.log(c);


        
        // 1、不会变量提升
        // console.log(Max);//报错
        // const Max = 30;

       // const 2、声明常量,一旦被声明,无法修改const。一旦声明变量,就必须立即初始化,不能留到以后赋值。
        // Max =40;//报错
        // console.log(max);

        // 3、有块级作用域
        /* if(1===1){
            const Max = 30;
        }
        console.log(Max); */  //报错

        // 4、不能重复声明
        // const Max = 30;
        // const Max = 40;//报错

        /* const person ={
            name:'xiaolin'
        };
        person.name = 'XIAOLIN'; */ //可以修改属性
        // 不能修改整个对象
        /* person ={
            age:20
        };
        console.log(person.name); */

        //如果真的想将对象冻结,应该使用Object.freeze方法。
        
        const foo = Object.freeze({});

		// 常规模式时,下面一行不起作用;
		// 严格模式时,该行会报错
		foo.prop = 123;
        
        //除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。
        var constantize = (obj) => {
  			Object.freeze(obj);
  			Object.keys(obj).forEach( (key, i) => {
    		if ( typeof obj[key] === 'object' ) {
      		constantize( obj[key] );
    	   }
  	});
};
        
        
        
        

        /* var arr  = [];
        for(var i=0;i<10;i++){
            arr[i] = function(){
                return i;
            }
        }
        console.log(arr);
        console.log(arr[5]()); */  //10

        // 作用1:for循环(经典例子)
        const arr  = [];
        for(let i=0;i<10;i++){
            arr[i] = function(){
                return i;
            }
        }
        //上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
        console.log(arr);//
        console.log(arr[5]());//5

        // 作用2:不会污染全局变量
        let RegExp = 10;
        console.log(RegExp);
        console.log(window.RegExp);

        // 建议:在默认情况下用const,而只有你知道变量值需要被修改的情况下使用let

    </script>
</body>
</html>

另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域(同一个作用域不可使用 let 重复声明同一个变量)

暂时性死区

有些“死区”比较隐蔽,不太容易发现。

function bar(x = y, y = 2) {
  return [x, y];
}

bar(); // 报错

上面代码中,调用bar函数之所以报错(某些实现可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于“死区”。如果y的默认值是x,就不会报错,因为此时x已经声明了。

function bar(x = 2, y = x) {
  return [x, y];
}
bar(); // [2, 2]

顶层对象的属性

顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。

window.a = 1;
a // 1

a = 2;
window.a // 2

上面代码中,顶层对象的属性赋值与全局变量的赋值,是同一件事。

顶层对象的属性与全局变量挂钩,被认为是 JavaScript 语言最大的设计败笔之一。这样的设计带来了几个很大的问题,首先是没法在编译时就报出变量未声明的错误,只有运行时才能知道(因为全局变量可能是顶层对象的属性创造的,而属性的创造是动态的);其次,程序员很容易不知不觉地就创建了全局变量(比如打字出错);最后,顶层对象的属性是到处可以读写的,这非常不利于模块化编程。另一方面,window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合适的。

ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1

let b = 1;
window.b // undefined

上面代码中,全局变量avar命令声明,所以它是顶层对象的属性;全局变量blet命令声明,所以它不是顶层对象的属性,返回undefined

三、模板字符串

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="box">
        
    </div>
    <script>
        // 模板字符串:使用tab键上面的反引号,插入变量时使用${变量名}
        const oBox = document.querySelector('.box');;
        let id= 1,
        name="xiaolin";
        // oBox.innerHTML = "<ul><li><p id="+id+">"+name+"</p></li></ul>"
        // 使用反引号添加
        let htmlStr = `
        <ul>
            <li>
                <p id="${id}">${name}</p>
            </li>
        </ul>`;
        oBox.innerHTML = htmlStr;
    </script>
</body>
</html>

四、强大的函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 1、带参数默认值的函数
        // es5写法
        /* function add(a,b){
            a = a || 10;  //给a添加默认值
            b = b || 20;  //给b添加默认值
            return a+b;
        }
        consle.log(add()); */

        // 直接使用=给a和b添加默认值
        function add(a=10,b=20){
            return a+b;
        }
        // console.log(add(30));


        // 2、默认的表达式也可以是一个函数
        /* function add(a,b=getVal(5)){
            return a+b;
        }
        
        function getVal(val){
            return val +5;
        }
        consle.log(add(10)); */ //10+10=20


        
        // es5写法
        /* function pick(obj){
            let result = Object.create(null);
            for(let i=1;i<arguments.length;i++){
                // console.log(arguments[i]);
                result[arguments[i]] = obj[arguments[i]];
            }
            return result;
        }
        let book = {
            title:'es6hhh',
            author:'xiaolin',
            year:2022
        }
        let bookData  = pick(book,'author','year','author');
        console.log(bookData); */

        // 3、剩余参数:由三个点...和一个紧跟着的具体参数指定 ...keys
        function pick(obj,...keys){
            //...keys 解决了arguments的问题
            let result = Object.create(null);
            for(let i=1;i<keys.length;i++){
                result[keys[i]] = obj[keys[i]];
            }
            return result;
        }

        let book = {
            title:'es6hhh',
            author:'xiaolin',
            year:2022
        }
        let bookData  = pick(book,'author','year','author');
        // console.log(bookData);


        function checkArgs(...args){
            //剩余运算符:如果原来是对象:产生的就是对象;如果原来是数组,产生的就是数组
            console.log(args);
            console.log(arguments);
        }
        // checkArgs('a','b','c');



        // 4、扩展运算符...
        // 剩余运算符:把多个独立的参数合并到一个数组中
        // 扩展运算符:将一个数组分割,并将各个项作为分离的参数传给函数
        /* const maxNum = Math.max(20,30);
        console.log(maxNum); */

        // 处理数组中的最大值,使用apply
        const arr = [10,20,30,40,50,100,200,300];
        // console.log(Math.max.apply(null,arr)); //es5

        // es6扩展运算符更方便
        // console.log(Math.max(...arr));


        // 5、es6的箭头函数 *****
        // 使用 =>来定义  function(){} 等于()=>{}
       /*  let add =function(a,b){
            return a+b;
        } */

        /* let add = (a,b)=>{
            return a+b;
        } */

        /* let add = val =>{
            return val+5;
        } */

        // let add = val => (val+5);

        // let add = (a,b) =>a+b;
        // console.log(add(10,20));

        let fn = ()=> 'hello World'+123;
        // console.log(fn());

        /* let getObj = id =>{
            return {
                id:id,
                name:"xiaolin"
            }
        } */


        let getObj = id =>({id:id,name:"xiaolin"});
        let obj = getObj(1);
        // console.log(obj);

        /* let fn2 = (function(){
            return function(){
                console.log('hello es6');
            }
        })(); */

        let fn2 = (()=>{
            return ()=>{
                console.log('hello es6');
            }
        })();

        // fn2();



        // 6、箭头函数没有this绑定
        // es5中的this指向:取决于调用该函数的上下文对象
        /* let PageHandle = {
            id:123,
            init:function(){
                document.addEventListener('click',function(event){
                    console.log(this);//document
                    this.doSomethings(event.type);// this.doSomethings is not a function
                }.bind(this),false)
            },
            doSomethings:function(type){
                console.log(`事件类型:${type},当前id:${this.id}`);
            }
        }
        PageHandle.init(); */

        let PageHandle = {
            id:123,
            init:function(){
                // 箭头函数没有this指向,箭头函数内部this值只能通过查找作用域链
                // 一旦使用箭头函数,当前就不存在作用域链
                document.addEventListener('click',(event)=>{
                    console.log(this);//PagrHandle
                    this.doSomethings(event.type);
                })
            },
            doSomethings:function(type){
                console.log(`事件类型:${type},当前id:${this.id}`);
            }
        }
        // PageHandle.init();



        // 使用箭头函数的注意事项
        // 1、函数内部没有arguments
        let getVal=(a,b)=>{
            console.log(arguments);//arguments is not defined
            return a+b;
        }
        // console.log(getVal(1,3));

        // 2、箭头函数不能使用new关键字来实例化对象
        let Person = ()=>{
            
        };
        // function函数,也是一个对象,但是箭头函数不是一个对象,它其实是一个语法糖
        // let p =new Person();//报错



        </script>
</body>
</html>

五、解构赋值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 解构赋值是对赋值运算符的一种扩展
        // 针对数组和对象进行操作的
        // 优点:代码书写上简洁易读
        //如果解构不成功,变量的值就等于undefined。

        let node = {
            type:'iden',
            name:'foo'
        }
        /* let type =node.type;
        let name = node.name; */

        // 完全解构
        let {type,name}=node;
        // console.log(type,name);

        
        let obj={
            a:{
                name:"张三"
            },
            b:[1,2,3],
            c:'hello es6'
        }

        // 不完全解构
        // let {a} = obj;
        // console.log(a);

        // 剩余运算符
        //如果原来是对象:产生的就是对象;如果原来是数组,产生的就是数组
        // let {a,...res}=obj;
        // console.log(res);

        //注意:对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值
        
        //如果变量名与属性名不一致,必须写成下面这样。

		let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
		// baz "aaa"

		let obj = { first: 'hello', last: 'world' };
		let { first: f, last: l } = obj;
		//f 'hello'
		 //l 'world'
        
        
        
        
        // 运行指定默认值
        // let {a,b=30} = {a:20};

        // 对数组解构
        let arr = [1,2,3];
        // let [a,b] = arr;
        // console.log(a,b);

        // 可嵌套
        let [a,[b,b1,b2],c] = [1,[2,3,4],3];
        console.log(a,b,b1,b2,c);

        
    </script>
</body>
</html>

注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。

let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null

上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。

function f() {
  console.log('aaa');
}

let [x = f()] = [1];

上面代码中,因为x能取到值,所以函数f根本不会执行。上面的代码其实等价于下面的代码。

let x;
if ([1][0] === undefined) {
  x = f();
} else {
  x = [1][0];
}

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined

上面最后一个表达式之所以会报错,是因为xy做默认值时,y还没有声明

解构赋值的用途

(1)交换变量的值

let x = 1;
let y = 2;

[x, y] = [y, x];

上面代码交换变量xy的值,这样的写法不仅简洁,而且易读,语义非常清晰。

(2)从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

// 返回一个数组

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

(3)函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来。

// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

(4)提取 JSON 数据

解构赋值对提取 JSON 对象中的数据,尤其有用。

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

上面代码可以快速提取 JSON 数据的值。

(5)函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';这样的语句。

(6)遍历 Map 结构

任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

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 (let [key] of map) {
  // ...
}

// 获取键值
for (let [,value] of map) {
  // ...
}

(7)输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

const { SourceMapConsumer, SourceNode } = require("source-map");

六、扩展的对象的功能

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 1、es6直接写入变量和函数,作为对象的属性和方法
        // const name = 'xiaolin',age=21;
        /* const person ={
            name:name,
            age:age,
            sayName:function(){
                console.log(this.name);
            }
        } */
        // 等价于以下写法,同名省略
        const name = 'xiaolin',age=21;
        const person ={
            name,
            age,
            sayName(){
                console.log(this.name);
            }
        }
        // person.sayName();

        /* function fn(x,y){
            return {x,y};
        } */
        let fn = (x,y)=>({x,y});
        // console.log(fn(10,20));

        let cart = {
            wheel:4,
            set(newVal){
                if(newVal<this.wheel){
                    throw new Error('轮子数太少了');
                }
                this.wheel=newVal;
            },
            get(){
                return this.wheel;
            }
        }
        // console.log(cart.get());
        // cart.set(3);
        // console.log(cart.get());



        /* const obj = {};
        obj.isShow = true;
        const name = 'a';
        obj[name+'bc']=123;
        // console.log(obj);

        obj['f'+'bc']=function(){
            console.log(this);
        }
        console.log(obj); */

        const name1 = 'a';
        const obj={
            isShow:true,
            [name1+'bc']:123,
            ['f'+name1]:function(){
            console.log(this);
            }
        };
        // console.log(obj);


        // 对象的方法
        // is() ==== 比较两个值是否严格相等
        // 解决NaN的问题
        // console.log(NaN===NaN);//false
        // console.log(Object.is(NaN,NaN));//true


        // assign() 对象的合并*****
        // Object.assign(target,obj1,obj2,...);
        // 返回合并之后的新对象,浅拷贝
        let newObj = Object.assign({},{a:1},{b:2});
        // console.log(newObj);
    </script>
</body>
</html>

七、Symbol

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 原始数据类型Symbol,它表示的是独一无二的值
        // 最大用途:用来定义对象的私有变量
        const name = Symbol('name');
        const name2 = Symbol('name');
        // console.log(name===name2);//false
        // console.log(name);//Symbol(name)
        // console.log(name2);//Symbol(name)
        // console.log(typeof name);//symbol

        let s1 = Symbol('s1');
        // console.log(s1);
        let obj = {
            [s1]:'xiaolin'
        };
        // obj[s1]='xiaolin';
        // 如果用Symbol定义的对象中的变量,取值时一定要用[变量名]
        // console.log(obj[s1]);

        //可枚举可以理解为是否可以被遍历被列举出来,可枚举性决定了这个属性能否被for…in查找遍历到。
        /* for(let key in obj){
            console.log(key);//无法输出
        } */

        // [s1]不可枚举,所以输出空数组
        // console.log(Object.keys(obj));

        // 获取Symbol声明的属性名(作为对象的key)
        let s = Object.getOwnPropertySymbols(obj);
        // console.log(s);
        // console.log(s[0]);

        //静态方法 Reflect.ownKeys() 返回一个由目标对象自身的属性键组成的数组。
        let m = Reflect.ownKeys(obj);
        // console.log(m);

    </script>
</body>
</html>

八、Map和Set

1、Set

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 集合:表示无重复值的有序列表
        let set = new Set();
        // console.log(set);
        // 添加元素
        set.add(2);
        set.add('2');
        set.add(["hello",1,2,3]);
        // 删除元素
        set.delete('2');
        // 检验某个值是否在set中
        // console.log(set.has(2));
        // console.log(set);
        // 集合的长度
        // console.log(set.size);

        // key和val是一样的
        set.forEach((val,key)=>{
            // console.log(val,key);
        });

        // 将set转换成数组(去除数组中的重复内容)
        let set2 = new Set([1,2,3,4,5,4,3]);
        // 扩展运算符
        let arr = [...set2];
        // console.log(arr);

        // 1、set中的对象的引用无法被释放
        let set3 = new Set(),obj={a:1};
        set3.add(obj);

        // 释放obj对象
        obj = null;
        // console.log(set3);//依然存在obj

        let set4 = new WeakSet(),obj1={a:1};
        set4.add(obj1);

        // 释放obj对象
        obj1 = null;
        console.log(set4);

        /* 
            WeakSet
            1、不能传入非对象类型的参数
            2、不可迭代
            3、没有forEach()
            4、没有size属性
        */
    </script>
</body>
</html>

2、Map

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // Map类型是键值对的有序列表,键和值是任意类型
        /* let map = new Map();
        map.set('name','张三');
        map.set('age',21);
        console.log(map.get('name'));
        console.log(map);
        map.has('name');
        map.delete('name');
        console.log(map);
        map.clear();
        console.log(map);
        
        map.set(['a',1,2],"hello");
        console.log(map); */

        let m = new Map([
            ['a',1],
            ['c',2]
        ]);
        console.log(m);

        // WeakMap和WeakSet类似
        let map2  = new WeakMap();
    </script>
</body>
</html>

九、数组的扩展功能

1、扩展方法1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        // 数组的方法 from() of()
        //1、form()将伪数组转换为真正的数组
        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,2,3);

        let lis = document.querySelectorAll('li');
        // console.log(lis);

        // console.log(Array.from(lis));
        // 扩展运算符,将伪数组转换为真正的数组
        // console.log([...lis]);

        // from()还可以接收第二个参数,用来对每个元素进行处理
        let liContents = Array.from(lis,ele=>ele.textContent);
        // console.log(liContents);


        //2、of()将一组值(任意类型),转换为数组
        let arr = console.log(Array.of(3,11,'20',[1,3],{id:1}));

        // 3、copywithin()复制3索引开始位置往后的内容替换0索引开始往后的内容
        console.log([1,2,3,8,9,10].copyWithin(0,3));//[8,9,10,8,9,10]

        // 4、find()  findIndex()
        // find()找到一个符合条件的数组成员并返回
        let num = [1,2,-10,-20,9,2].find(n=>n<0);
        console.log(num);
        // findIndex()找到一个符合条件的数组成员的索引并返回
        let numIndex = [1,2,-10,-20,9,2].findIndex(n=>n<0);
        console.log=(numIndex);
    </script>
</body>
</html>

2、扩展方法2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //5、entries() keys() values()返回一个遍历器,可以使用for...of循环进行遍历
        //keys()对键名遍历
        // values()对值进行遍历
        // entries()对键值对遍历

        console.log(['a','b'].keys());

        // 取索引
        for(let index of ['a','b'].keys()){
            console.log(index);
        }

        for(let value of ['a','b'].values()){
            console.log(value);
        }

        /* let arr = new Array;
        for(let arr of ['a','b'].entries()){
            console.log(arr[0],arr[1]);
        } */

        for(let [index,ele] of ['a','b'].entries()){
            console.log(index,ele);
        }

        let letter = ['a','b','c'];
        let it = letter.entries();
        /* console.log(it.next().value);
        console.log(it.next().value);
        console.log(it.next().value);
        console.log(it.next().value); */


        // 6、includes()返回一个布尔值,表示某个数组是否包含给定的值
        console.log([1,2,3].includes(2));//true
        console.log([1,2,3].includes(4));//false

        // 以前的indexOf()
        console.log([1,2,3].indexOf(3));//返回的是索引的位置
    </script>
</body>
</html>

十、迭代器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // Iterator
        // 是一种新的遍历机制
        // 1、迭代器是一个接口,能快捷的访问数据
        // 通过Symbol.iterator来创建迭代器,通过迭代器的next()来获取迭代之后的结果
        // 2、迭代器是用于遍历数据结构的指针(数据库的游标)
        

        // 使用迭代
        const items = ['one','two','three'];
        // 创建新的迭代器
        const ite = items[Symbol.iterator]();
        console.log(ite.next());//{value: "one", done:false} done表示是否遍历完成,false未完成,true为完成
        console.log(ite.next());
        console.log(ite.next());
        console.log(ite.next());
    </script>
</body>
</html>

十一、生成器

1、生成器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //generator函数,可以通过yield关键字,将函数挂起,为了改变执行流程提供了可能,同时为异步编程也提供了方案
        // 它和普通函数的区别
        // 1、function后面 函数名之前有个*
        // 2、只能在函数内部使用yield表达式,让函数挂起

        function* func(){
            console.log("one");
            yield 2;
            console.log("two");
            yield 3;
            console.log("end");
        }
        // 返回一个遍历对象,可以调用next()
        let fn = func();
        // console.log(fn.next());
        // console.log(fn.next());
        // console.log(fn.next());

        // 总结:generator函数是分段执行的,yield语句是暂停执行,而next()是恢复执行

        function* add(){
            console.log("start");
            let x = yield '2';
            console.log("one:"+x);
            let y = yield '3';
            console.log("two:"+y);
            console.log("total:"+(x+y));
            // return x+y;
        }

        const fn1 = add();
        /* console.log(fn1.next());//在yield '2'处,停下,{value:'2',done:false}
        console.log(fn1.next(20));//在yield '3'处停下,20给x传值,x变为20,输出one:20,{value:'3',done:false};
        console.log(fn1.next(30));//30给y传值,输出 two:30,{value:50,done=true};
        console.log(fn.return(100)); */

        // 使用场景,为不具备Iterator接口的对象提供了遍历操作
        function* objectEntires(obj){
            // 获取对象的所有key保存到数组[name,age]
            const propkeys = Object.keys(obj);
            for(const propkey of propkeys){
                yield [propkey,obj[propkey]];
            }
        }

        const obj = {
            name:"小林",
            age:21
        }

        // obj[Symbol.iterator] = objectEntires;
        // console.log(obj);
        
        for(let [key,value] of objectEntires(obj)){
            console.log(`${key}:${value}`);
        }

    </script>
</body>
</html>

2、Generator的应用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
    <script>

        /* 
            Generator  部署ajax操作,让异步代码同步化
        */



        // 回调地狱
        // $.ajax({
        //     url:'http://127.0.0.1:5500/test.html',
        //     method:'get',
        //     success(res){
        //         console.log(res);
        //         // 继续发送请求
        //         /* $.ajax({
        //             url:'',
        //             method:'',
        //             success(res1){
        //             console.log(res1);
        //             // 继续发送请求
                        
        //             }
        //         }) */
        //     }
        // });

        /* const a = 10;
        const b = 20; */


        /* function* main(){
            let res = yield request('url');
            console.log(res);

            // 执行后面操作
            console.log("数据请求完成,可以继续操作");
        }

        const ite = main();
        ite.next();

        function request(url){
            $.ajax({
                url,
                method:'get',
                success(res){
                    ite.next(res);
                }
            });
        } */


        // 加载locaing...页面
        // 数据加载完成...
        // loading关闭掉

        function* load(){
            loadUI();
            yield showData();
            hideUI();
        }
        
        let itLoad = load();
        itLoad.next();

        function loadUI(){
            console.log("加载loading...页面");
        }
        function showData(){
            setTimeout(()=>{
                console.log("数据加载完成");
                itLoad.next();
            },5000);
        }
        function hideUI(){
            console.log("隐藏loading...页面");
        }
        /* loadUI();
        showData();
        hideUI(); */

        /* function showData1(){
            console.log("加载loading...页面");
            setTimeout(()=>{
                console.log("数据加载完成");
                console.log("隐藏loading...页面");
            },1000);
        }

        showData1(); */


        
    </script>
</body>
</html>

十二、Promise

1、Promise对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // Promise  承诺
        // 相对于一个容器,保存着未来才会结束的事件(异步操作)的一个结果
        // 各种异步操作都可以用同样的方法进行处理axios

        /* 
            特点:
            1、对象的状态不受外界影响,处理异步操作有三个操作  Pending(进行中) Resolved(成功) Rejected(失败)
            2、一旦状态改变,就不会再变,任何时候都可以得到这个结果
        */

        /* let pro = new Promise(function(resolved,rejected){
            // 执行异步操作
            let res = {
                code:404,
                data:{
                    name: 'xiaolin'
                },
                error:"请求失败"
            }
            setTimeout(()=>{
                if(res.code===200){
                    resolved(res.data);
                }else{
                    rejected(res.error);
                }
            },2000);
        });

        console.log(pro);

        pro.then((val)=>{
            console.log(val);
        },(err)=>{
            console.log(err);
        }); */


        function timeOut(ms){
            return new Promise((resolved,rejected)=>{
                setTimeout(()=>{
                    resolved("请求成功!");
                },ms);
            });
        }

        timeOut(5000).then((val)=>{
            console.log(val);
        });
        
    </script>
</body>
</html>

2、使用Promise封装ajax

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>

        const getJSON = function(url){
            return new Promise((resolve,reject)=>{
                const xhr = new XMLHttpRequest();
                xhr.open('GET',url);
                xhr.onreadystatechange = handler;
                xhr.responseType='json';
                xhr.setRequestHeader('Accept','application/json');
                // 发送
                xhr.send();
                function handler(){
                    // console.log(this.readyState);
                    if(this.readyState===4&&this.status==200){
                        resolve(this.response);
                    }else{
                        reject(new Error(this.statusText));
                    }
                }
            });
        }

        /* getJSON("http://127.0.0.1:5500/test.html")
        .then((data)=>{
            console.log(data);
        },(error)=>{
            console.log(error);
        }); */



       /*  getJSON('http://127.0.0.1:5500/test.html')
            .then((data)=>{
                console.log(data);
            }).then(null,err=>{

            }); */

            // 等价于下面

        getJSON('http://127.0.0.1:5500/test.html')
            .then(data=>{
                console.log(data);
            }).catch(err=>{
                console.log(err);
            });


        // then()方法
        /* 
            then()第一个参数就是resolve回调函数,第二个参数是可选的,是reject状态回调函数
            then()返回一个新的Promise实例,可以采用链式编程
        */
        
    </script>
</body>
</html>

3、Promise的其他方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="div">正在加载图片....</div>
    <script>
        // 1、resolve()能将现有的任何对象转换为promise对象

        // let p =Promise.resolve('foo');
        /* let p =new Promise(resolve=>resolve('foo'));
        // console.log(p);
        p.then((data)=>{
            console.log(data);
        }); */



        // 2、all()应用:一些游戏类的素材,等待图片、flash、等等静态资源等加载完成后才进行页面初始化
        /* let pro1 = new Promise((resolve,reject)=>{

        });
        let pro2 = new Promise((resolve,reject)=>{

        });
        let pro3 = new Promise((resolve,reject)=>{

        });

        let p4 = Promise.all([pro1,pro2,pro3]);
        p4.then(()=>{
            //三个都成功才成功
        }).catch(err=>{
            // 如果有一个失败了,就失败了
        }); */




        const div = document.getElementById('div');
        
        // 3、race():某个异步请求设置超时时间,并且在超时后执行相应的操作
        // 请求图片资源
        function requestImg(imgSrc){
            return new Promise((resolve,reject)=>{
                const img = new Image();
                img.onload = function(){
                    resolve(img);
                }
                img.src = imgSrc;
            });
        }

        function timeOut(){
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    reject(new Error("图片请求超时"));                    
                },5000);
            });
        }

        Promise.race([requestImg('https://ts2.cn.mm.bing.net/th?id=OIP-C.tV58EvgJSzLG3iOTLzB85QHaEo&w=316&h=197&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2'),timeOut()]).then(data=>{
            console.log(data);
            div.innerHTML="";
            document.body.appendChild(data);
        }).catch(err=>{
            console.log(err);
            div.innerText="您的网速过慢,图片请求失败!";
        });


        /* 
        
            done()和finnally()  无论成功还是失败都会执行
        */
        /* 
            server.listen(3000).then(()=>{

            }).finnally(server.stop());

        */





    </script>
</body>
</html>

十三、async的用法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        /* 
            async作用:使得异步操作更加方便
            基本操作 async他会返回一个Promise对象
            就可以使用then catch
            是generator的一个语法糖
        */

        /* 
            Generator  Promise  async
            1、解决回调地域
            2、使得异步操作变得方便
            
        */
        async function f(){
            // return await 'hello async';
            let s =  await 'hello async';
            let data = await s.split('');
            return data;
        }
        // 如果async函数中有多个await,那么then函数会等待所有await指令。运行完的结果才去执行
        // console.log(f);
        f().then(v=>{
            console.log(v);
        }).catch(e=>{
            console.log(e);
        });

        async function f2(){
            // throw new Error("出错了!");
            try {
                await Promise.reject("出错了");
            } catch (error) {
                
            }
            return await Promise.resolve("hello");
        }
        f2().then(v=>console.log(v)).catch(e=>console.log(e));


        // 需求,获取和风天气 现在now的数据

        const getJSON = function(url){
            return new Promise((resolve,reject)=>{
                const xhr = new XMLHttpRequest();
                xhr.open('GET',url);
                xhr.onreadystatechange = handler;
                xhr.responseType='json';
                xhr.setRequestHeader('Accept','application/json');
                // 发送
                xhr.send();
                function handler(){
                    // console.log(this.readyState);
                    if(this.readyState===4&&this.status==200){
                        resolve(this.response);
                    }else{
                        reject(new Error(this.statusText));
                    }
                }
            });
        }

        async function getNowWeather(url){
            // 发送ajax  获取实况天气
            let res = await getJSON(url);
            console.log(res);
            // 获取HeWeather6的数据   获取未来3-7天的天气
            let arr =await res.HeWeather6;
            return arr[0].now;

        }
        getNowWeather("url")
            .then(now=>{
                console.log(now);
            })
    </script>

</body>
</html>

十四、class类

1、类的简介

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // es5造类
        /* function Person(name,age){
            this.name,
            this.age=age
        }
        Person.prototype.sayName=function(){
            return this.name;
        }
        let p1 = new Person('xiaolin',21); */
        // console.log(p1);

        // es6
        class Person{
            // 实例化的时候会立即被调用
            constructor(name,age){
                this.name=name,
                this.age
            }
            /* sayName(){
                return this.name;
            }
            sayAge(){
                return this.age;
            } */
        }
        // 通过Object.assign方法一次性向类的原型添加多个方法
        Object.assign(Person.prototype,{
            sayName(){
                return this.name;
            },
            sayAge(){
                return this.age;
            }
        });

        let p2 = new Person('xiaolin',21);
    </script>
</body>
</html>

2、类的继承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 使用关键字extends
        class Animal{
            constructor(name,age){
                this.name=name;
                this.age=age;
            }
            sayName(){
                return this.name;
            }
            sayAge(){
                return this.age;
            }
        }
        class Dog extends Animal{
            constructor(name,age,color){
                super(name,age);
                // Animal.call(this,name,age);
                this.color=color;
            }
            sayColor(){
                return this.color;
            }
            // 重写
            sayName(){
                console.log("我叫:"+ this.name);
            }
        }

        let d = new Dog('xiaoh',3,'yellow');
        console.log(d);
        d.sayName();
        console.log( d.sayColor());
        

        // 思考:如何让多个类,混入到一个类中
    </script>
</body>
</html>

十五、module模块的应用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="module">
        // import obj,{name,age,sayName} from './modules/index.js'
        import * as f from './modules/index.js'
        // console.log(obj);
        console.log(f.default);
        console.log(f.name);
        // console.log(name,age,sayName());
    </script>
</body>
</html>
// es6模块功能主要有两个命令构成:export和import
// export用于规定模块的对外接口,import用于输入其他模块提供的功能

/* 
    一个模块就是一个独立的文件
*/
export const name ='XIAOLIN';
export const age =18;
export const sayName = function(){
    return "my name is xiaolin";
};


function  sayName1(){
    return "my name is xiaolin";
};
export {sayName1};

/* const obj ={
    foo:'foo'
} */

class Person{
    constructor(){

    }
    sayName(){
        
    }
}
// export default obj;
export default Person;

       this.age=age;
        }
        sayName(){
            return this.name;
        }
        sayAge(){
            return this.age;
        }
    }
    class Dog extends Animal{
        constructor(name,age,color){
            super(name,age);
            // Animal.call(this,name,age);
            this.color=color;
        }
        sayColor(){
            return this.color;
        }
        // 重写
        sayName(){
            console.log("我叫:"+ this.name);
        }
    }

    let d = new Dog('xiaoh',3,'yellow');
    console.log(d);
    d.sayName();
    console.log( d.sayColor());
    

    // 思考:如何让多个类,混入到一个类中
</script>
```

十五、module模块的应用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="module">
        // import obj,{name,age,sayName} from './modules/index.js'
        import * as f from './modules/index.js'
        // console.log(obj);
        console.log(f.default);
        console.log(f.name);
        // console.log(name,age,sayName());
    </script>
</body>
</html>
// es6模块功能主要有两个命令构成:export和import
// export用于规定模块的对外接口,import用于输入其他模块提供的功能

/* 
    一个模块就是一个独立的文件
*/
export const name ='XIAOLIN';
export const age =18;
export const sayName = function(){
    return "my name is xiaolin";
};


function  sayName1(){
    return "my name is xiaolin";
};
export {sayName1};

/* const obj ={
    foo:'foo'
} */

class Person{
    constructor(){

    }
    sayName(){
        
    }
}
// export default obj;
export default Person;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值