网页编程和设计(六)| ES6新特性

ECMAScript 6 简介

ECMAScript 和 JavaScript 的关系

ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现,常场合,这两个词是可以互换的。

名称详解

ECMAScript 6(以下简称 ES6)是 JavaScript 语言的标准,在2015 年 6 月发布。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
网页编程和设计(六)| ES6新特性_第1张图片
因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017
等等

ES6带来的新特性

  1. letconst 命令
  2. 变量的解构赋值
  3. 字符串扩展
  4. 函数扩展
  5. 对象扩展
  6. 数组扩展
  7. 运算符扩展
  8. Promise对象
  9. Class
  10. Class 继承

Nodejs环境安装

Nodejs简介

Nodejs诞生于2009年,主攻服务器方向,使得利用 JavaScript 也可以完成服务器代码的编写

Nodejs安装

Nodejs官网
https://nodejs.org/en/

网页编程和设计(六)| ES6新特性_第2张图片
Nodejs的安装与一般软件一样
网页编程和设计(六)| ES6新特性_第3张图片

大量的库

在安装 Nodejs 的同时,会附带一个 npm 命令, npm 是Node的包管理工具,这样正是接下来我们要用到的npm 的简单结构有助于 Node.js 生态系统的激增,现在 npm 仓库托管了超过 1,000,000 个可以自由使用的开源库包

npm 镜像

由于服务器在国外,所以下载速度比较慢,我们可以用国内的镜像

阿里镜像地址
https://npmmirror.com/

在命令行运行如下命令即可

npm install -g cnpm --registry=https://registry.npmmirror.com

看到如下信息,代表安装成功
网页编程和设计(六)| ES6新特性_第4张图片

Babel转码器

Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在老版本的浏览器执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持

浏览器支持性查看
https://caniuse.com/


Babel官网
https://babeljs.io/

转码示例

原始代码用了箭头函数,Babel 将其转为普通函数,就能在不支持箭头函数的 JavaScript 环境执行了

// 转码前
input.map(item => item + 1);
// 转码后
input.map(function (item) {
  return item + 1;
});

Babel安装流程

第一步:安装 Babel

npm install --save-dev @babel/core

第二步:配置文件 .babelrc

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

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

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

第三步:转码规则

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

npm install --save-dev @babel/preset-env

第四步:将规则加入 .babelrc

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

Babel命令行转码

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

Let 命令

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

let块级作用域

{
  let JavaScrip = 10;
  var gb = 1;
}
JavaScrip // ReferenceError: JavaScrip is notdefined.
gb // 1

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

for (let i = 0; i < 10; i++) {
  // ...
}
console.log(i);// ReferenceError: i is not defined

对比 var 和 let 在循环中的应用

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

上面代码,输出的 10 ,而我们期待的是 6

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

上面代码,输出的 6

let不存在变量提升

var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined 。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用

为了纠正这种现象, let 命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;

let不允许重复声明

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

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

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 的作用域与let命令相同:只在声明所在的块级作用域内有效

