ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言
JavaScript ,它包含了三大部分:ECMAScript、DOM、BOM ECMAScript:ECMAScript是JavaScript这门语言的核心组成,是这门语言的精髓所在。ECMAScript包括变量定义,函数,语法,作用域等等语法,需要我们去不断钻研 ECMAScript 和 JavaScript 的关系是,前者是后者的语法规范,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)
2011年 ,ECMAScript 5.1版发布
2015年,ECMAScript 6正式版发布,即ECMAScript 2015。简称ES6
2016年,ECMAScript 7发布 2017年,ECMAScript 8发布;
2018年,ECMAScript 9发布
ES6 的版本变动内容最多,具有里程碑意义 ES6 加入许多新的语法特性,编程实现更简单、高效 ES6 是前端发展趋势,就业必备技能
let 关键字用来声明变量,const关键字用来声明常量。 let和const的区别是:let是变量可以修改,const是常量不可以修改 let和const的相同点: 1.都不能重复声明 2.支持块级作用域,在作用域内定义的变量或常量只能在作用域内使用
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。 数组的解构赋值: 把数组的元素赋给多个变量
const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;
对象的解构赋值: 把对象的属性值赋给相应的变量
const lin={
name:'林志颖',
tags:['车手','歌手','演员']
};
let {name,tags}=lin;
注意:声明和赋值不能分开,必须在一句话里完成
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
字符串中可以出现换行符
可以使用 ${xxx} 形式输出变量
let star = '王宁';
let result = `${star}在前几年离开了开心麻花`;
//当遇到字符串与变量拼接的情况使用模板字符串
key和value的名字一样的时候,可以省略value
let a = 1; let b = 2;
let json1 = {a: a, b: b, c: 3};
let json2= {a, b, c: 3}; //简写
console.log(json2);
json内函数简写,可以将函数的:function去掉,直接写函数名()
let obj = {
a: "helloWorld",
say(){
console.log(this.a); }
};
obj.say();//helloWorld
//对象简写形式简化了代码,所以以后用简写就对了
箭头函数: 省略function关键字,参数部分和函数体之间用箭头连接
let fn=(a)=> { return a * 2; }
console.log(fn(5));
箭头函数简写:如果没有形参,不能省略(),如果只有一个形参可以省略(),如果函数体只有一个return语句,可以省略{}和return关键字
let fn=()=>{
return "Hellow";
}
console.log(fn());
let fn=a=>a*2;
console.log(fn(5));
let fn2=(a,b)=>a*b;
console.log(fn2(2,6));
注意:箭头函数不会更改this指向,用来指定回调函数会非常合适. 箭头函数定义回调函数的示例
setTimeout(()=>{
console.log(this);//this指向window对象
console.log('3s后显示');
},3000);
ES6中用...args表示rest参数,用于获取函数的实参,它类似于java的可变参数。
let fn1=function(...args){
console.log(args);
}
fn1(1,2,3);//[1,2,3]
fn1(1,2,3);//[2,3,5]
//注意:rest参数适用于参数个数不确定的函数,且只能在参数列表的最后面
扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,展开数组。
const city1=["北京","上海","重庆"];
const city2=["南京","杭州"];
let citys=[...city2,...city1];
console.log(citys);
迭代器(Iterator)就是一种接口,为各种不同的数据结构提供统一的访问机制(也叫"遍历器")。任何数据结构只要部署 Iterator接口,就可以认为是"可遍历的",可完成遍历操作。部署Iterator接口就是一个数据结构具有Symbol.iterator属性。
原生具备 iterator 接口的数据类型如下,可统一使用 for ...of 进行遍历 a) Array b) Set c) Map d) String e) TypedArray f) NodeList 注意 1). for..of循环与for..in循环相比,for..in只能遍历出key(数组的索引),for..of直接得到value. 如果要通过for...of循环获取数组的索引,可借助数组实例的keys方法.
const westTravel=["唐僧","孙悟空","猪八戒","沙僧"];
console.log(westTravel);
for(let v of westTravel){
console.log(v);
}
console.log('***********************');
const emps=[{
eid=001,
name='路仁贾',
sex='男'
},{
eid:002,
name='肖兵倚',
sex='女'
}];
//for...of遍历索引
for(let index of emps.keys()){
console.log(index,emps[index]);
}
2). for..of循环与forEach循环相比, for..of可和break、continue配合使用,而forEach不能用break,continue,但能用return
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯 一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进 行遍历,集合的属性和方法:
size: 返回集合的元素个数
add(): 增加一个新元素,返回当前集合
delete(): 删除元素,返回 boolean 值
has(): 检测集合中是否包含某个元素,返回 boolean 值
clear(): 清空集合,返回 undefined
let s1=new set([1,2,3,2,3]);
console.log(s1.size);
console.log(s1.add(4));
for(const e of s1){
console.log(e);
}
console.log(s1.delete(2));
console.log(s1.has(2));
console.log(s1.clear());
ES6 提供了Map数据结构。它类似于对象,也是键值对的集合。但是key可以是各种类型的值(包括对象)。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。Map 的属性和方法:
size: 返回 Map 的元素个数
set(): 增加一个新元素,返回当前 Map
get(): 返回键名映射的键值
has(): 检测 Map 中是否包含某个元素,返回 boolean 值
clear(): 清空集合,返回 undefined
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。新的 class 写法让对象原型的写法更加清晰、更像面向对象编程的语法而已。 知识点:
class 声明类
constructor 定义构造函数
extends 继承父类
super 调用父级构造方法
static定义静态方法和属性
父类方法可以重写
class Phone{ //父类
constructor(brand,color,price){ //构造方法
this.brand=brand;
this.color=color;
this.price=price;
}
call(){ //对象方法
console.log(this.brand +'品牌手机比较好')
}
}
class SmartPhone extends Phone{ //子类
constructor(brand,color,price,pixel){
super(brand,color,price);
this.pixel=pixel;
}
playGame(){ //子类方法
console.log('玩游戏流畅');
}
call(){ //方法重写
console.log('网络通畅');
}
static run(){
console.log('程序运行速度快');
}
}
Math.trunc(): 用于去除一个数的小数部分,返回整数部分。 Number.isInteger(): 用来判断一个数值是否为整数. Number.parseInt() 与 Number.parseFloat():这两个方法和全局方法 parseInt 和parseFloat的作用一样
Array.of():将一组数值转换为数组 find():数组实例方法,返回数组中第一个满足条件的元素,如果没有满足条件的元素,返回undefined
findIndex():数组实例方法,返回第一个符合条件的元素的索引,若无满足条件的元素,返回-1 keys(),values()和entries():它们都是数组实例的方法,都返回一个遍历器对象。 keys()返回可遍历所有键的Iterator,values返回可遍历所有值的Iterator,entries()返回可遍历所有键值的Iterator。利用for..of可以完成遍历操作 filter():去掉数组中不满足条件的数据,返回满足条件的数据 下面的示例保留可被5整除的数
const a1=[3,5,12,15,9];
let a2=a1.filter(item=>item % 5==0);
console.log(a2);
map(): 按某个条件对原数组进行检测,将元素映射到一个新数组中
const emps=[{
name:"张鸣",
salary:5600
},{
name:"李华",
salary:6100
},{
name:"王亮",
salary:7200
}];
let result=emps.map((value)=>{
(if(value.salary>6000){
return value.name;
}
return value.salary;
})
模块化是指将一个大的js程序文件,拆分成若干小的文件,然后将小文件组合起来。 当项目变的复杂的时候,一个html页面可能需要加载好多个js文件,这时很容易出现命名冲突(如a.js和b.js中定义了同名的变量s),并且多个js文件之间不能相互引用。 我们可通过模块化来解决上述问题。 模块化是一种管理方式,即把特定的功能封装到一个模块(文件)中,模块之间相互隔离,但可以通过特定的接口公开内部成员,也可以依赖别的模块。 模块化开发的好处:方便代码的重用,提升开发效率,方便后期的维护。
(1)CommonJS => NodeJS、Browserify (2)AMD => requireJS (3)CMD => seaJS
CommonJS是Node中的模块化规范,其特点如下: 1).模块分为单文件模块与包 2).模块成员导出:module.exports和exports 3).模块成员导入:require('模块标识符')
ES6模块化规范中有如下定义: 1). 每个js文件都是一个独立的模块 2). 导入模块成员使用import关键字 3). 暴露模块成员使用export关键字
Babel是一个javascript编译器,可将ECMAScript 2015+ 版本的代码转换为向后兼容的JavaScript 语法。简单的说,就是将ES6代码转为ES5代码,从而在现有环境执行(有些浏览器可能不兼容ES6)。 要使用Babel这款js语法转换器,需要做如下操作: (1).全局安装babel-cli和browserify(编译)
npm install babel-cli browserify -g
(2).在项目中定义package.json文件 (在项目根目录下执行npm init -y命令可自动生成该文件) 参考内容如下:
{ "name": "es6-babel", "version": "1.0.0" }
(3).在项目中安装预设(转换器)
npm install babel-preset-latest --save-dev 或
npm i babel-preset-latest -D
(4).在项目中添加.babelrc配置文件 该文件在项目的根目录下,用来设置转码规则和插件,基本格式如下。
{
"presets": [],
"plugins": []
}
parsets字段设定转换规则,官方提供以下规则集。 ES2015转码规则
npm install babel-preset-es2015 --save-dev
最新转码规则
npm install babel-preset-latest --save-dev
最后将转换规则加入.babelrc.例如 将最新转码规则加入
{
"presets": ["latest"],
"plugins": []
}
(5).在项目中编码,创建不同的模块 分别在src/js目录下创建2个js文件(模块),用来导出成员 module1.js: 导出模块成员方式1:分别暴露
export function foo() {console.log('module1 foo()');}
export let bar = function () {console.log('module1 bar()');}
export const DATA_ARR=[1,3,5]
module2.js: 导出模块成员方式2:统一暴露
let data = 'module2 data' function fun1() {console.log('module2 fun1() ' + data);}
function fun2() {console.log('module2 fun2() ' + data);}
export {fun1,fun2}
再创建main.js用来导入上面的模块 //引入其它的模块 import xxx from '路径' /以下{foo,bar}是解构赋值的写法,相当于解析module1实例的属性foo,bar(其值为函数),并赋值给foo和bar变量/
import {foo, bar, DATA_ARR} from './module1'
import {fun1, fun2} from './module2'
foo(); bar();
console.log(DATA_ARR);
fun1(); fun2();
(6).进行转码 首先创建输出目录,再执行如下命令
babel 源目录 -d 输出目录
browserify 源文件 -o 输出文件
其中-d参数指定输出目录,用browserify编译js
例如:babel src/js -d dist
browserify dist/main.js -o dist/index.js
这样在dist目录下就生成了转换后的index.js文件,它可兼容旧浏览器. 我们在页面上引入index.js文件,访问页面就能看到执行效果了,模块化成功! 补充:ES6规范中,导出模块成员除了上面用到的两种外,还有一种默认导出export default
let func=function(){
console.log("module3 func");
}
export default{
a,b,func
}
对于默认导出的方式,在导入时要import 模块实例名 from '路径'
//导入默认导出的模块成员
import m3 from './module3'
//调用默认导出的模块成员
m3.func();
console.log(m3.a);
/* let和const关键字
let 关键字用来声明变量,const关键字用来声明常量。
let和const的区别是:let是变量可以修改,const是常量不可以修改
let和const的相同点:
1.都不能重复声明 2.支持块级作用域,在作用域内定义的变量或常量只能在作用域内使用 */
let a = 10;
const city = '武汉';
console.log('a=' + a, city);
// city = '北京';
a = 20;
console.log('a=' + a, city);
if (true) {
let b = 15;
console.log(b);
}
//console.log(b); // 'b' is not defined
//在ES5中,没有专门声明常量的关键字,统一用var声明,es5中声明的变量不支持块级作用域
if (true) {
var s = 16;
}
console.log(s);
//city='南京';
//数组的解构赋值:把数组中的元素赋给变量
const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;
console.log(zhang, liu, li, guo);
const star = {
name: '黎明',
tags: ['歌神', '影帝']
};
//对象的解构赋值:把对象的属性值赋给变量,变量名要和对象的属性名一样
let {
name,
tags
} = star;
console.log(name);
console.log(tags);
let city = '南京';
console.log(`李明在${city}工作`);
//对象的简写
let name = "张三";
let p = {
name, //等价于name:name
work() {
console.log(`${this.name}正在工作!`);
}
}
p.work();
//ES5中不能用对象的简写
//rest参数:...args
//实现对任意个参数求和,并返回
function totalSum(...args) {
let sum = 0;
//args能收集所有的实参,把args当成数组来使用
if (args != null && args.length > 0) {
//for..in循环数组时,变量i代表索引
for (let i in args) {
sum += args[i];
}
}
return sum;
}
let result = totalSum();
console.log(result); //0
result = totalSum(2, 3);
console.log(result); //5
result = totalSum(2, 3, 9);
console.log(result); //14
//Spread扩展运算符:将一个数组转为用逗号分隔的参数序列,展开数组
const city1 = ['武汉', '南京'];
const city2 = ['北京', ...city1, '上海'];
console.log(city2);
const westEast = ['唐僧', '孙悟空', '八戒', '沙师弟'];
console.log(westEast);
//for...of遍历数组,element表示每个元素本身
for (let element of westEast) {
console.log(element);
}
//for..in遍历数组,element代表索引(从0开始)
for (let element in westEast) {
console.log(element);
}
console.log('*************************');
//for...of遍历数组,数组.keys()得到所有的索引(数组)
for (let element of westEast.keys()) {
if (element == 2) {
continue;
}
console.log(element, westEast[element]);
}
console.log('*************************');
//ES5中的forEach循环,它传入一个回调函数,参数e代表每个元素,i代表索引
westEast.forEach((e, i) => {
console.log(i, e);
if (i == 2) {
return; //结束当前这次循环
}
});
const set = new Set([1, 2, 3, 2, 4]);
console.log('size:' + set.size);
//新增成员
let result = set.add(5);
console.log(result);
console.log(result.has(5));;
//遍历
for (let item of result) {
console.log(item);
}
const bookMap = new Map([
['id', 'b001']
]);
//新增成员
bookMap.set('name', '红楼梦');
bookMap.set('price', 108);
console.log(bookMap);
console.log(bookMap.get('name'));
console.log(bookMap.has('price'));
//遍历:item代表key,value的键值对,键值对构成了数组
for (let item of bookMap.entries()) {
console.log(`key:${item[0]},value:${item[1]}`);
}
//父类
class Phone {
//构造函数
constructor(brand, color) {
this.brand = brand;
this.color = color;
}
//实例方法
call() {
console.log(`${this.brand}品牌的手机可以打电话!`);
}
}
//子类
class HuaWei extends Phone {
//构造函数
constructor(brand, color, price) {
//调用父类的构造函数
super(brand, color);
this.price = price;
}
//子类方法
playGame() {
console.log(this.price + '元的手机玩游戏', '品牌:' + this.brand, '颜色:' + this.color);
}
//重写父类的方法
call() {
console.log('我可以打视频电话');
}
//静态方法
static run() {
console.log('我可以运行大应用程序');
}
}
//创建对象
const parent = new Phone('苹果', '灰色');
parent.call();
console.log('******************************');
const child = new HuaWei('华为', '银色',
6800);
child.playGame();
child.call();
//调用静态方法
HuaWei.run();
// Array.of(): 将一组数值转换为数组
const arr = Array.of(10, true, 'Hello');
console.log(arr);
//find(): 数组实例方法,返回数组中第一个满足条件的元素,如果没有满足条件的元素,返回undefined
const arr2 = [3, 4, 6, 8, 9];
let result = arr2.find(item => item > 5)
console.log(result);
/* keys() , values()和 entries():它们都是数组实例的方法,都返回一个遍历器对象。
keys()返回可遍历所有键的Iterator,values返回可遍历所有值的Iterator,entries()返回可遍历所有键值的Iterator。利用for..of可以完成遍历操作 */
for (let i of arr2.keys()) {
console.log('index:' + i); //key就是索引
}
console.log('*******************************');
for (let v of arr2.values()) {
console.log(`value:${v}`);
}
console.log('*******************************');
for (let entry of arr2.entries()) {
console.log(`key:${entry[0]},value:${entry[1]}`);
}
console.log('*******************************');
const a1 = [3, 5, 15, 12, 19]
let a2 = a1.filter(value =>
value % 5 == 0
)
console.log(a2);
console.log('*******************************');
const stus = [{
name: '张明',
score: 78
}, {
name: '王亮',
score: 58
}, {
name: '朱云',
score: 90
}]
let a3 = stus.map(value => {
if (value.score > 80) {
return '优秀'
} else if (value.score >= 60) {
return '良好'
} else {
return '不及格'
}
})
console.log(a3);
本文章使用limfx的vscode插件快速发布