ES 6新语法
阅读原文时间:2023年07月10日阅读:4

一、块级作用域绑定

  • ### 回顾:使用var关键字定义变量

定义 = 声明 + 赋值;

  1. 可以一次定义多个变量

2. 定义时可以只声明不赋值

3. 定义之后可以随时修改变量的值

4. 变量声明会被提升

5. 可重复定义变量

6. 全局定义的变量会被作为全局对象(global/window)的属性

7. 在代码块中使用 var 关键字声明的变量不会被束缚在代码块中

if (true) {

         var foo, bar = 'abc';  
     }

     console.log(foo, bar)

// 0. 可以一次定义多个变量
// let foo = 123, bar = 'abc';

     // 1. 定义时可以只声明不赋值  
     // let foo, bar;

     // 2. 定义之后可以随时修改变量的值  
     // let foo = 123, bar = 'abc';  
     // foo = 'abc';  
     // bar = 123;  
     // console.log(foo, bar);  // 'abc' 123

     // 3. 使用 let 关键字定义的变量,变量声明不会被提升,因此我们需要先定义,后使用  
     // console.log(foo);  // foo is not undefined  
     // let foo = 123;

     // 4. 在同一作用域下,不能重复定义同名变量  
     // let foo = 123;  
     // let foo = 'abc';  // Identifier 'foo' has already been declared  
     // console.log(foo)

     // 5. 全局定义的变量会被作为全局对象(global/window)的属性

     // 6. 在代码块中使用 let 关键字声明的变量会被束缚在代码块中

1. 在使用 const 关键字声明常量时,必须要进行赋值(初始化)。

2. 常量一旦初始化后,就不能被修改。

3. 在同一作用域下,不能重复定义同名的常量。

4. 常量的声明不会被提升

5. 所有常量只在当前代码块内有效,一旦执行流到了代码块外,这些常量就会被立即销毁。
6.不在Windows下

  • 插入数据

  • 给变量前面加三个点(…),就不再打印出数组格式了,(如控制台打印的一二行,第一行是使用展开操作符,第二行是没有使用展开操作符的)

  • 使用场景:a.合并数组  b.复制数组

不定参数:顾名思义,不知道还有多少个参数,剩余的统统接收,用来代替arguments;

  • 函数中剩余操作符只能是函数中最后的一个形参,格式:…bar;

  • 第一个实参会被赋值给第一个形参,剩余所有的实参都会被交给形参 bar,bar会自动变成一个数组;

二、解构

在 ECMAScript 5 或更早的版本中,从对象或数组中获取特定的数据并赋值给本地变量需要书写很多并且相似的代码。例如:

let options = {
repeat: true,
save: false
};

// 从对象中提取数据

let repeat = options.repeat,
save = options.save;

这段代码反复地提取在 options 上存储地属性值并将它们传递给同名的本地变量。虽然这些看起来不是那么复杂,不过想象一下如果你的一大批变量有着相同的需求,你就只能一个一个地赋值。而且,如果你需要从对象内部嵌套的结构来查找想要的数据,你极有可能为了一小块数据而访问了整个数据结构。

这也是 ECMAScript 6 给对象和数组添加解构的原因。当你想要把数据结构分解为更小的部分时,从这些部分中提取数据会更容易些。很多语言都能使用精简的语法来实现解构操作

  1. 声明的变量是同名变量,写在{}里即可,变量之间用“,”隔开就行;

  2. 声明的变量是非同名变量,在{}里写上"   “:”+ “变量名”    "  ,变量之间用“,”隔开  例如:

    let { firstName: first_name, lastName: last_name } = obj;

  3. 为变量指定默认值,当对象中没有某个属性时,直接写上变量的名字加“=”即可, 例如:

    let { firstName, lastName, myAge = 20 } = obj;

    let { firstName: first_name, lastName: last_name, myAge: my_age = 20} = obj;

  4. 为已有变量重新赋值,({}=obj),因为JS解析引擎不允许操作赋值符(=)左边出现花括号所以使用 "()"将整个赋值语句包起来,使他成为一个表达式

  5. 嵌套对象解构,(俄罗斯套娃,哈哈~~)例如:obj里面的phone里面的number赋值给同名变量number

    let { phone: { number, brand } } = obj;

  6. 数组解构初始化变量:数组中的元素会按照顺序赋值给变量

  7. 使用数组解构为变量重新赋值,[  ]=colors,

    [ firstColor, secondColor ] = colors;我们

  8. 为变量指定默认值,当数组中没有第四个元素。而我们又需要第四个元素时,我们可以给变量赋值,但是当元素中有第四个元素,我们再给第四个元素赋值是无效的;

  9. 跳过数组中的指定元素,当我们不需要第二,三个元素,又需要第四个元素,中间可以用“  ,”隔开,

  10. 嵌套解构前面不需要的数据用 “ ,”隔开,嵌套的用“ [ ]”l来表示

三、函数