if (true) {
  const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is notdefined

const 命令声明的常量也是不存在提升

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

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

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

对象解构赋值

解构可以用于对象

注意:
对象的属性没有次序,变量必须与属性同名,才能取到正确的值

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>Documenttitle>
head>
<body>

    <script>

        var user = {
            name:"iwen",
            age:20
        }

        // 利用解构赋值方式简化他
        const { name,age } = user;
        console.log(name,age);

        //对console中方法进行 解构赋值 这样就不需要 console.log
        const { log } = console;
        log(name,age);

        //对Math中方法进行 解构赋值 这样就不需要 Math.* 
        const { abs,ceil,floor,random } = Math;
        log(random())
        
        var root = {
            rootname:"ime"
        }
        let rootname = 'iwen' 
        /*如果定义的变量名和对象中的属性名一样 
        在做对象解构赋值时可以用括号括起来 不需要使用let,const修饰 
        这种方式 语义不明显 不建议使用 尽量起不同的名字
        */
        // ({ rootname } = root);
    script>
body>
html>

字符串扩展

字符串Unicode 表示法

ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其中 xxxx 表示字符的 Unicode 码点。

Unicode

统一码(Unicode),也叫万国码、单一码,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

"\u0061"
// "a"

字符串遍历器接口

for...of 循环遍历

for (let i of 'itbaizhan') {
  console.log(i);
}

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

let url = "https://editor.csdn.net/mdnot_checkout=1&spm=1015.2103.3001.8066&articleId=132731432"
let h1 = "ES6新特性"
let h2 = ` ES6新特性`

字符串新增方法

includes(), startsWith(), endsWith()

传统上,JavaScript 只有 indexOf 方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。

  1. includes(): 返回布尔值,表示是否找到了参数字符串
  2. startsWith(): 返回布尔值,表示参数字符串是否在原字符串的头部
  3. endsWith(): 返回布尔值,表示参数字符串是否在原字符串的尾部
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

这三个方法都支持第二个参数,表示开始搜索的位置

let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

repeat()

repeat 方法返回一个新字符串,表示将原字符串重复 n 次。

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

padStart(),padEnd()

ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。 padStart() 用于头部补全, padEnd() 用于尾部补全。

//第一个参数为字符串的长度 第二参数为用于补全的元素
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

trimStart(),trimEnd()

ES2019对字符串实例新增了 trimStart() 和 trimEnd() 这两个方法。它们的行为与 trim() 一致, trimStart() 消除字符串头部的空格, trimEnd() 消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。

const s = ' JavaScrip ';
s.trim() // "JavaScrip"
s.trimStart() // "JavaScrip "
s.trimEnd() // " JavaScrip"

at()

at() 方法接受一个整数作为参数,返回参数指定位置的字符,支持负索引(即倒数的位置)。

注意:
如果参数位置超出了字符串范围, at() 返回 undefined

数组扩展_扩展运算符

扩展运算符(spread)是三个点( … )。将一个数组转为用逗号分隔的参数序列

console.log(...[1, 2, 3])	// 1 2 3
console.log(1, ...[2, 3, 4], 5)	// 1 2 3 4 5

替代函数的 apply 方法

由于扩展运算符可以展开数组,所以不再需要 apply 方法,将数组转为函数的参数了

// ES5 的写法
Math.max.apply(null, [14, 3, 77])
// ES6 的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);

合并数组

扩展运算符提供了数组合并的新写法

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合并数组
arr1.concat(arr2, arr3);// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合并数组
[...arr1, ...arr2, ...arr3]// [ 'a', 'b', 'c', 'd', 'e' ]

数组扩展_新增方法

Array.from()

Array.from 方法用于将类数组转为真正的数组

注意:
常见的类数组有三类:

  1. arguments
  2. 元素集合
  3. 类似数组的对象

arguments

函数里面的可选参数,一个类似数组的效果称为类数组,伪数组,只能使用数组的读取方式和length属性,不能使用数组方法:push

元素集合

类似数组的对象

Array.of()

Array.of()方法用于将一组值,转换为数组

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>Documenttitle>
head>
<body>

    <h3>标题1h3>
    <h3>标题2h3>
    <h3>标题3h3>

    <script>
        // 类数组,伪数组,只能使用数组的读取方式和length属性,不能使用数组方法:push
        
        // arguments
        function add(){
            console.log(); // 读取到10 20 30
            var result = Array.from(arguments);
            result.push(40)
            console.log(result);
        }

        add(10,20,30)


        // 元素集合
        let titles = document.querySelectorAll("h3");
        console.log(Array.from(titles));


        // 类似数组的对象
        var user = {
            "0":"iwen",
            "1":20,
            "2":"男",
            length:3
        }
        console.log(Array.from(user));

        //Array.of() 方法用于将一组值,转换为数组
        console.log(Array.of(10,20,30)); // [10,20,30]

        console.log(Array(3));//构造函数的形式,创建了一个数组开辟了数组长度为3的空间
    script>
   
body>
html>

对象的扩展

属性的简洁表示法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

let name = "iwen"
const user = {
    name,
    age:20
}
console.log(user.name);//iwen

除了属性简写,方法也可以简写

const o = {
  method() {
    return "Hello!";
 }
};
// 等同于
const o = {
  method: function() {
    return "Hello!";
 }
};

这种写法用于函数的返回值,将会非常方便

function getPoint() {
  const x = 1;
  const y = 10;
  return {x, y};
}
getPoint() // {x:1, y:10}

属性名表达式

ES6 允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内

//相当于是动态设置Key的值
var ib = "ES6"
var user = {
	[ib]: "web,java,python",
	age: 13,
	['a'+'b'] :123
}
console.log(user)

运行结果:
网页编程和设计(六)| ES6新特性_第5张图片

对象的扩展运算符

ES2018 将这个运算符引入了对象

var z = { a: 10, b: 20 }
var n = { ...z }
console.log(n); // a:10,b:20

函数的扩展_箭头函数

基本用法

ES6 允许使用“箭头”( => )定义函数 说白了就是 Java 中的 Lambda表达式

var add = (x) => x;
// 等同于
var add = function (x) {
    return x;
};

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分

var add = (x,y) => x+y;
// 等同于
var add = function (x,y) {
    return x+y;
};

var add = () => 100;
// 等同于
var add = function () {
    return 100;
};

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用 return 语句返回

var add = (x,y) => {
    var z = 10;
    return x+y+z
};
// 等同于
var add = function (x,y) {
    var z = 100
    return x+y+z
};

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。

var add = (x,y) => ({x:10,y:20});

箭头函数的一个用处是简化回调函数(匿名函数)

var arr = [10,20,30]
arr.map((item,index) => console.log("item = "+item + " " + index))
arr.map(item => console.log("item = "+item))

运行结果:
网页编程和设计(六)| ES6新特性_第6张图片

使用注意点

对于普通函数来说,内部的 this 指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的 this 对象,内部的 this 就是定义时上层作用域中的 this

  		var name = "ime"
        var user = {
            name: "iwen",
            age: 20,
            getName() {
                setTimeout(()=> console.log(this.name),1000) // iwen
            }
        }
        user.getName();

注意:
箭头函数里面根本没有自己的 this ,而是引用外层的 this

Set 数据结构

基本用法

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set 本身是一个构造函数,用来生成 Set 数据结构。

通过 add() 方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。

const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
  console.log(i);
}
// 2 3 5 4

