ECMA(European Computer Manufacturers Association)
中文名称为欧洲计算机制 造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该 组织改名为 Ecma
国际。
ECMAScript
是由Ecma
国际通过 ECMA-262
标准化的脚本程序设计语言。
Ecma
国际制定了许多标准,而 ECMA-262
只是其中的一个。所有标准列表点我查看
ECMA-262(ECMAScript)
历史版本点我查看
版本 | 时间 | 说明 |
---|---|---|
第1版 | 1997年 | 制定了语言的基本语法 |
第2版 | 1998年 | 较小改动 |
第3版 | 1999年 | 引入正则、异常处理、格式化输出等,IE开始支持 |
第4版 | 2007年 | 过于激进,未发布 |
第5版 | 2009年 | 引入严格模式、JSON,扩展对象、数组、原型、字符串、日期方法 |
第6版 | 2015年 | 模块化、面向对象语法、Promise、箭头函数、let、const、数组解构赋值等 |
第7版 | 2016年 | 幂运算符、数组扩展、Async/await关键字 |
第8版 | 2017年 | Async/swait、字符串扩展 |
第9版 | 2018年 | 对象解构赋值、正则扩展 |
第10版 | 2019年 | 扩展对象数组方法 |
ES.next | 动态指向下一个版本 |
TC39(Technical Committee 39)
是推进 ECMAScript
发展的委员会。其会员都是 公司(其中主要是浏览器厂商,有苹果、谷歌、微软、因特尔等)。TC39
定期 召开会议,会议由会员公司的代表与特邀专家出席
let
关键字用来声明变量,使用let声明的变量特点如下:
示例如下:
<script>
// 1. 不允许重复声明
// let name = '旺财';
// let name = '小强';
// 2. 块级作用域
// 声明的变量只能在块内使用,if while for else
// {
// let name2 = '罗志祥';
// console.log(name2);
// }
// console.log(name2);
// 3. 不存在变量提升
// console.log(song);
// let song = '白色空间';
// 4. 不影响作用域
// {
// let girl = '周扬青';
// function test(){
// console.log(girl);
// }
// test();
// }
script>
const
关键字用来声明常量,特点如下:
示例如下:
<script>
const VALUE = 12;
// VALUE = 13; 会报错
const person = {
name:'wangcai',
age:12
}
console.log(person);// {name: "wangcai", age: 12}
person.name = '小强';// 不会报错
console.log(person);// {name: "小强", age: 12}
person = {
};// Uncaught TypeError: Assignment to constant variable
script>
注意:对象属性修改和数组元素变化不会触发const报错
应用场景:
const
let
ES6
允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这称为解构赋值。
示例如下:
<script>
// 1. 数组的解构赋值
const names = ["张三", "李四", "王五"];
let [zhang, li, wang] = names;
console.log(zhang);
console.log(li);
console.log(wang);
// 2. 对象的解构赋值
const person = {
name: "旺财",
age: 12,
eat: function () {
console.log("我就知道吃");
},
};
let {
name, age, eat } = person;
console.log(name);
console.log(age);
eat();
// 3. 复杂解构赋值
let tingfeng = {
name: "谢霆锋",
age: 38,
songs: ["忘情水", "北京欢迎你"],
history: [
{
name: "谢小小",
},
{
name: "谢大大",
},
],
};
let {
songs: [one, two],
history: [first, second],
} = tingfeng;
console.log(one);
console.log(history);
console.log(second);
script>
注意:频繁使用对象方法、数组元素,就可以使用解构赋值
模板字符串(template string)
是增强版的字符串,用反引号(`)标识,特点如下:
${xxx}
形式输出变量示例如下:
<script>
// 1. 声明模板字符串
let str = `我也是一个字符串哦`
// 2. 内容中可以直接出现换行符
let str2 = `
- 肾疼
- 腰疼
- 胸疼
`
// 3. 变量拼接
let name = '旺财'
let out = `${
name}是我的最爱哦`
console.log(out);
script>
注意:当遇到字符串与变量拼接时使用模板字符串
ES6
允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。
示例如下:
<script>
let name = '旺财'
let change = function(){
console.log('我们可以改变世界');
}
const person={
name,
change,
eat(){
console.log('我们还可以吃吃吃');
}
}
console.log(person);
script>
注意:对象简写形式简化了代码,推荐以后使用简写
ES6
允许使用「箭头」(=>)定义函数,注意点如下:
arguments
示例如下:
<script>
// 1.通用写法
let fn = (agr1, arg2, arg3) => {
return agr1 + arg2 + arg3;
};
let result = fn(1, 2, 3);
console.log(result);
// this是静态的,始终指向函数声明时所在作用域下的this的值
function getName() {
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
};
// 设置window的name属性
window.name = "旺财";
const person = {
name: "小强",
};
// 直接调用
getName(); // 旺财
getName2(); // 旺财
// call方法调用
getName.call(person); //小强
getName2.call(person); // 旺财
// 2. 不能作为构造函数实例化对象
// let Dog= (name,age)=>{
// this.name = name
// this.age = age
// }
// let d = new Dog('旺财',12)
// console.log(d);//Uncaught TypeError: Dog is not a constructor
// 3. 不能使用arguments变量
// let fn2 = () => {
// console.log(arguments);//Uncaught ReferenceError: arguments is not defined
// };
// fn2();
// 4. 箭头函数的简写
// 1. 当形参只有一个参数时,可以省略小括号
let add = (n) => {
return n + n;
};
// 2. 当函数体只有一条语句的时候,此时return可以省略,且语句的执行结果就是函数的返回值
let pow = (n) => n * n;
console.log(pow(2));
script>
ES6
允许给函数参数赋值初始值。
示例如下:
<script>
// 1. ES6允许给函数参数设置默认值,一般位置放最后
function add(a, b, c = 10) {
return a + b + c;
}
let result = add(1, 2, 3);
console.log(result);
// 2. 与解构赋值结合
function connect({
host = "127.0.0.1", port, username, password }) {
console.log(host);
console.log(password);
}
connect({
host: "localhost",
port: "8080",
username: "root",
password: "root",
});
script>
ES6
引入rest
参数,用于获取函数的实参,用来代替arguments
。
示例如下:
<script>
// ES5获取实参方式
function data(){
console.log(arguments);
}
data('旺财','小强','大明')
// ES6 rest参数
function data2(...args){
console.log(args);
}
data2('猪','鸭','鱼') // ["猪", "鸭", "鱼"]
script>
注意:rest参数非常适合不定个数参数函数的场景
「...」
扩展运算符能将数组转换为逗号分隔的「参数序列」。
示例如下:
<body>
<div>div>
<div>div>
<div>div>
<script>
// ...扩展运算符能将一个数组转换成以逗号分隔的参数序列
const tfboys = ['易烊千玺','王源','黄晓明'] // => '易烊千玺','王源','黄晓明'
function chunwan(){
console.log(arguments);
}
chunwan(...tfboys)
// 1. 数组的合并
const kuaizi = ['肖央','王太利']
const fenghuang = ['曾毅','玲花']
const zuixuanxiaopingguo = kuaizi.concat(fenghuang)
console.log(zuixuanxiaopingguo);
const zuixuanxiaopingguo2 = [...kuaizi,...fenghuang]
console.log(zuixuanxiaopingguo2);
// 2. 数组的克隆
const sanzhihua = ['E','G','M']
const sanyecao = [...sanzhihua]
console.log(sanyecao);
// 3. 将伪数组转换为真正的数组
const divs = document.querySelectorAll('div')
console.log(divs);
const divArr = [...divs]
console.log(divArr);
script>
body>
ES6
引入了一种新的原始数据类型Symbol
,表示独一无二的值。他是javascript
语言的第七种数据类型,是一种类似于字符串的数据类型。
特点如下:
symbol
的值是唯一的,用来解决命名冲突问题symbol
值不能与其他数据进行运算symbol
定义的对象属性不能使用for...in
循环遍历,但是可以使用Reflect.ownKeys
来获取对象的所有键名注意:遇到唯一性的场景,要使用symbol
Symbol()
Symbol('xxx')
Symbol.fro('xxx')
示例如下:
<script>
// 创建symbol
let s = Symbol();
console.log(s, typeof s); // 10-symbol基本使用.html:12 Symbol() "symbol"
let s2 = Symbol("demo");
let s3 = Symbol("demo");
console.log(s2, s3, s2 === s3); // Symbol(demo) Symbol(demo) false
let s4 = Symbol.for("test");
let s5 = Symbol.for("test");
console.log(s4 === s5); // true
// 不能与其他数据进行计算
// let result = s + 100
script>
示例如下:
<script>
let game = {
};
// 声明一个对象
let methods = {
up: Symbol(),
down: Symbol(),
};
game[methods.up] = function () {
console.log("我可以快速上升");
};
game[methods.down] = function () {
console.log("我可以快速下降");
};
console.log(game);
// 添加symbol属性2
let youxi = {
name: '狼人杀',
[Symbol('say')]:function(){
console.log('我可以发炎');
},
[Symbol('zibao')]:function(){
console.log('我可以自爆');
}
}
console.log(youxi);
script>
除了定义自己使用的Symbol
值意外,ES6
还提供了11个内置的Symbol
值,指向语言内部使用的方法,可以称这些方法为魔术方法,因为他们会在特定的场景下自动执行。
方法 | 描述 |
---|---|
Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对 象的实例时,会调用这个方法 |
Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个 布尔值,表示该对象用于 Array.prototype.concat()时, 是否可以展开。 |
Symbol.species | 创建衍生对象时,会使用该属性 |
Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会 调用它,返回该方法的返回值。 |
Symbol.replace | 当该对象被 str.replace(myObject)方法调用时,会返回 该方法的返回值 |
Symbol.search | 当该对象被 str. search (myObject)方法调用时,会返回 该方法的返回值。 |
Symbol.split | 当该对象被 str. split (myObject)方法调用时,会返回该 方法的返回值。 |
Symbol.iterator | 对象进行 for…of 循环时,会调用 Symbol.iterator 方法, 返回该对象的默认遍历器 |
Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。 |
Symbol.toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返 回值 |
Symbol.unscopables | 该对象指定了使用with关键字时,哪些属性会被with 环境排除。 |
迭代器是一种机制,他是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator
接口,就可以完成遍历操作。
ES6
创造了一种新的遍历命名for..of
循环,Iterator
接口主要供for..of
消费。
原生具备Iterator
接口的数据(可用for of
遍历):
工作原理:
注意: 需要自定义遍历数据的时候,要想到迭代器
示例代码:
<script>
const xiyou = ["猪八戒", "唐僧", "孙猴子", "沙僧"];
for (let v of xiyou) {
console.log(v);
}
// 自定义迭代器
const banji = {
name: "终结一班",
students: ["小米", "三星", "华为"],
[Symbol.iterator]() {
let index = 0;
let _this = this;
return {
next: function () {
if (index < _this.students.length) {
const result = {
value: _this.students[index], done: false };
index++;
return result;
} else {
return {
value: undefined, done: true };
}
},
};
},
};
for(let stu of banji){
console.log(stu);
}
script>
生成器函数时ES6
提供的一种异步变成解决方案,语法行为与传统函数完全不同。
示例代码:
<script>
// 生成器其实就是一种特殊的函数,异步编程
function* gen() {
console.log("hello generator");
yield "一只没有耳朵";
yield "一只没有尾巴";
yield "真奇怪 真奇怪";
}
let iterator = gen();
console.log(iterator);
console.log(iterator.next()); //{value: "一只没有耳朵", done: false}
console.log(iterator.next()); //{value: "一只没有尾巴", done: false}
console.log(iterator.next()); //{value: "真奇怪 真奇怪", done: false}
console.log(iterator.next()); //{value: undefined, done: true}
// 遍历
// for(let v of gen()){
// console.log(v);
// }
script>
示例如下:
// 生成器传参
function* gen2(arg) {
console.log(arg);// AAA
let one = yield 111;
console.log(one);// BBB
let two = yield 222;
console.log(two);//CCC
let three = yield 333;
console.log(three);//DDD
}
// 执行获取迭代器对象
let iterator2 = gen2('AAA')
console.log(iterator2.next())
// next方法可以传入实参
console.log(iterator2.next('BBB'));
console.log(iterator2.next('CCC'));
console.log(iterator2.next('DDD'));
示例一:
<script>
// 需求 1S后控制台输出111,2S后输出222,3S后输出333
function one() {
setTimeout(() => {
console.log("111");
iterator3.next()
}, 1000);
}
function two() {
setTimeout(() => {
console.log("222");
iterator3.next()
}, 2000);
}
function three() {
setTimeout(() => {
console.log("333");
iterator3.next()
}, 3000);
}
function* gen() {
yield one();
yield two();
yield three();
}
let iterator3 = gen()
iterator3.next()
script>
示例二:
<script>
// 模拟获取 用户数据->订单数据->商品数据
function getUser() {
setTimeout(() => {
console.log("用户数据获取成功");
let data = "用户数据";
iterator4.next(data)
}, 1000);
}
function getOrders() {
setTimeout(() => {
console.log("订单数据获取成功");
let data = "订单数据";
iterator4.next(data)
}, 1000);
}
function getGoods() {
setTimeout(() => {
console.log("商品数据获取成功");
let data = "商品数据";
iterator4.next(data)
}, 1000);
}
function* gen4() {
let user = yield getUser();
console.log(`user:${
user}`);
let orders = yield getOrders();
console.log(`orders:${
orders}`);
let goods = yield getGoods();
console.log(`goods:${
goods}`);
}
let iterator4 = gen4();
iterator4.next();
script>
Promise
是ES6
引入的异步编程的新解决方案。语法上Promise
是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
示例:
<script>
// 实例化Promise对象
new Promise(function (resolve, reject) {
setTimeout(() => {
let data = "hello world";
// resolve(data);
reject('error')
}, 1000);
}).then(
function (value) {
// 成功回调 resolve
console.log(value);
},
function (reason) {
// 失败回调 reject
console.log(reason);
}
);
script>
ES6
提供了新的数据结构Set
,类似于数组,但成员的值都是唯一的,集合实现了iterator
接口,所有可以使用「扩展运算符」
和「for...of...」
进行遍历,集合的属性和方法如下:
size
:返回集合的元素个数add
:增加一个新元素,返回当前集合delete
:删除元素,返回boolean
值has
:检测集合中是否包含某个元素,返回boolean
值clear
:清空集合,返回undefined
<script>
const s = newSet(["旺财", "小米", "三星", "华为", "苹果"]);
console.log(s.size);
s.add("诺基亚");
s.delete("旺财");
console.log(s.has("vivo"));
s.clear();
console.log(s);
// 示例
let arr = [1, 2, 1, 3, 5, 6, 2, 4, 5, 3];
// 1. 数组去重
let r1 = [...new Set(arr)];
console.log(r1);
// 2. 数组取交集
let arr2 = [2, 3, 4, 2, 3, 9, 10];
let r2 = [...new Set(arr)].filter((item) => new Set(arr2).has(item));
console.log(r2);
// 3. 并集
let union = [...new Set([...arr, ...arr2])];
console.log(union);
// 4. 差集
let r4 = [...new Set(arr)].filter((item) => !new Set(arr2).has(item));
console.log(r4);
script>
ES6
提供了Map
数据结构,它类似于对象,也是键值对的集合。但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了iterator接口,所以可以使用「扩展运算符」
和「for...of..」
进行遍历。Map的属性和方法如下:
size
:返回Map
的元素个数set
:增加一个新元素,返回当前Mapget
:返回键名对象的键值has
:检测Map
中是否包含某个元素,返回boolean
值clear
:清空集合,返回undefined
示例:
const m = new Map()
m.set('name','旺财')
m.set('change',function(){
console.log('我是大旺财');
})
console.log(m.get('name'));
m.set('demo','test')
m.delete('demo')
for(let v of m){
console.log(v);
}
m.clear()
console.log(m);
ES6
提供了更接近传统语言的写法,引入了Class
(类)这个概念,作为对象的模板。通过class
关键字可以定义类。
基本上,ES6
的class
可以看做只是一个语法糖,它的绝大部分功能,ES5
都可以做到,新的class
写法只是让对象原型的写法更加清晰、更加面向对象编程的语法而已。
知识点:
class
声明类constructor
定义构造函数初始化extends
继承父类super
调用父级构造方法static
定义静态方法和属性示例:
<script>
// class初体验
class Phone {
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
call() {
console.log("我可以打电话哦");
}
// get set方法
get price() {
console.log("get prices called");
return 2999;
}
set price(newVal) {
console.log("set price called");
}
// 静态属性
static version = "MIUI 12.0.2";
// 静态方法
static printVersion() {
console.log("i am ", this.version);
}
}
let huawei = new Phone("华为", 1111);
huawei.call();
console.log(huawei.version); // undefined
// huawei.printVersion()// Uncaught TypeError: huawei.printVersion is not a function
console.log(Phone.version); // MIUI 12.0.2
Phone.printVersion(); //i am MIUI 12.0.2
// get set test
console.log(huawei.price);// 2999
huawei.price = "3999";
console.log(huawei.price);
// 类继承
class SmartPhone extends Phone {
constructor(brand, price, color, size) {
super(brand, price);
this.color = color;
this.size = size;
}
photo() {
console.log("我可以拍照哦");
}
// 子类重写父类方法
call() {
console.log("我可以视频通话哦");
}
}
let xiaomi = new SmartPhone("小米", 1999, "red", 6.9);
xiaomi.photo(); // 我可以拍照哦
xiaomi.call(); // 我可以视频通话哦
script>
body>
ES6
提供了二进制和八进制数值的新的写法,分别用前缀0b
和0o
表示。
// 二进制和八进制
let b = 0b1010;
let o = 0o777;
let d = 100;
let x = 0xff;
console.log(b, o, d, x);
Number.isFinite()
用来检查一个数值是否是有限的Number.isNaN()
用来检查一个值是否为NaN
ES6
将全局方法parseInt
和parseFloat
移植到Number
对象上面,使用不变
Math.trunc()
用于去除一个小数的小数部分,返回整数部分
Number.isInteger()
用来判断一个数值是否为整数
<script>
// 二进制和八进制
let b = 0b1010;
let o = 0o777;
let d = 100;
let x = 0xff;
console.log(b, o, d, x); //10 511 100 255
// isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100)); // true
console.log(Number.isFinite(100 / 0)); // false
console.log(Number.isFinite(Infinity)); // false
// isNaN检测一个数值是否为NaN
console.log(Number.isNaN(123)); // false
// parseInt parseFloat字符串转整数
console.log(Number.parseInt("123asa")); //123
console.log(Number.parseFloat("2.3431ifm是")); //2.3431
// isInteger判断一个数是否为整数
console.log(Number.isInteger(5)); //true
console.log(Number.isInteger(5.2)); //false
// trunc将数字的小数部分抹掉
console.log(Math.trunc(3.4)); //3
// sign判断一个梳到底为整数 负数 还是零
console.log(Math.sign(100)); //1
console.log(Math.sign(0)); //0
console.log(Math.sign(-100)); //-1
script>
ES6
新增了一些Object
对象的方法:
Object.is
:比较两个值是否严格相等,与「===」行为基本一致(+0与NaN)Object.assign
:对象的合并,将源对象的所有可枚举属性,复制到目标对象__proto__
、setPrototypeOf
可以直接设置对象的原型示例:
<script>
// 1. Object.is判断两个值是否完全相等
console.log(Object.is(120, 120)); //true
console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false
// 2. Object.assign对象的合并
const config1 = {
host: "localhost",
port: "9090",
};
const config2 = {
port: "8080",
username: "username",
};
console.log(Object.assign(config1, config2)); //{host: "localhost", port: "8080", username: "username"} 同字段的话后面会把前面的替换
// 3, Object.setPrototypeof 设置对象原型
const p = {
name: "旺财",
};
const hobbis = {
hobbies: ["篮球", "足球"],
};
Object.setPrototypeOf(p, hobbis);
console.log(Object.getPrototypeOf(p)); //hobbies: (2) ["篮球", "足球"] _proto__: Object
console.log(p); //{name: "旺财"}name: "旺财"__proto__: hobbies: (2) ["篮球", "足球"]__proto__: Object
script>
模块化是指将一个大的程序文件,拆分为许多小的文件,然后将小文件组合起来。
模块化的优势有以下几点:
ES6
之前的模块化规范有:
CommonJS
==> NodeJS
、Browerify
AMD
===> requireJS
CMD
==> seaJS
模块功能个主要由两个命令构成:export
和import
export
:用于规定模块的对外接口,导出import
:用于输入其他模块提供的功能,导入