学习ES6====记录时间 2021 09 02

风景

ES6 前言

ES6 从开始制定到最后发布,整整用了 15 年。

前面提到,ECMAScript 1.0 是 1997 年发布的,接下来的两年,连续发布了 ECMAScript 2.0(1998 年 6 月)和 ECMAScript 3.0(1999 年 12 月)。3.0 版是一个巨大的成功,在业界得到广泛支持,成为通行标准,奠定了 JavaScript 语言的基本语法,以后的版本完全继承。直到今天,初学者一开始学习 JavaScript,其实就是在学 3.0 版的语法。

2000 年,ECMAScript 4.0 开始酝酿。这个版本最后没有通过,但是它的大部分内容被 ES6 继承了。因此,ES6 制定的起点其实是 2000 年。

为什么 ES4 没有通过呢?因为这个版本太激进了,对 ES3 做了彻底升级,导致标准委员会的一些成员不愿意接受。ECMA 的第 39 号技术专家委员会(Technical Committee 39,简称 TC39)负责制订 ECMAScript 标准,成员包括 Microsoft、Mozilla、Google 等大公司。

2007 年 10 月,ECMAScript 4.0 版草案发布,本来预计次年 8 月发布正式版本。但是,各方对于是否通过这个标准,发生了严重分歧。以 Yahoo、Microsoft、Google 为首的大公司,反对 JavaScript 的大幅升级,主张小幅改动;以 JavaScript 创造者 Brendan Eich 为首的 Mozilla 公司,则坚持当前的草案。

2008 年 7 月,由于对于下一个版本应该包括哪些功能,各方分歧太大,争论过于激烈,ECMA 开会决定,中止 ECMAScript 4.0 的开发,将其中涉及现有功能改善的一小部分,发布为 ECMAScript 3.1,而将其他激进的设想扩大范围,放入以后的版本,由于会议的气氛,该版本的项目代号起名为 Harmony(和谐)。会后不久,ECMAScript 3.1 就改名为 ECMAScript 5。

2009 年 12 月,ECMAScript 5.0 版正式发布。Harmony 项目则一分为二,一些较为可行的设想定名为 JavaScript.next 继续开发,后来演变成 ECMAScript 6;一些不是很成熟的设想,则被视为 JavaScript.next.next,在更远的将来再考虑推出。TC39 委员会的总体考虑是,ES5 与 ES3 基本保持兼容,较大的语法修正和新功能加入,将由 JavaScript.next 完成。当时,JavaScript.next 指的是 ES6,第六版发布以后,就指 ES7。TC39 的判断是,ES5 会在 2013 年的年中成为 JavaScript 开发的主流标准,并在此后五年中一直保持这个位置。

2011 年 6 月,ECMAScript 5.1 版发布,并且成为 ISO 国际标准(ISO/IEC 16262:2011)。

2013 年 3 月,ECMAScript 6 草案冻结,不再添加新功能。新的功能设想将被放到 ECMAScript 7。

2013 年 12 月,ECMAScript 6 草案发布。然后是 12 个月的讨论期,听取各方反馈。

2015 年 6 月,ECMAScript 6 正式通过,成为国际标准。从 2000 年算起,这时已经过去了 15 年。

ES6概述

ECMAScript6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。Mozilla公司将在这个标准的基础上,推出JavaScript2.0。ECMA Script,JavaScript的语言标准。

let和const命令

ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

上面代码在代码块之中,分别用let和var声明了两个变量。然后在代码块之外调用这两个变量,结果let声明的变量报错,var声明的变量返回了正确的值。这表明,let声明的变量只在它所在的代码块有效。

for循环的计数器,就很合适使用let命令。

for (let i = 0; i < 10; i++) {
  // ...
}

console.log(i);
// ReferenceError: i is not defined

上面代码中,计数器i只在for循环体内有效,在循环体外引用就会报错。

下面的代码如果使用var,最后输出的是10。

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。

如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

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


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

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

不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

// 报错
function func() {
  let a = 10;
  var a = 1;
}

// 报错
function func() {
  let a = 10;
  let a = 1;
}

因此,不能在函数内部重新声明参数。

function func(arg) {
  let arg;
}
func() // 报错
function func(arg) {
  {
    let arg;
  }
}
func() // 不报错
ES6 的块级作用域

let实际上为 JavaScript 新增了块级作用域。

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

上面的函数有两个代码块,都声明了变量n,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是 10。

{{{{
  {let insane = 'Hello World'}
  console.log(insane); // 报错
}}}};

ES6 允许块级作用域的任意嵌套。

{{{{
  let insane = 'Hello World';
  {let insane = 'Hello World'}
}}}};

上面代码使用了一个五层的块级作用域,每一层都是一个单独的作用域。第四层作用域无法读取第五层作用域的内部变量。内层作用域可以定义外层作用域的同名变量。

