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. 使用严格模式的注意点
- 不可以省略声明变量的关键字(如,var、let、const)
"use strict";
n = 10;
console.log(n);//报错 Uncaught ReferenceError: n is not defined
- 禁止函数使用this关键字指向全局变量
"use strict";
function fn(){
console.log(this);//undefined
}
fn();
- 禁止使用八进制方法
//未使用严格模式
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.
- 不允许在非函数的代码块内声明函数
"use strict";
{
function fn(){
console.log(this);
}
}
fn();//Uncaught ReferenceError: fn is not defined
- 严格模式下,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的指向,后面直接传实参
控制台输出:
3.Array新增
- indexOf():判断数组中是否包含某个元素。
- forEach():用来遍历数组中的每一项;这个方法执行是没有返回值的,对原来数组也没有影响。
- map():和forEach非常相似,都是用来遍历数组中的每一项的,区别是map的回调函数中支持return返回。
- reduce():接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终为一个值,是ES5中新增的一个数组逐项处理方法。
- filter():过滤出数组中你想要的元素,不改变原数组。
- ……
ES6
1.let
作用类似于var,用来声明变量,但是所声明的变量,只在let命令所在的代码块内有效。
- 它如果在{}内部声明的变量,外部不能访问
- 它防止了变量提升,遵循先定义后使用
- 它防止了同一个变量重复被定义
- 它声明的值可以被修改,也可以被修改成任意类型(与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 声明的是常量,一旦声明,值将是不可变的。
- 它的变量名只能声明一次,不能重复声明
- 它防止了变量提升
- 它具备块级作用域
- 它的值不能被修改
如果是引用类型,可以修改它的属性或方法,不能修改类型和地址
3.String新增
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
- repeat():返回一个新字符串,表示将原字符串重复n次。
- ``:字符串模版
4.Array新增
- Array.from():方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。
- Array.of():方法用于将一组值,转换为数组。
- find():通过条件查找,如果存在返回满足条件的这一项,如果不存在就返回undefined。
- findIndex():通过条件查找,如果存在返回满足条件的这一项的下标,如果不存在就返回-1。
- for-of 遍历集合:这是目前遍历数组最简洁和直接的语法;它避免了for-in的所有缺陷;与forEach()不一样,它支持break,continue和return。遍历数组得到的是值,是根据长度遍历。
var arr = [11, 22, 33, , , , 77]
for (var val of arr) {
console.log(val);
}
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);
控制台输出
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中各种循环的区别:
- for : JS语言诞生就有的循环, 也是使用最多的循环方式, 很多计算机语言都有的循环方式, 可用于遍历数组,字符串;
- while : 很多计算机语言也都有的循环方式, 和for循环在使用上的区别是: for循环一般用于已知遍历次数的情况,while一般用在不知道遍历次数的情况;
- do-while: 和while有点类似,不过while是先判断后执行循环体,do...while是先会执行一次循环体后再判断;
- for-in : 专门用于遍历对象的循环方式 , 也可以遍历数组,但不推荐遍历数组
- forEach: ES5新增的遍历方式,支持IE9+, 遍历数组的写法比较简洁,快速, 但是不能中断循环,不能使用break和continue;
- for-of : ES6新增的遍历方式, 和for-in用法类似, 但比for-in强大很多, for-of可以遍历数组, 字符串, Set, Map等。