Web前端
ES6新特性
let
和const
命令- 变量的解构赋值
- 字符串扩展
- 函数扩展
- 对象扩展
- 数组扩展
- 运算符扩展
- Promise对象
- Class
- Class 继承
- …
命令行工具
常用的命令行工具:
CMD
命令行工具PowerShell
命令行工具
CMD命令行
- 打开命令行窗口
- win : 左下角开始,找到运行,点击,输入
cmd
,回车 - win :
win+r
快速打开命令行窗口 - mac :
command
+空格,输入terminal
- win : 左下角开始,找到运行,点击,输入
- 选择盘符 : 盘符名加冒号 E:
- 查看盘符及目录下文件与文件夹:
wn:dir
mac:ls
- 清空命令行信息:
win:cs
mac:cleal
- 进入文件夹或目录 :
cd 文件夹名称
- 返回到上一级目录 :
cd../
- 快速补全目录或文件夹名称:
tab
- 创建文件夹:
mkdir 文件夹名称
- 查看历史输入过的命令:上下按键
PowerShell
- 打开方式
- 在开始位置搜索 Powershel 打开
- 在对应目录按住 shift+右键,打开
- 其他保持一致
Babel转码器
可以将ES6代码转为ES5代码
- 安装Babel
npm install --save-dev @babel/core
- 配置文件
.babelrc
{
"presets":[],
"plugins":[]
}
- 转码规则
presets字段设定转码规则,官方提供以下规则集,可以根据需要安装
npm install --save-dev @babel/preset-env
- 将规则加入
.babelrc
{
"presets":[
"@babel/env"
],
"plugins":[]
}
- Babel命令行转码
npm install --save-dev @babel/cli
基本用法如下:
#转码结果输出到标准输出
$ npx babel example.js
转码结果写入一个文件
# --out-file或-0 参数指定输出文件
$ 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
命令所在的代码块内有效。
- var关键字:函数级作用域
- let关键字
- let是块级作用域(花括号级作用域
{}
) - let不存在变量提升
- let不允许重复声明(在相同作用域内)
- let是块级作用域(花括号级作用域
Const命令
const
声明一个只读常量,一旦声明,常量的值就不能改变
- 一旦声明,就必须立即初始化
- 作用域与
let
相同,块级作用域 - 不存在变量提升
- 不可以重复声明
对象的解构赋值(变量的结构赋值)
user = {
name : 'xxx',
age : 20
};
let {name, age} = user;
注意
对象的属性没有次序,必须和属性同名,才能取到正确的值
- 对象的解构赋值可以很方便将现有对象的方法复制到某个变量
let {log} = console;
let {random, floor, ...} = Math;
如果将一个已经声明的变量用于解构赋值,报错。
字符串扩展
字符串Unicode表示法
ES6 加强了对 Unicode 的支持,允许采用 \uxxx
形式表示一个字符,其中 xxx
表示字符的 Unicode 码点。
Unicode
统一码(Unicode),也叫万国码、单一码,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
"\u0061"
// "a"
字符串遍历接口
for...of
遍历循环
for (let i of "hello"){
console.log(i); //i是字符串中的每一个字符
}
模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
// 动态创建一个a标签,a标签的href属性是动态的
let url = 'www.baidu.com';
//当向页面写入动态标签时,标签的数据一般来源于服务器
let h1 = '<a href="' + url +'">百度</a>';
//字符串模板
let h2 =`<a href='${url}'>百度</a>`;
字符串新增方法
includes(), startsWith(), endsWith()
传统上,JavaScript 只有 indexof
方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
includes()
: 返回布尔值,表示是否找到了参数字符串startsWith()
: 返回布尔值,表示参数字符串是否在原字符串的头部endswith()
: 返回布尔值,表示参数字符串是否在原字符串的尾部
这三个方法都支持第二个参数,表示开始搜索的位置
let s='Hello_world!';
s.startswith('world',6) // true
s.endswith('Hello',5)// true
s.includes('He11o',6)// false
repeat()
repeat()
方法返回一个新字符串,表示将原字符串重复n次。
'x'.repeat(3) //“xxx'
'he1lo'.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()
消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。
at()
at()
方法接受一个整数作为参数,返回参数指定位置的字符,支持负索引(即倒数的位置)。
const str ='hel1o';
str.at(1)//"e"
str.at(-1)//"o'
注意
如果参数位置超出了字符串范围,at()
返回undefined
数组扩展:扩展运算符
扩展运算符(spread)是三个点(…
)。将一个数组转为用逗号分隔的参数序列
- 替代函数的 apply 方法
由于扩展运算符可以展开数组,所以不再需要 appy 方法,将数组转为函数的参数了
// ES5 的写法
Math.max.apply(nu71, [14, 3, 77])
// ES6 的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
- 合并数组
//扩展运算符提供了数组合并的新写法
const arrl = ['a', 'b'];
const arr2 =['c'];
const arr3 =['d','e'];
//ES5 的合并数组
arr1.concat(arr2,arr3); // ['a','b','c','d',r'e']
// ES6 的合并数组
[...arr1,...arr2,...arr3]//['a','b','C','d','e']
数组扩展:新增方法
- Array.from()
Array.from
方法用于将类数组转为真正的数组
温馨提示
常见的类数组有三类:
- arguments
- 元素集合
- 类似数组的对象
arguments
function add(){
let collect = Array.from(arguments);
collect.push(40);
console.1og(collect);
}
add(10,20,30)
元素集合
let divs = document.queryselectorA1l('div');
console.log(Array.from(divs));
类似数组的对象
let arrayLike = {
'0' : 'a',
'1' : 'b',
'2' : 'c',
length : 3
};
let arr = Array.from(arrayLike);
console.log(arr);
- Array.of()
Array.of()
方法用于将一组值,转换为数组
Array.of(3, 11, 8)//[3,11,8]
对象的扩展
属性的简洁表示法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
let name ="hello";
const user = {
name ,
age:20
}
除了属性简写,方法也可以简写
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 允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内
let propkey = 'hello';
let obj= {
[propKey]: true,
['a'+'bc']:123
};
对象的扩展运算符
ES2018 将这个运算符引入了对象
let z = {a: 3, b: 4};
let n = {...z};
console.log(n);
{...{}, a: 1}
// { a: 1 }
函数的扩展:箭头函数
基本用法
ES6 允许使用箭头( =>
)定义函数
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 = 10;
return x+y+z;
}
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
var add = (x,y) => ({x:10,y:20});
箭头函数的一个用处是简化回调函数(匿名函数)
var arr = [10,20,30];
arr.map(item =>{
console.log(item);
})
使用注意点
对于普通函数来说,内部的 this
指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的 this
对象,内部的 this
就是定义时上层作用域中的 this
var name = "hello";
var user = {
name:"world",
getName(){
setTimeout(() => {
console.log(this.name); //world
})
}
}
user.getName()
温馨提示
箭头函数里面根本没有自己的this
,而是引用外层的this
Set数据结构
基本用法
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值
- Set本身是一个构造函数,用来生成 Set 数据结构。
const s= new set();
[2, 3, 5, 4, 5, 2, 2].forEach(x=> s.add(x));
for(let i of s){
console.1og(i);
}
//2 3 5 4
通过 add()
方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值
- Set函数可以接受一个数组作为参数
const set=new set([1,2,3,4,4]);
[...set]
//[1,2,3,4]
- 数组去除重复成员的方法
// 去除数组的重复成员
[...new Set(array)]
- 字符串去除重复字符
[...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
方法
add()
:添加delete()
:删除某个值,返回一个布尔值,表示删除是否has()
:返回一个布尔值,表示该值是否为Set成员clear()
:清除所有成员,没有返回值
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
构造函数接受一个函数作为参数,该函数的两个参数分别是resove
和reject
。它们是两个函数,由JavaScript 引擎提供,不用自己部署
Promise
实例生成以后,可以用 then
方法分别指定 resolved
状态和 rejected
状态的回调函数。
promise.then(function(value){
//success
}, function(error){
//failure
})
Promise_Ajax实操
<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.readyState === 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://...").then(function(data){
console.log(data);
}, function(error){
console.log(error);
})
</script>
</body>
Async函数
ES2017 标准引入了 async 函数,使得异步操作变得更加方便
async
函数可以将异步操作变为同步操作
function print(){
//定时器是异步的
setTimeout(()=>{
console.log("定时器");
}, 10);
console.log("Hello");
}
print(); // Hello 定时器
基本语法
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(10, "Hello");
使用场景:网络请求之间的依赖关系,很多接口可能要以来于上一个接口的数据才能执行
Class类
Class的基本语法
//ES5类的表现形式
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var p = new Person("zhangsan",20);
p.getName();
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class
关键字,可以定义类
基本上,ES6 的 class
可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
getName(){
console.log(this.name);
}
}
var p = new Person("zhangsan",20);
p.getName();
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 完全不同
Class属性与方法
- 实例方法
通过类的实例对象调用方法
class People{
say(){
console.1og("He11o");
}
}
var p=new People();
p.say()
- 实例属性
实例属性指的是类的实例对象可调用的属性
class People{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name,this.age);
}
}
//p:实例对象
var p= new People("iwen",20);
p.say()
console.log(p.name,p.age);
- 静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static
关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法“
class Person{
static classMethod(){
console.1og(“He11o");
}
}
Person.classMethod()//Hello
var p=new Person();
p.classMethod()//p.classMethod is not a function
温馨提示
注意,如果静态方法包含this
关键字,这个this
指的是类,而不是实例。
- 静态属性
静态属性指的是 Class 本身的属性,即 Class.propName
class People{}
People.status ="等待";
console.log(People.status);
Class的继承
Class 可以通过 extends
关键字实现继承,让子类继承父类的属性和方法。extends
的写法比 ES5 的原型链继承,要清晰和方便很多
class Point {
}
class colorPoint extends Point {
}
ES6 规定,子类必须在 constructor()
方法中调用 super()
,否则就会报错,这是因为子类自己的 this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。如果不调用super()
方法,子类就得不到自己的 this
对象
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
getName(){
console.log(this.name);
}
static getInfo(){
console.log("people");
}
}
class Student extends Person{
constructor(name, age, schoolName){
super(name, age);
this.schoolName = schoolName;
}
getSchool(){
console.log(this.schoolName);
}
}
var stu = new Student("zhangsan", 20, "xx大学");
stu.getName();
Student.getInfo();
stu.getSchool();
Module语法
历史上,JavaS一直没有模块(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 ='zhang';
export var lastName ='san';
export var year = 2000;
- export命令导出函数
export function add(x,y){
return x+y;
};
import命令
- 使用
export
命令定义了模块的对外接口以后,其他JS文件就可以通过import
命令加载这个模块
// profile.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'
一个文件中,默认只能存在一个export default命令