ES5 语法中,为函数形参指定的默认值写法

 ES6中为函数形参指定默认值

  a.除了为形参直接指定默认值以外,形参的默认值还可以是表达式,例如,timeout = 5 * 1000

  b.在预编译阶段,形参表达式不会执行,只有在调函函数,并且没有为形参传递实参的情况下才执行

previousValue:上一个值

currentValue:当前的值

reduce()方法:

1.接收一个函数作为累加器,将数组元素计算为一个值(从左到右),

2.需要接收四个参数( 必需:1.acc 累加器 2.cur 当前值 ;可选:1.idx 当前索引  2 .src 源数组)

凡是以后遇到匿名函数都可以使用箭头函数

省略等号和function

  1. 如果形参数量为 0,则必须加上小括号。箭头后面的表达式的结果会被作为函数的返回值。

  2. 如果形参的数量为 1,则可以省略小括号。

  3. 如果形参数量大于 1,则不能省略小括号。

  4. 如果函数的执行体比较简单(直接量或表达式),可以省略大括号,箭头后面的直接量或表达式会被自动作为返回值

  5. 如果函数的执行体比较复杂,则不能省略大括号。

  1. 普通函数作用域中的 this 已经被绑定成 window 对象,因此当我们放问 this 时,直接在当前作用域下就能访问的到。

  2. 箭头函数的作用域中没有绑定 this,因此,当我们访问 this 时,会去上一层作用域中查找 this。

 <script>  
     // 1. ECMAScript 5 中判断构造函数是否通过 new 关键字调用的写法  
     // function Person (fullName) {  
     //     if (this instanceof Person) {  
     //         this.fullName = fullName;  
     //     } else {  
     //         return new Person(fullName);  
     //     }  
     // }

     // let student = Person('孟天乐')

     // 2. ECMASript 6 引入一个 new.target 属性,当我们使用 new 操作符调用构造函数时,new.target 属性的值为构造函数,否则为 undefined  
     // function Person (fullName) {  
     //     if (typeof new.target !== 'undefined') {  
     //         this.fullName = fullName;  
     //     } else {  
     //         throw new Error('必须通过 new 关键字来调用 Person。');  
     //     }  
     // }  
     // let student = new Person('孟天乐');  
     // console.log(student)

     // 3. 除此之外,还可以检查 new.target 是否被某个特定构造函数所有调用。  
     // 例如,Person 构造函数中的 new.target 属性的值被限定为 Person  
     // function Person (fullName, age) {  
     //     if (typeof new.target === Person) {  
     //         this.fullName = fullName;  
     //         this.age = age;  
     //     } else {  
     //         throw new Error('必须通过 new 关键字来调用 Person。');  
     //     }  
     // }

     // function Dog (fullName, age) {  
     //     Person.call(this, fullName, age)  
     // }

     // let dog = new Dog('HeHe', 3)

     // console.log(dog)

     // 4. 不能在函数外部使用 new.target,否则会报错  
     function Person () {  
         console.log(new.target)  
     }

     // 下面代码会抛出错误:new.target expression is not allowed here  
     // console.log(new.target) 

     let student = new Person('崔景龙')

 </script>

四、对象

  • 当一个对象的属性与本地变量同名时,不需要再写冒号和值,直接写属性名即可

<script>

     // ES 5 中并没有定义对象属性的枚举顺序,有 JavaScript 引擎厂商自行决定。  
     // ES 6 中明确规定了对象的自有属性被枚举时的返回顺序。  
     // 自有属性枚举顺序的基本规则:  
     // 1. 所有数字按升序  
     // 2. 所有字符串按照它们被加入对象时的顺序排序

     let obj = {  
         a: 1,  
         0: 2,  
         c: 3,  
         2: 4,  
         b: 5,  
         1: 6  
     };

     console.log(Object.getOwnPropertyNames(obj));  // \["0", "1", "2", "a", "c", "b"\]

 </script>

 <script>

     let person = {  
         getGreeting () {  
             return 'Hello';  
         }  
     };

     let dog = {  
         getGreeting () {  
             return 'woof';  
         }  
     };

     // 使用 create() 方法将 person 对象作为原型对象  
     let friend = Object.create(person);  // {}  
     console.log(friend.getGreeting());  // 'Hello'  
     console.log(Object.getPrototypeOf(friend) === person);  // true

     // 使用 setPrototypeOf() 方法将 friend 对象的原型对象修改成 dog  
     Object.setPrototypeOf(friend, dog);  
     console.log(friend.getGreeting());  // 'Hello'  
     console.log(Object.getPrototypeOf(friend) === dog);  // true

 </script>

 <script>

     let person = {  
         getGreeting () {  
             return 'Hello';  
         }  
     };

     let dog = {  
         getGreeting () {  
             return 'woof';  
         }  
     };

     // let friend = {  
     //     getGreeting () {  
     //         return Object.getPrototypeOf(this).getGreeting.call(this) + ', hi';  
     //     }  
     // };

     // ES 6 引入了 super 关键字,super 指向当前对象的原型对象,实际上也就是 Object.getPrototypeOf(this) 的值,于是,上面的代码可以简化成如下形式:  
     let friend = {  
         getGreeting () {  
             return super.getGreeting() + ', hi';  
         }  
     };

     // 使用 setPrototypeOf() 方法将 friend 对象的原型对象修改成 person  
     Object.setPrototypeOf(friend, person);  
     console.log(friend.getGreeting());  // 'Hello'  
     console.log(Object.getPrototypeOf(friend) === person);  // true

     // 使用 setPrototypeOf() 方法将 friend 对象的原型对象修改成 dog  
     Object.setPrototypeOf(friend, dog);  
     console.log(friend.getGreeting());  // 'Hello'  
     console.log(Object.getPrototypeOf(friend) === dog);  // true

 </script>

