「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。
ECMAScript2015
摘要
1.新的标准规范
ECMAScript2015 是 js 的一种的新的标准规范,就是对 js 的写法上提出了新的语法要求和写法格式。
2.ECMAScript 和 js 关系
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。javascript 是 netscape 创 造的并交给了国际标准化组织 ECMA,之所以不叫做 JavaScript 由于商标的问题,java 是 sun 公司的商标,根据 授权协议只有 Netscape 公司可以合法使用 JavaScript 这个名字,另外就是为了体现 JavaScript 的标准的制定者 不是 ECMA 所以取名为 ECMAScript。
3.ES6 与 ECMAScript 2015 的关系
ES6 是 ECMA 的为 JavaScript 制定的第 6 个版本的标准,标准委员会最终决定,标准在每年的 6 月份正式发布一 次,作为当年的正式版本。ECMAscript 2015 是在 2015 年 6 月份发布的 ES6 的第一个版本。依次类推 ECMAscript 2016 是 ES6 的第二个版本、 ECMAscript 2017 是 ES6 的第三个版本……
块级作用域
1.块级作用域的种类
ECMAScript2015 为 js 提出的第三个作用域,凡是带{}的都是一个块级作用域。
if 语句的{},for 循环中的{},while 中的{},或者是我们单独写的{} try{}catch(error){}这些都提供了块级作用域。
块级作用域分析
1.为什么需要块级作用域?
-
内层变量会覆盖外层变量
var lagou = "拉勾"; function fn() { console.log(lagou); //undefined if (false) { var lagou = "hello"; } } fn();
这是因为 fn 函数体内以及有 var 声明的变量 lagou,只是还没有赋值,默认为 undefined。
-
用来计数的循环变量泄露为全局变量
for (var i = 0; i < 10; i++) {} // 10 console.log(i);
2.块级作用域的成员
块级作用域内的成员需要使用 let 或 const 命令定义的变量。
var lagou = "拉勾";
function fn() {
console.log(lagou); //拉勾
if (true) {
let lagou = "hello";
}
}
fn();
let const
1.let
基本用法
ECMAScript2015 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
let 主要声明块级作用域下的成员,这个成员变量的作用域范围只能在当前块级作用域下。
- wer
- er
2.const
const 声明变量的同时必须要赋值。
const 声明之后,不允许去修改它的值,这里面的值说的是不允许修改它,是声明之后不允许重新指向一个新
的内存地址,可以去修改内存地址中的属性成员。
数组
1.数组的解构
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
-
完全解构 将数组中的每一个值都对应上相应的变量。
var arr = ["lagou", "edu", "web"]; let [com, ind, work] = arr; console.log(work); //web -
不完全解构 数组中的部分值对应上了相应的变量。
var arr = ["lagou", "edu", "web"]; let [, , work] = arr; console.log(work); //web注意:模式没有匹配上的可以不填,但是必须要加逗号隔开。
-
扩展运算符...
-
展开运算符说明
-
三个点(…)是一个展开运算符,其功能为对三个点后面的变量进行展开操作
-
三个点(…)展开运算符:只能对具有 Iterator 接口的对象进行展开操作
-
使用场景
 案例一 ```jsvar arr=["拉勾","edu","web"]; fn(...arr)//web
案例二js let a = [88,99,100]; let b = [101,102,103]; a.push(...b); console.log(a);//[88, 99, 100, 101, 102, 103]案例三js let d={ e:"拉钩教育", f:"www.lagou.com" } let obj={ g:"web", h:1100, ...d }; console.log(obj); {g: "web", h: 1100, e: "拉钩教育", f: "www.lagou.com"}案例四js var st="拉钩 edu"; var arr=[...st]; console.log(arr)//["拉", "钩", "e", "d", "u"]掌握了展开运算符的使用规则,我们看一下数组的特殊解构。js let [a,...b] = [1,2,3,4,5,6]; console.log(a)//1 console.log(b)//[2,3,4,5,6]
-
-
-
解构不成功
右边的变量的个数超过了等号左边中数组的元素
let [a, b, c] = [12]; console.log(b); //undefined如果解构没有成功,则变量的值是 undefined,如果是展开运算的变量则是空数组。
let [a, b, ...c] = [12]; console.log(c); //[]
2.数组的扩展
-
扩展运算符...
-
扩展运算符(spread)是三个点(
...)它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。 -
替代 apply()的使用技巧
我们之前在求一个数组中的最大值得时候采用得方式是 Math.max.apply(null,[12,34,56,43]) ==56
var max = Math.max.apply(null, [12, 34, 56, 43]); console.log(max); //56 var max2 = Math.max(...[12, 34, 56, 43]); console.log(max2); //56
-
-
Array 类的扩展方法
- Array.from()
Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
var arraylike = { 0: "lagou", 1: "edu", 2: "web", length: 3, }; var arr = Array.from(arraylike); ["lagou", "edu", "web"];Array.from 还可以接受第二个参数,作用类似于数组的
map方法,用来对每个元素进行处理,将处理后的值放入返回的数组var arr = Array.from([1, 2, 3], function (x) { return x * x; }); console.log(arr); //[1,4,9]-
Array.of 方法用于将一组值,转换为数组,这个方法的主要目的,是弥补数组构造函数
Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。var arr = Array(3); //[emptyx3]这里面 3 表示数组中元素的长度。
var arr = Array(2, 3, 4); //[2,3,4]当
Array()里的参数个数大于 1 的时候,表示的是数组元素。Array.of()方法不管里面参数的个数多少,都将其转为数组的元素。var arr = Array.of(3); console.log(arr); //[3]
对象
1.对象中有关变量的解构赋值
解构不仅可以用于数组,还可以用于对象。对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { name, work } = { name: "lagou", work: "web" };
console.log(name, work); //lagou web
2.对象的扩展
-
对象的简写
-
当变量名和属性名同名式,省略同名的属性值
const foo = "bar"; const baz = { foo }; // 等同于 const baz = { foo: foo };
-
-
省略方法中的 function
const obj = { method() { return "拉勾!"; }, }; // 等同于 const obj = { method: function () { return "拉勾!"; }, };-
属性的赋值器(setter)和取值器(getter)
const lagou = { name: "拉勾", get com() { return this.name; }, set work(value) { this.name = this.name + value; }, }; console.log(lagou.com); //拉勾 lagou.work = "招聘"; console.log(lagou.name); //拉勾招聘 -
属性名表达式
es5 中定义对象的属性有两种方法,一种是用标识符做属性,一种是用表达式做属性
方法一; obj.name = "拉勾"; // 方法二 obj["name"] = "拉勾"; var lagou = { name: "拉勾", };如果使用大括号定义对象,那么在 es5 中只能使用标识符定义属性。
var lagou = { name: "拉勾", };但是 ECMAScript2015 在使用大括号定义对象的时候,允许使用表达式定义属性,把表达式放在方括号中。
let name = "lagou"; const lagou = { [name]: "web", }; console.log(lagou); //{lagou: "web"}
-
3.三点运算在对象中的用途
-
用于对象的解构
-
对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(z); //{a: 3, b: 4}上面代码中,变量
z是解构赋值所在的对象。它获取等号右边的所有尚未读取的键(a和b),将它们连同值一起拷贝过来。注意:1.解构赋值必须是最后一个参数。2.解构赋值的拷贝是浅拷贝。
-
-
用于扩展运算
-
对象的扩展运算符(
...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。let z = { name: "lagou", work: "web" }; let n = { ...z }; n; // { name: "lagou", work: "web" }
-
字符串
1.字符串模板
-
传统的字符串里不能使用换行符,必须使用转义符\n 替代,字符串模板里可以使用。模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
-
模板字符串中嵌入变量,需要将变量名写在
${}之中。大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性var name = "拉勾"; var st = `欢迎来到${name}`; console.log(st);
2.标签模板
-
模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能。
console.log`hello`; 等同于; console.log(["hello"]);标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
注意:如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
var name="laogou"; var work="web" function tag(st,a,b){ console.log(st); console.log(a); console.log(b) return "hello lagou"; } var st=tag`hello${name},职业${work}开发` console.log(st)//hello lagou ["hello", ",职业", "开发", raw: Array(3)] laogou web函数内的返回值,就是
tag函数处理模板字符串后的返回值。var name = "laogou"; var work = "web"; function tag(st, a, b) { console.log(st); console.log(a); console.log(b); return "hello lagou"; //如果没有返回值,则默认是undefined } var st = tag`hello${name},职业${work}开发`; console.log(st); //hello lagou
3.扩展的方法
-
字符串实例的方法
-
includes()
返回布尔值,表示是否找到了参数字符串
var st = "lagou web"; var b = st.includes("web"); console.log(b); //true -
startsWith()
返回布尔值,表示参数字符串是否在原字符串的头部
var st = "lagou web"; var b = st.startsWith("la"); console.log(b); //true -
endsWith()
返回布尔值,表示参数字符串是否在原字符串的尾部
var st = "lagou web"; var b = st.endsWith("web"); console.log(b); //true
-
函数
参数默认值
-
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
function fn(a, b = " lagou ") { console.log(a + b); } fn("hello"); //hello lagou -
注意:
- 参数变量是默认声明的,所以不能用
let或const再次声明. - 使用参数默认值时,函数不能有同名参数
- 参数变量是默认声明的,所以不能用
-
参数默认值的位置
-
通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。
function f(x = 1, y) { return [x, y]; } f() // [1, undefined] f(2) // [2, undefined] f(, 1) // 报错
-
rest 参数
-
ES6 引入 rest 参数(形式为
...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。function add(...values) { console.log(values); } add(2, 5, 3); // [2, 5, 3] -
rest 参数和函数中的参数解构有什么区别
- rest 参数是发生在函数的定义阶段,函数的额参数解构是发生在函数的调用阶段
- 二者是一种互为逆运算
function add(...values) {
//这是rest参数
console.log(values);
}
add(2, 5, 3); // [2, 5, 3]
var arr = [1, 2, 3];
function fn(a, b, c) {
console.log(a + b + c);
}
fn(...arr); //6 这是参数的解构
箭头函数
- ES6 允许使用“箭头”(
=>)定义函数。
var f = (v) => v;
// 等同于
var f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
// 等同于
var f = function () {
return 5;
};
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function (num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
var sum = (num1, num2) => {
return num1 + num2;
};
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
let getItem = id => { id: id, name: "Temp" }; //报错
let getItem = id => ({ id: id, name: "Temp" });//不报错
- 箭头函数有几个使用注意点
- 函数体内的
this对象,就是定义时所在的对象,而不是使用时所在的对象。箭头函数外面的 this 是什么,箭头函数内的 this 还是什么。 - 不可以当作构造函数,也就是说,不可以使用
new命令,否则会抛出一个错误。 - 不可以使用
arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
- 函数体内的
var name="web"
var obj={
name:"lagou",
fn(){
var t=setTimeout(function(){
console.log(this.name)//web this是window
},1000)
}
}
obj.fn()
-----------------------------------
var name="web"
var obj={
name:"lagou",
fn(){
var t=setTimeout(()=>{
console.log(this.name)//lagou this是obj
},1000)
}
}
obj.fn()
Object
Object.assign()
-
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。const target = { a: 123, b: 123, }; const sourcel = { a: 456, c: 456, }; const result = Object.assign(target, sourcel); console.log(target); //{a: 456, b: 123, c: 456} console.log(target === result); //true如果目标对象与源对象有同名属性,则后面的属性会覆盖前面的属性。且
assign()的返回值就是第一个对象。如果有多个源对象有同名属性,依然是后面的会覆盖前面的属性
const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target; // {a:1, b:2, c:3} -
利用
Object.assign()复制一个对象,且其中一个对象的修改不会影响到另一个对象const sourcel = { a: 123, }; var obj = Object.assign({}, sourcel); obj.a = 456; console.log(obj); //{a: 456} console.log(sourcel); //{a: 123}
Object.is()
-
Object.is就是用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。ES5 比较两个值是否相等,只有两个运算符:相等运算符(
==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。console.log(Object.is(+0, -0)); //false console.log(+0 === -0); //true console.log(Object.is(NaN, NaN)); //true console.log(NaN === NaN); //false
Proxy
概述
Proxy 可以理解成一个快递员,我们发快递还是接受快递,都需要这个快递员充当一个代理的作用。ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例,这个实例就是一个代理对象(快递员)。
var proxy = new Proxy(target, handler);
目标对象
这个代理对象有两个参数,一个是代理的目标对象,第二个也是一个对象,它是配置对象,用来定制代理的拦截行为。
const person = {
name: "zce",
age: 20,
};
const personProxy = new Proxy(person, {
get(target, property) {
console.log(target, property); //person{name:"zce",age:20}
return 100;
},
set() {},
});
配置对象
-
配置对象中一般有两个方法
get和set,get是用来拦截对目标对象属性的访问请求。get方法中有两个参数,第一个参数是目标对象,第二个参数是访问的那个属性。const person = { name: "zce", age: 20, }; const personProxy = new Proxy(person, { get(target, property) { console.log(target, property); return 100; }, set() {}, }); console.log(personProxy.name); //100
注意,这个get方法的返回值就是我们获取的这个属性的返回值。
-
这个
get方法中有三个参数,一个是代理的目标对象,一个是代理的处理对象,第三个参数是 proxy 实例本身,且第三个参数是可选参数。const person = { name: "zce", age: 20, }; const personProxy = new Proxy(person, { get(target, property, o) { console.log(o); //proxy{name:"zec",age:20} return property in target ? target[property] : undefined; }, set() {}, }); console.log(personProxy.age); //20 -
这个
set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选const person = { name: "zce", age: 20, }; const personProxy = new Proxy(person, { get(target, property, o) { return property in target ? target[property] : undefined; }, set(obj, pro, value, o) { console.log(obj, pro, value, o); }, }); console.log((personProxy.name = "zhang")); //{name: "zce", age: 20} "name" "zhang" Proxy {name: "zce", age: 20}可以去设置一些属性或修改
const person = { name: "zce", age: 20, }; const personProxy = new Proxy(person, { get(target, property, o) { return property in target ? target[property] : undefined; }, set(target, pro, value, o) { //可以做一些内部校验 target[pro] = value; }, }); console.log((personProxy.name = "lagou")); person; //{name:"lagou",age:20}