ES5和ES6

91 阅读8分钟

ES5

1.严格模式

1-1. 什么是严格模式

  严格模式,从字面上就很好理解,即更严格的模式 在这种模式下执行,浏览器会对JS的要求更苛刻,语法格式要求更细致,更符合逻辑。

怪异模式:就是我们之前一直使用的开发模式,就叫怪异模式。因为很多时候出来的结果是非常怪异的,所以才称之为怪异模式。

1-2. 严格模式的优点

  • 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
  • 代码运行的一些不安全之处,保证代码运行的安全;
  • 提高编译器效率,增加运行速度;

1-3. 使用严格模式

"use strict";

1-4. 严格模式的分类

  • 全局严格 函数外的,全局的
"use strict";
n = 10;
console.log(n);//报错 Uncaught ReferenceError: n is not defined
  • 局部严格 函数内的,是局部的
function fn(){
    "use strict";
    n = 10
    console.log(n);//报错 Uncaught ReferenceError: n is not defined
}

1-5. 使用严格模式的注意点

  1. 不可以省略声明变量的关键字(如,var、let、const)
"use strict";
n = 10;
console.log(n);//报错 Uncaught ReferenceError: n is not defined
  1. 禁止函数使用this关键字指向全局变量
"use strict";
function fn(){
    console.log(this);//undefined
}
fn();
  1. 禁止使用八进制方法
//未使用严格模式
var num=027;//八进制数27
console.log(num);//23   自动转成十进制
//使用严格模式
var num=027;//八进制数27
console.log(num);//Uncaught SyntaxError: Octal literals are not allowed in strict mode. 
  1. 不允许在非函数的代码块内声明函数
"use strict";
{
    function fn(){
        console.log(this);
    }
}
fn();//Uncaught ReferenceError: fn is not defined
  1. 严格模式下,arguments变量,形参是不会变(不同步)
//未使用严格模式
function fn(a){
    console.log(a);//10
    a=20;
    console.log(arguments);//Arguments [20, callee: (...), Symbol(Symbol.iterator): ƒ]
}
fn(10)
//使用严格模式
"use strict"
function fn(a){
    console.log(a);//10
    a=20;
    console.log(arguments);//Arguments [10, callee: (...), Symbol(Symbol.iterator): ƒ]
}
fn(10)

2.bind、apply、call

作用:绑定一个新对象, 让函数中的this指向该对象
区别:bind不会立即执行,需要手动执行。apply和call都会立即执行,区别在于apply第2个参数是一个数组

var person = {
    name: "刘诗诗"
}
var obj = {
    name: "刘亦菲",
    show(skill,dress) {
        console.log(this);
        console.log("姓名:"+this.name);
        console.log("技能:"+skill);
        console.log("穿着:"+dress);
    }
}
console.log("-------原来的-------");
obj.show("演戏", "古装")

console.log("-------更改后--------");
obj.show.bind(person)("演戏", "古装");//用于改变this的指向,并不会执行方法,需要后面再补一个小括号传入实参
obj.show.apply(person, ["演戏", "古装"]);//第一个参数改变this的指向,第二个参数为数组,为实参
obj.show.call(person, "演戏", "古装");//第一个参数改变this的指向,后面直接传实参

控制台输出: image.png

3.Array新增

  1. indexOf():判断数组中是否包含某个元素。
  2. forEach():用来遍历数组中的每一项;这个方法执行是没有返回值的,对原来数组也没有影响。
  3. map():和forEach非常相似,都是用来遍历数组中的每一项的,区别是map的回调函数中支持return返回。
  4. reduce():接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终为一个值,是ES5中新增的一个数组逐项处理方法。
  5. filter():过滤出数组中你想要的元素,不改变原数组。
  6. ……

具体用法见“JS数组”中的高阶函数(ES5)

ES6

1.let