Set 函数可以接受一个数组作为参数

const set = new Set([1, 2, 3, 4, 4]);
[...set] // [1, 2, 3, 4]

数组去除重复成员的方法

var arr = [10,20,30,10,20,40];
var s = new Set(arr); //[10,20,30,40]

字符串去除重复字符

[...new Set('ababbc')].join('') // "abc"

向 Set 加入值的时候,不会发生类型转换,所以 5"5" 是两个不同的值。

var mySet = new Set();
mySet.add("5")
mySet.add(5)
console.log(mySet); // Set(2) {'5', 5}

size属性

返回 Set 实例的成员总数

const items = new Set([1, 2, 3, 4, 5, 5, 5,5]);
items.size // 5

Set 数据结构方法

add()

set添加方法

var mySet = new Set();
mySet.add("5")
console.log(mySet);

delete()

删除某个值,返回一个布尔值,表示删除是否

var mySet = new Set();
mySet.add("5")
var flag = mySet.delete("5");
console.log(flag);  // true

has()

返回一个布尔值,表示该值是否为 Set 的成员

var mySet = new Set();
mySet.add("5")
var flag = mySet.has("5");
console.log(flag);  // true

clear()

清除所有成员,没有返回值

var mySet = new Set();
mySet.add("5")
mySet.clear();
console.log(mySet);  // Set(0) {size: 0}

Promise 对象

基本概念

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了 Promise 对象

所谓 Promise ,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的API,各种异步操作都可以用同样的方法进行处理

有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外, Promise 对象提供统一的接口,使得控制异步操作更加容易

基本用法

ES6 规定, Promise 对象是一个构造函数,用来生成 Promise 实例

const promise = new Promise(function(resolve,
reject) {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
 } else {
    reject(error);
 }
});

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject 。它们是两个函数,由 JavaScript 引擎提供,不用自己部署

Promise 实例生成以后,可以用 then 方法分别指定 resolved 状态和 rejected状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

加载图片资源例子