// IIFE 写法
(function () {
  var tmp = ...;
  ...
}());

// 块级作用域写法
{
  let tmp = ...;
  ...
}

块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。

为什么需要块级作用域?

ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。

const 命令

基本用法
const声明一个只读的常量。一旦声明,常量的值就不能改变。

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

上面代码表明改变常量的值会报错。

const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const foo;
// SyntaxError: Missing initializer in const declaration

上面代码表示,对于const来说,只声明不赋值,就会报错。
const的作用域与let命令相同:只在声明所在的块级作用域内有效。

if (true) {
  const MAX = 5;
}

MAX // Uncaught ReferenceError: MAX is not defined

const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

if (true) {
  console.log(MAX); // ReferenceError
  const MAX = 5;
}

上面代码在常量MAX声明之前就调用,结果报错。

const声明的常量,也与let一样不可重复声明。

var message = "Hello!";
let age = 25;

// 以下两行都会报错
const message = "Goodbye!";
const age = 30;

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

函数默认参数与箭头函数

函数默认参数

在方法的参数后面加上一个默认值即可

代码演示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        // 默认参数 给参数列表设定初始值
        function add(a =100,b=100) {
            console.log(a,b);    
        }
        // 执行方法,会用默认值填充,打印出来100,100
        add();
        // 覆盖默认值打印  结果是1,2      
        add(1,2);
        
         打印结果
        // 100 100
        // 1  2
    </script>
</body>
</html>

箭头函数
箭头函数简化函数的定义,可以让我们不用使用function关键字
箭头函数三个特点:

1 不需要function关键字来创建函数
2 省略return关键字
3 继承当前上下文的 this 关键字

代码演示:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>箭头函数</title>
</head>
<body>
    <script>
        // 箭头函数
        // 它也是一种函数的定义,它简化定义仅此而已。
        // 步骤:1:去掉function  2: 括号后面加箭头  3: 如果逻辑代码仅有return可以直接省去。 4: 如果参数只有一个,可以把括号省去
        // 1: 声明式的定义
        function add (a,b){
            return a+b;
        };
        // 2: 表达式的定义
        var add2 = function(a,b){
            return a+b;
        }     
        // 3: 箭头函数的定义
        var sum = (a = 100,b = 300)=>{
            console.log(a+b);
        };
        // 这里执行箭头函数
        sum(50,50);
        // 这里执行箭头函数
        sum();
        // 这里执行箭头函数
        sum(400);
    </script>
///  运行结果 
/// 100
/// 400
/// 700
</body>
</html>

箭头函数深度学习

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>箭头函数</title>
</head>
<body>
    <script>
        // 箭头函数
        // 它也是一种函数的定义,它简化定义仅此而已。
        // 步骤:1:去掉function  2: 括号后面加箭头。
        
        // 无参数的函数
        //var sum = function(){
        //}
        // 箭头改造如下
        //var sum = ()=>{}
        
        // 有参数
        // 第一种情况  一个参数的如下
        //var sum2 = function(a){
        //};
        // 箭头改造如下
        var sum2 = (a)=>{};
        var sum2 = a=>{
            return a;
        };
        
        // 第二种情况 二个参数的以上,记住括号一定要加
        //var sum3 = function(a,b){
        //    return a + b;
        //};
        // 箭头改造如下
        var sum3 = (a,b)=>{
            return a + b;
        };
        
        // 第三种情况,如果没有逻辑体,只有返回值可以简化如下
        //var sum4 = function(a,b){
        //    return a + b;
        //};
        // 箭头改造如下
        var sum4 = (a,b)=>a+b
        // 执行
        console.log(sum2(100));
        console.log(sum3(100,100));
        console.log(sum4(100,100));
/// 结果 
// 100
// 200
// 200

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

对象初始化简写

它是指:如果一个对象中的key和value的名字一样的情况下可以定义成一个。

代码演示:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>对象简写</title>
</head>
<body>
<script>
    function person(name, age) {
        //return {name:name,age:age};
        // 对象简写
        return { name, age };
    };
    // 调用和执行
    var json = person("hap你吃了么", 20);
    console.log(json.name, json.age);
    //========================= 实战应用 =========================
    //<button οnclick="login()">登录</button>
    function login() {
        var username = $("#username").val();
        var password = $("#password").val();
        // 发送ajax
        $.ajax({
            type: "post",
            // 对象简写
            data: { username, password },
            // 原始写法
            //data:{username:username,password:password},
            success() {}
            //原始写法
            //success:function(){}
        });
    }
</script>
</body>
</html>

规律:

如果key和value的名字一直,可以只定义一次即可
如果value是给函数,可以把 :function 去掉,只剩()即可