作用类似于var,用来声明变量,但是所声明的变量,只在let命令所在的代码块内有效。

  1. 它如果在{}内部声明的变量,外部不能访问
  2. 它防止了变量提升,遵循先定义后使用
  3. 它防止了同一个变量重复被定义
  4. 它声明的值可以被修改,也可以被修改成任意类型(与const的区别)
if(true){
    var a = 1;
    let b = 2;
}
console.log(a);//1
console.log(b);//报错 Uncaught ReferenceError: b is not defined  

let关键字涉及到一个概念——块级作用域:ES6以前,只有全局作用域和函数局部作用域,ES6之后加入块级作用域,一个大括号{}我们称之为一个代码块,一个大括号{}的内部就是块级作用域。

2.const

const 声明的是常量,一旦声明,值将是不可变的。

  1. 它的变量名只能声明一次,不能重复声明
  2. 它防止了变量提升
  3. 它具备块级作用域
  4. 它的值不能被修改
    如果是引用类型,可以修改它的属性或方法,不能修改类型和地址

3.String新增

  1. includes():返回布尔值,表示是否找到了参数字符串。
  2. startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
  3. endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
  4. repeat():返回一个新字符串,表示将原字符串重复n次。
  5. ``:字符串模版

具体用法见“JS字符串”中的字符串方法

4.Array新增

  1. Array.from():方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。
  2. Array.of():方法用于将一组值,转换为数组。
  3. find():通过条件查找,如果存在返回满足条件的这一项,如果不存在就返回undefined。
  4. findIndex():通过条件查找,如果存在返回满足条件的这一项的下标,如果不存在就返回-1。
  5. for-of 遍历集合:这是目前遍历数组最简洁和直接的语法;它避免了for-in的所有缺陷;与forEach()不一样,它支持break,continue和return。遍历数组得到的是值,是根据长度遍历。
var arr = [11, 22, 33, , , , 77]
for (var val of arr) {
    console.log(val);
}

image.png

5.Function新增

5-1.函数默认参数

function fn(num = 100) {//设置默认参数值
    console.log(num);
}
fn(10)//10
fn()//100

5-2.扩展运算符(spread)

...三个点

//将一个数组转为用逗号分隔的参数序列
var arr = ['张三', '李四', '王五'];
function fn(a,b,c) {
    console.log(`${a},${b},${c}`); //张三,李四,王五 
}
fn(...arr);

//求最大值、最小值
var arr=[11,22,33,44]
var max=Math.max(...arr);
var min=Math.min(...arr);
console.log(max);//44
console.log(min);//11

//可用于浅拷贝数组或对象
var person = { name: "张三", age: 20 };
var newPerson = { ...person }
console.log(person);//{name: '张三', age: 20}
console.log(newPerson);//{name: '张三', age: 20}

var arr = [11, 22, 33, 44]
var newArr = [...arr]
console.log(arr);//(4) [11, 22, 33, 44]
console.log(newArr);//(4) [11, 22, 33, 44]


//可用于合并数组或对象
var person = { name: "张三", age: 20 };
var student = { id: 1001, grade: "高一" }
var concatObj = { ...person, ...student };
console.log(concatObj);//{name: '张三', age: 20, id: 1001, grade: '高一'}


var arr1 = [11, 22, 33]
var arr2 = [88, 99]
var arr3 = [...arr1, ...arr2]
console.log(arr3);//(5) [11, 22, 33, 88, 99]

//剩余参数
// a 接收了 11
// b 接收了 22
// 剩下的全部给了arr
function fn(a,b,...arr){
    console.log(a,b);//11 22
    console.log(arr);//(8) [33, 44, 55, 66, 77, 88, 99, 10]
}
fn(11,22,33,44,55,66,77,88,99,10)

5-3.箭头函数

ES6允许使用“箭头”=>定义函数

//普通
function fn(num) {
    return num * 10;
}