<!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="box">等待加载</div>

    <script>

        var box = document.getElementById("box")

        function loadImageAsync(url){
            const promise = new Promise(function(resolve, reject){
                // 异步处理:消耗时间的代码
                const image = new Image(); // 创建image对象
                image.src = url
                image.onload = function(){
                    resolve(image)
                }
                image.onerror = function(){
                    reject(new Error('Could not load image at ' + url))
                }
            })

            return promise;
        }

        const promise = loadImageAsync("http://iwenwiki.com/api/musicimg/2.png");
        promise.then(function(data){
            // 成功
            box.appendChild(data)
        },function(error){
            // 失败
            box.innerHTML = "图片加载失败";
            console.log(error);
        })
    </script>
</body>
</html>

Promise对象_Ajax实操

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>
        // XHR对象
        const getJSON = function(url){
            const promise = new Promise(function(resolve,reject){
                // 异步操作:网络请求代码
                const handler = function(){
                    if(this.readyState !== 4){
                        // 0 1 2 3 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("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php")
        .then(function(data){
            console.log(data);
        },function(error){
            console.log(error);
        })
    </script>    
</body>
</html>

Async 函数

ES2017 标准引入了 async 函数,使得异步操作变得更加方便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>
        // function print(){
        //     // 定时器时异步的
        //     setTimeout(()=>{
        //         console.log("定时器");
        //     },10)
        //     console.log("Hello");
        // }

        // print(); // Hello  定时器  

        // async
        function timeout(ms){
            // resolve:是一个函数
            return new Promise((resolve,reject) =>{
                setTimeout(function(){
                    console.log("定时器");
                    resolve();
                },ms)
            })
        }
        async function asyncPrint(ms,value){
            // 把具有异步操作的代码前面放入:await
            await timeout(ms);
            console.log(value);
        }
        asyncPrint(100,"hello")
    </script>    
</body>
</html>

resolvetimeout 函数返回的 Promise 对象的 Promise 构造函数中的回调函数。它的作用是在指定的时间(ms 毫秒)后,将 Promise 对象从等待状态变为成功状态。

具体来说,timeout 函数返回一个 Promise 对象,该对象会在指定的时间后自动从等待状态转为成功状态,不带任何值。这是通过使用 setTimeout 函数来实现的,setTimeout 函数会在指定的时间后调用回调函数,而回调函数中的 resolve 就是将 Promise 对象的状态设置为成功,并触发后续的 then 方法链。

在 asyncPrint 函数中,通过 await 关键字暂停函数的执行,等待 timeout 函数返回的 Promise 对象从等待状态变为成功状态。然后,继续执行后面的代码,即打印 value 到控制台。

因此,在调用 asyncPrint(‘hello world’, 50) 之后,hello world 会在等待 50 毫秒后被打印到控制台。

当调用 resolve(result) 时,它会将 Promise 对象的状态设置为成功,并将 result 参数作为最终的结果传递出去。这会触发后续添加到该 Promise 的 then 方法中的回调函数执行,以处理 Promise 的成功情况。

在代码示例中的 ajax 函数实现中,当使用 $.getJSON 方法进行异步请求成功后,通过调用 resolve(result) 来将 Promise 的状态设置为成功,并将 result 参数传递出去。这样,后续的 await 表达式将获得 Promise 的结果并继续执行。

总的来说,resolve 函数的作用是设置 Promise 对象的状态为成功,并传递最终的结果。它是 Promise 内部机制的一部分,由 JavaScript 引擎自动调用。在这个例子中,resolve 用于处理异步操作成功的情况,将结果传递给后续的代码。

Class 的基本语法

类的由来

JavaScript 语言中,生成实例对象的传统方法是通过构造函数

function Point(x, y) {
  this.x = x;
  this.y = y;
}
Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类

基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
 }
  toString() {
    return '(' + this.x + ', ' + this.y +')';
 }
}

constructor 方法

constructor() 方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法。一个类必须有 constructor() 方法,如果没有显式定义,一个空的 constructor() 方法会被默认添加

class Point {
}
// 等同于
class Point {
  constructor() {}
}

类的实例

生成类的实例的写法,与 ES5 完全一样,也是使用 new 命令

class Point {
  // ...
}
// 报错
var point = Point(2, 3);
// 正确
var point = new Point(2, 3);

注意点

不存在提升

类不存在变量提升(hoist),这一点与 ES5 完全不同

new Foo(); // ReferenceError
class Foo {}

Class属性与方法

实例方法

通过类的实例对象调用方法

class People{
    say(){
        console.log("Hello");
   }
}
var p = new People();
p.say()

实例属性

实例属性指的是类的实例对象可调用的属性

class People{
    constructor(name,age){
        this.name = name;
        this.age = age;
   }
    say(){
        console.log(this.name,this.age);
   }
}
var p = new People("iwen",20);
p.say()
console.log(p.name,p.age);

静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”

class Person {
    static classMethod() {
        console.log("Hello");
   }
}
Person.classMethod() // Hello
var p = new Person();
p.classMethod() // p.classMethod is not a function

注意: 如果静态方法包含 this 关键字,这个 this 指的是类,而不是实例。

class People {
    static getSay() {
        this.say();
   }
    static say() {
        console.log('hello');
   }
    say() {
        console.log('world');
   }
}
People.getSay() // hello

静态属性

静态属性指的是 Class 本身的属性,即 Class.propName

class People{}
People.status = "等待"
console.log(People.status);//等待

Class 的继承

基础用法

Class 可以通过 extends 关键字实现继承,让子类继承父类的属性和方法。extends 的写法比 ES5 的原型链继承,要清晰和方便很多

class Person{
}
class Student extends Person{
}

ES6 规定,子类必须在 constructor() 方法中调用 super() ,否则就会报错,这是因为子类自己的 this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。如果不调用 super() 方法,子类就得不到自己的 this 对象

<!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>

        class Person{
            constructor(name,age){
                this.name = name;
                this.age = age
            }
            getName(){
                console.log(this.name);
            }

            static getInfo(){
                console.log("这是一个人类");
            }
        }

        class Student extends Person{

            constructor(name,age,schoolName){
                super(name,age);
                this.schoolName = schoolName;
            }

            getSchool(){
                console.log(this.schoolName);
            }
        }
        var s = new Student("小明",15,"二中");
        s.getName();
        Student.getInfo();
        s.getSchool();

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

运行结果:
网页编程和设计(六)| ES6新特性_第7张图片

Module 的语法

历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的 require 、Python 的 import ,甚至就连CSS 都有 @import ,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍

ES6 模块是通过 export 命令显式指定输出的代码,再通过 import 命令输入。

export var Hello = "hello" // hello.js文件
import { Hello } from "./hello.js" //index.js文件

测试方式

我们采用Nodejs方式进行测试Module语法

但是nodejs采用的是CommonJS的模块化规范,使用require引入模块;而import是ES6的模块化规范关键字。想要使用import,必须引入babel转义支持,通过babel进行编译,使其变成node的模块化代码。

疑惑:为啥不用前端方式测试,前端方式测试会更加麻烦

第一步:全局安装babel-cli npm install -g babel-cli
第二步:安装 babel-preset-env npm install -D babel-preset-env
第三步:运行代码 babel-node --presets env index.js

export 命令

export命令导出变量

export var firstName = 'sxt';
export var lastName = 'JavaScrip';
export var year = 2000;

export命令导出函数

export function add(x, y) {
  return x + y;
};

import 命令

使用 export 命令定义了模块的对外接口以后,其他 JS 文件就可以通过 import 命令加载这个模块

// name.js
export var firstName = 'sxt';
export var lastName = 'itbaizhan';
export var year = 2000;

// main.js
import { firstName, lastName, year } from './profile.js';

如果想为输入的变量重新取一个名字, import 命令要使用as关键字,将输入的变量重命名

// value.js
export var value = 1;
// main.js
import { value as val } from './value.js';

除了指定加载某个输出值,还可以使用整体加载,即用星号( * )指定一个对象,所有输出值都加载在这个对象上面

// circle.js
export function area(radius) {
  return Math.PI * radius * radius;
}
export function circumference(radius) {
  return 2 * Math.PI * radius;
}
// main.js
import { area, circumference } from './circle';
// 可以修改如下
import * as circle from './circle';

export default 命令

从前面的例子可以看出,使用 import 命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法

为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到 export default 命令,为模块指定默认输出。

// export-default.js
export default function () {
  console.log('foo');
}

其他模块加载该模块时, import 命令可以为该匿名函数指定任意名字

// import-default.js
import customName from './export-default';
customName(); // 'foo'

你可能感兴趣的:(es6,前端,ecmascript)