ECMAScript 6 简介
ECMAScript 和 JavaScript 的关系
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现,常场合,这两个词是可以互换的。
名称详解
ECMAScript 6(以下简称 ES6)是 JavaScript 语言的标准,在2015 年 6 月发布。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017
等等
ES6带来的新特性
let
和const
命令- 变量的解构赋值
- 字符串扩展
- 函数扩展
- 对象扩展
- 数组扩展
- 运算符扩展
- Promise对象
- Class
- Class 继承
- …
Nodejs环境安装
Nodejs简介
Nodejs诞生于2009年,主攻服务器方向,使得利用 JavaScript 也可以完成服务器代码的编写
Nodejs安装
Nodejs官网
https://nodejs.org/en/
Nodejs的安装与一般软件一样
大量的库
在安装 Nodejs 的同时,会附带一个 npm 命令, npm 是Node的包管理工具,这样正是接下来我们要用到的npm 的简单结构有助于 Node.js 生态系统的激增,现在 npm 仓库托管了超过 1,000,000 个可以自由使用的开源库包
npm
镜像
由于服务器在国外,所以下载速度比较慢,我们可以用国内的镜像
阿里镜像地址
https://npmmirror.com/
在命令行运行如下命令即可
npm install -g cnpm --registry=https://registry.npmmirror.com
看到如下信息,代表安装成功
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>Document</title>
</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 = "<a href='"+ url +"'>ES6新特性</a>"
let h2 = `<a href='${url}'> ES6新特性</a>`
字符串新增方法
includes(), startsWith(), endsWith()
传统上,JavaScript 只有 indexOf
方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
- includes(): 返回布尔值,表示是否找到了参数字符串
- startsWith(): 返回布尔值,表示参数字符串是否在原字符串的头部
- 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
方法用于将类数组转为真正的数组
注意:
常见的类数组有三类:
- arguments
- 元素集合
- 类似数组的对象
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>Document</title>
</head>
<body>
<h3>标题1</h3>
<h3>标题2</h3>
<h3>标题3</h3>
<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)
运行结果:
对象的扩展运算符
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))
运行结果:
使用注意点
对于普通函数来说,内部的 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
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和 reject
。它们是两个函数,由 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>
resolve
是 timeout
函数返回的 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>
运行结果:
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'