//箭头函数简化,与上面的等价
//1.只有一个参数,就可以省略小括号
var fn = num => {
    return num * 10;
}
//2.如果代码体只有一句话,{}和return都可省略
var fn = num => num * 10;

6.Object新增

6-1.属性简写

var age = 20;
var sex = "女";
var a = "na", b = "me"
var obj = {
    //属性简写
    age, sex,
    // 等价于:
    // age:age
    // sex:sex
    
    //属性名表达式
    [a + b]: "刘亦菲"
}
console.log(obj);//{age: 20, sex: '女', name: '刘亦菲'}

6-2.方法简写

var a = "clo";
var b = "se";
var obj = {
    // show:function(){
    // }
    //方法简写
    show() {
    },
    //方法名表达式
    [a + b]() {
    },
}
console.log(obj);//{show: ƒ, close: ƒ}

6-3 Object.assign()

Object.assign(target, source1[, source2,...]);
用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。

//Object.assign的方式合并数组
var obj1 = { id: 1, name: "刘亦菲" }
var obj2 = { name: "刘诗诗", age: 18 }
//合并返回一个新的对象
var obj4 = Object.assign({}, obj1, obj2)
console.log(obj4);//{id: 1, name: '刘诗诗', age: 18}
console.log(obj1);//{id: 1, name: '刘亦菲'}
console.log(obj1 === obj4);//false

6-4 Object.is( , )

用来比较两个值是否严格相等。它与严格比较运算符(===)的行为基本一致, 不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

//Object.is  它属于恒等于 ===
console.log(NaN == NaN);//false
console.log(NaN === NaN);//false
console.log(Object.is(NaN, NaN));//true

console.log(-0 == 0);//true
console.log(-0 === 0);//true
console.log(Object.is(-0, 0));//false

console.log(Object.is(10, "10"));//false
console.log(Object.is(true, 1));//false
console.log(Object.is(10, 10));//true
console.log(Object.is({}, {}));//false 2个不同的对象

7.Set

数据结构Set类似于数组,但是成员的值都是唯一的,没有重复的值。

var set = new Set([1,2,3,4,5,5,5,5]);
console.log(set.size); // 5

7-1.Set的属性和方法

  • size : 数量
  • add(value):添加某个值,返回Set结构本身
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功
  • has(value):返回一个布尔值,表示该值是否为Set的成员
  • clear():清除所有成员,没有返回值
var set = new Set([1, 5, 5, 1, 2, 2, 3, 1, 2, 1]);//给初始值
console.log(set.add(1));//Set(4) {1, 5, 2, 3}  //不能添加重复项
console.log(set.add(7));//Set(5) {1, 5, 2, 3, 7} //添加成功,返回变化后的集合
console.log(set.delete(2));//true //如果删除成功返回true,删除失败返回false
console.log(set.has(1));//true   //判断是否存在,存在返回true,不存在返回false
set.forEach(function (val1, val2, set) {//遍历
    //1 1 Set(4) {1, 5, 3, 7}
    //5 5 Set(4) {1, 5, 3, 7}
    //3 3 Set(4) {1, 5, 3, 7}
    //7 7 Set(4) {1, 5, 3, 7}
    console.log(val1, val2, set);
})
console.log(set.size);//4
set.clear()//清除所有成员
console.log(set);//Set(0) {size: 0}

7-2.利用Set解决数组去重

//利用Array.from() 或[...set]转换成数组解决数组去重问题
var list = [1, 5, 5, 1, 2, 2, 3, 1, 2, 1];
var arr = [...new Set(list)];  
// var arr=Array.from(new Set(list));//这里与上面一行的效果一样
console.log(arr);//(4) [1, 5, 2, 3]

8.WeakSet

WeakSet和Set一样都不存储重复的元素, 用法基本类似,但有一些不同点, WeakSet的成员只能是对象,而不能是其他类型的值。