对象解构
对象解构 —- es6提供一些获取快捷获取对象属性和行为方式
代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>对象解构</title>
</head>
<body>
    <script>
        // 对象解构 --- es6提供一些获取快捷获取对象属性和行为方式
        var person = {
            name:'zhangsan',
            age:32,
            language:"cn",
            // 函数也有处理
            /* say:function(){
                console.log(this.name+"年龄是:" + this.age);
            }   */
            /* say:()=>{
                console.log(this.name+"年龄是:" + this.age);
            }  *///简化为下
            say(){
                console.log(this.name+"年龄是:" + this.age);
            } 
        };
        // ===========================传统的做法========================
         // 通过 . 的方式
        var name = person.name;
        var age = person.age;
        person.say();
         // 通过 [] 的方式
        var name = person["name"];
        var age = person["age"];
        person["say"]();
        // ===========================对象解构做法========================
        //es6的做法 前提:默认情况name,age必须是jsonkey.
        var {name,age} = person;
        console.log(name,age);
        // 可以用冒号取小名
        var {name,age,language:lan} = person;
        console.log(name,age,lan);
    </script>
</body>
</html>

传播操作符【…】

把一个对象的属性传播到另外一个对象中 Spread Operator
示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>ES6的语法:传播操作符【...</title>
</head>
<body>
    <script>
        // 1: 定义一个对象
        var person1 = {
            name: '上好佳',
            age: 16,
        };
        // 2: 对象解构
        var {name,age} = person1;
        // =========================== ... 对象融合=====================
        var person2 = {
            ...person1,
            gender:1,
            tel:123456789
        };
        console.log(person2);
        // =========================== ... 对象取值=====================
        // ... 对象取值
        var person3 = {
            name:"李四",
            gender:1,
            tel:"11111",
            address:'北京'
        };
        // ...person4 把剩下没取走给我。
        var {name,gender,...person4} = person3;
        console.log(name)
        console.log(age)
        console.log(person4)
        // =================场景分析 -----伪代码========================
        // 模拟后台:异步查询返回用户数据 如下:
        function findUsers(){
            $.get("xxxxx",function(res){
                var res = {
                    pages:11,
                    pageSize:10,
                    pageNo:1,
                    firstFlag:true,
                    lastFlag:false,
                    total:123,
                    data:[{},{},{},{}],
                };
                // ==========================对象 ... 取值===============
                var {data:users,...pagesjon} = res;
                //等价于
                /*  var users = res.data;
                   var pagesjon = {
                    res = {
                        pages:11,
                        pageSize:10,
                        pageNo:1,
                        firstFlag:true,
                        lastFlag:false,
                        total:123,
                    }; */
            })
        }
    </script>
</body>
</html>

数组map和reduce方法使用(了解)

数组中map方法的应用场景

map() 方法可以将原数组中的所有元素通过一个函数进行处理并放入到一个新数组中并返回该新数组。
示例代码:有一个字符串数组,希望转为int数组

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>数组方法的扩展-map reduce</title>
</head>
<body>
    <script>
        //要对arr数组的每个元素*2
        let arr = [1,2,3,4,5,6,7];
        //传统的方式
        let newarr = [];
        for(let i=0; i<arr.length; i++){
            newarr.push(arr[i]*2);
        }
        console.log(newarr);
        /*********************************map*********************/
        // 1:数据类型的更改 map自带循环的功能
        // 2:map方法可以将原数组中的所有元素通过一个函数进行处理并放入到一个新数组中并返回该新数组。
        var newarr = arr.map(function (value) {
            return value * 2;
        });
        /* 
        // 箭头简化
        var newarr = arr.map(value => parseInt(value) * 2);
        */
        console.log("原数组:", arr);
        console.log("map的newarr数组:", newarr); // 2 40 -10 6
        
        // map处理对象的数据
        var users = [{age: 10, name: "小学"},{age: 12, name: "小相"},{age: 15, name: "小伴"}]
        var naeusers = users.map(value => {
            value.age = value.age + 1;
            value.check = true;
            return value;
        });
        console.log(newusers);
        /*********************************end map*********************/
        
    </script>
</body>
</html>

reduce()

reduce(function(),初始值(可选)) :
接收一个函数(必须)和一个初始值(可选),该函数接收两个参数:

  1. 第一个参数是上一次reduce处理的结果
  2. 第二个参数是数组中要处理的下一个元素
  3. reduce() 会从左到右依次把数组中的元素用reduce处理,并把处理的结果作为下次reduce的第一个参数。如果是 第一次,会把前两个元素作为计算参数,或者把用户指定的初始值作为起始参数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>数组方法的扩展-map reduce</title>
</head>
<body>
    <script>
        /*********************************reduce*********************/
        //reduce 计算方法 
        let arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        // 箭头写法 -- 1到10相加 
        var result = arr2.reduce((a, b) => a + b);
        // 原始写法  -- 1到10相加
        //var result = arr2.reduce(function(a,b){
        //    return a+b;
        //})
        console.log(result);
        /*********************************end reduce*********************/
    </script>
</body>
</html>


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值