五、类

        1. 类的声明不会被提升,而构造函数的声明会被提升。

        2. 使用除 new 以外的方式调用类的构造函数(constructor)会导致程序抛出错误。

        3. 在类中声明的方法都是不可枚举的。

 <!-- 要想让浏览器把 module1.js 和 module2.js 当成两个模块去解析,你要为 script 标签添加 type="module" 属性 -->  
 <!-- 要想然下面的代码正确执行,不能使用文件协议(file://),也就是说不能直接使用浏览器打开该页面,需要将其放入服务器中,然后再打开。 -->  
 <script src="./13-module1.js" type="module"></script>  
 <script src="./14-module2.js" type="module"></script>  
 <script src="./15-module3.js" type="module"></script>  

  • module1.js

    // 崔景龙

    // 1. 模块私有的内容
    // function multiply (x, y) {
    // return x * y;
    // }

    // 2. 模块导出的内容
    // export function sum (x, y) {
    // return x + y;
    // }

    // export function substract (x, y) {
    // return x - y;
    // }

    // 3. 一次导出多个模块成员
    function divide (x, y) {
    return x / y;
    }

    function remainder (x, y) {
    return x % y;
    }

    export { divide, remainder };

    // 4. 为导出成员重命名
    // export { divide as div, remainder as rem };

    // 5. 默认导出,模块默认导出成员,其他模块导入该成员时,名称不能写到大括号中,并且无需与导出时的名称一致。
    // export default function max (x, y) {
    // return x > y ? x : y;
    // }

    // 6. 每个模块只能有一个默认导出,因此下面的代码会抛出错误。
    // export default function min (x, y) {
    // return x < y ? x : y;
    // }

  • module2.js

    // 刘旭凯

    // 1. 从 module1.js 中导入 sum() 和 substract() 方法
    // import { sum, substract } from './13-module1.js';

    // 使用从 module1.js 中导入的方法
    // console.log(sum(12, 48))
    // console.log(substract(12, 48))

    // 2. 导入重命名之后的模块成员
    // 注意,必须要写成重命名之后的名称(div,rem),不能写成重命名之前的名称(divide,remainder)
    // import { div, rem } from './13-module1.js';
    // console.log(div(48, 12))
    // console.log(rem(48, 12))

    // 3. 导入其他模块默认导出成员
    // 注意,名称不能写到大括号中,并且无需与导出时的名称一致。
    // import abc from './13-module1.js';
    // console.log(abc(12, 48))

    // 4. 同时导入其他模块的默认导出的成员和普通导出的成员
    // import abc, {sum, div} from './13-module1.js'
    // console.log(abc(12, 48))
    // console.log(sum(12, 48))
    // console.log(div(12, 48))

    // 5. 为导入的成员重命名
    // 注意,重命名之后不能再使用之前的名称了,否则会抛出错误。
    // import { substract as sub} from './13-module1.js';
    // console.log(sub(12, 48))
    // console.log(substract(12, 48)); // 抛出错误

    // 6. 导入其他模块导出的所有成员
    // import * as module1 from './13-module1.js'
    // console.log(module1.sum(12, 34))
    // console.log(module1.default(12, 34))

    // 7. 导入没有导出任何成员的模块,目的是想让模块中的代码执行
    // 注意,模块中的代码只在第一次被导入时执行。
    // import './13-module1.js';

    // 下面是一个简单的使用场景:

    // module1.js 文件中有如下代码:
    // let age = 20;

    // export function getAge () {
    // return age;
    // }

    // export function setAge () {
    // age++;
    // }

    // module2.js 文件中的代码如下:
    // import { setAge } from './13-module1.js';
    // setAge();

    // module3.js 文件中的代码如下:
    // import './module2.js';
    // import { getAge } from './module1.js';
    // console.log(getAge()); // 21

    // 8. 将导入的成员重命名之后再次导出
    export { divide as div, remainder as rem } from './13-module1.js';

  • module3.js

    // 导入 module2.js 模块中导出的成员(对应 module2.js 文件中第8个示例)
    import { div, rem } from './14-module2.js';
    console.log(div(48, 12))
    console.log(rem(48, 12))

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章