var wset=new WeakSet([{id:1,name:"刘亦菲"},{id:1,name:"刘亦菲"}]);//有两个对象,因为这两个对象的地址不同
console.log(wset);//WeakSet {{…}, {…}}
var wset=new WeakSet();
var obj={id:1,name:"刘亦菲"}
var wset=new WeakSet([obj,obj]);//只有一个对象,因为它们是一个对象
console.log(wset);//WeakSet {{…}}
console.log(wset.add({id:2,name:"刘诗诗"}));//添加
console.log(wset.has(obj));//判断是否存在
console.log(wset.delete(obj));//删除

9.Map

Map 是一个“超对象”,其 key 除了可以是 String 类型之外,还可以为其他类型(如:对象)。

//Map([[key,value],[key,value]])
let map = new Map([[1, 'one'],[2, 'two'],[3, 'three']]);

9-1.Map的方法和属性

  • size:返回成员总数。
  • set(key, value):设置一个键值对。
  • get(key):读取一个键。
  • has(key):返回一个布尔值,表示某个键是否在Map数据结构中。
  • delete(key):删除某个键。
  • clear():清除所有成员。
  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
var map = new Map([
    [1, "刘亦菲"],
    ["age", 18],
    [3, { foods: ["螺蛳粉", "新疆炒米粉", "麻辣烫"] }]
])
console.log(map.size);//3
map.set("address", "中国");//添加
console.log(map);//Map(4) {1 => '刘亦菲', 'age' => 18, 3 => {…}, 'address' => '中国'}
map.set(1, "刘诗诗");//添加  键存在则会覆盖原来的值
console.log(map);//Map(4) {1 => '刘诗诗', 'age' => 18, 3 => {…}, 'address' => '中国'}
console.log(map.delete(1));//true    //根据键删除
console.log(map.has(3));//true   //判断键是否存在
console.log(map.get(3));//{foods: Array(3)}     //根据键获取值
map.forEach(function (val, key, map) {
    //遍历
    //age 18 Map(3) {'age' => 18, 3 => {…}, 'address' => '中国'}
    //3 {foods: Array(3)} Map(3) {'age' => 18, 3 => {…}, 'address' => '中国'}
    //address 中国 Map(3) {'age' => 18, 3 => {…}, 'address' => '中国'}
    console.log(key, val, map);
})
        
var obj = map.keys()//获取所有的key值
console.log(obj);//MapIterator {'age', 3, 'address'}

var vals = map.values()//获取所有的value值
console.log(vals);//MapIterator {18, {…}, '中国'}

//获取键值对,默认就是 entries
var entries=map.entries();
console.log(entries);//MapIterator {1 => '刘诗诗', 'age' => 18, 3 => {…}, 'address' => '中国'}

map.clear();//清空
console.log(map);//Map(0) {size: 0}

10.解构赋值

//----------对象------------
var obj = { id: 1, name: "刘亦菲", age: 18 }
var { id, age, name } = obj;//顺序可打乱,key名不可更改
console.log(id, name, age);
//外部如果有相同的变量名称
var age = 100;
console.log(age);//100
//解决办法-->在解构赋值时取一个新的名字  别名
var { age: myAge } = obj
console.log(myAge);//18

//----------数组-------------
var arr = [11, [22, 33], 44]
var [a, [b, c], d] = arr;//一一对应
console.log(a, b, c, d);//11 22 33 44
//交换位置
var arr = [11, 22]
var [a, b] = arr;
[a, b] = [b, a]
console.log(a, b);//22 11

//----------函数-------------
function fn({name, age}) {
    console.log(name, age);//刘亦菲 18
}
fn({ age: 18, name: "刘亦菲" })

11.Class

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

class Person {
    //静态属性
    static Weight = 56;
    //构造器 初始化属性
    //constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法
    constructor(sId, sName, sAge) {
        this.sId = sId;
        this.sName = sName;
        this.sAge = sAge;
    }
    //行为 非静态方法:被实例化才能被调用
    eat() {
        console.log(`${this.sName}天生的吃货`);
    }
    //行为 静态方法:可通过类名调用
    static study() {
        // console.log(this);//是当前类不是当前实例
        return new this;
    }
}
//实例化
var p = new Person(1001, '张小明', 20);//不需要传参时可以不写Person后的括号
console.log(p);//Person {sId: 1001, sName: '张小明', sAge: 20}
p.eat();//张小明天生的吃货
        
Person.study().eat();//undefined天生的吃货
console.log(Person.Weight);//56

12.类的继承

继承:子类拥有父类的属性和方法。
Class之间可以通过extends关键字,实现继承。
使用super关键字,调用父类的方法或属性。

//继承:子类拥有父类的属性和方法
//父类
class Person {
    constructor(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    eat(food) {
        return `我${this.name}最爱吃${food}`
    }
    run(num) {
        return `我${this.name},今年${this.age}岁,第${num}次提桶跑路`
    }
}
//子类
class Programmer extends Person {
    constructor(name, age, sex, hair) {
        super(name, age, sex)
        this.hair = hair;
    }
    //程序员子类独有的行为
    coding() {
        console.log("没日没夜的写代码....");
    }
    //重写父类的方法
    run(num) {
        return `我${this.name},今年${this.age}岁,发量${this.hair},第${num}次提桶跑路`
    }
}
var p = new Programmer("张小明", 22, "男", "堪忧");
console.log(p.eat("肉"));
console.log(p.run(2));
p.coding();
console.log(p);

控制台输出

image.png

13.Symbol

Symbol 是ES6引入的一种新的数据类型,来表示独一无二的值

var s1 = Symbol();//s1是一个独一无二的标记
var s2 = Symbol();//s2是一个独一无二的标记
console.log(s1 == s2);//false
console.log(s1 === s2);//false
console.log(typeof s1);//symbol   类型,值类型

var obj = {
    A: Symbol("帅哥"),//括号里的内容只是对标记的描述
    B: Symbol("帅哥")
}
switch (obj.B) {
    case "帅哥":
        console.log("111");
        break;
    case obj.A:
        console.log("222");
        break;
    case obj.B:
        console.log("333");//333   这句代码被执行
        break;
    default:
        break;
}

var s3 = Symbol.for("aaa")//第一次,就问是否有aaa这个标识,如果没有就创建
var s4 = Symbol.for("aaa")//第二次,就问是否有aaa这个标识,如果有就直接拿来用不用再创建
console.log(s3 == s4);//true
console.log(s3 === s4);//true
//Symbol用法:
// 作为属性名, 防止属性的值被更改
var obj = {};
var n = Symbol();
obj[n] = 'hello';
console.log(obj[n]);; // hello
// Symbol值作为对象属性名时,不能用点运算符
var obj = {};
var n = Symbol();
obj.n = '张三';
obj[n] = '李四';
console.log(obj.n, obj[n]); //张三 李四

JS中各种循环的区别:

  1. for : JS语言诞生就有的循环, 也是使用最多的循环方式, 很多计算机语言都有的循环方式, 可用于遍历数组,字符串;
  2. while : 很多计算机语言也都有的循环方式, 和for循环在使用上的区别是: for循环一般用于已知遍历次数的情况,while一般用在不知道遍历次数的情况;
  3. do-while: 和while有点类似,不过while是先判断后执行循环体,do...while是先会执行一次循环体后再判断;
  4. for-in : 专门用于遍历对象的循环方式 , 也可以遍历数组,但不推荐遍历数组
  5. forEach: ES5新增的遍历方式,支持IE9+, 遍历数组的写法比较简洁,快速, 但是不能中断循环,不能使用break和continue;
  6. for-of : ES6新增的遍历方式, 和for-in用法类似, 但比for-in强大很多, for-of可以遍历数组, 字符串, Set, Map等。