ES5-ES6

ES5

严格模式

介绍

ES5除了正常的运行模式(又称为混杂模式),还添加了第二种运行模式:“严格模式”(strict mode)。严格模式顾名思义,就是使JavaScript在更严格语法条件下运行。

作用

  1. 消除JavaScript语法的一些不合理,不严谨之处,减少一些怪异行为
  2. 消除代码运行的一些不安全之处,保证代码运行的安全
  3. 为未来新版本的JavaScript做好铺垫

使用

  • 在全局或函数的第一条语句定义为:‘use strict’
  • 如果浏览器不支持,只解析为一条简单的语句,没有任何副作用
// 全局使用严格模式
'use strict';
girl = 'Saber';

// 函数中使用严格模式
function main(){
  'use strict';
  boy = 'Archer';
}
main()

语法和行为改变

  • 必须用 var 声明变量,不允许使用未声明的变量
  • 禁止自定义函数中的 this 指向 window
  • eval 作用域 eval 是一个函数,接收字符串参数,会对字符串进行js语法解析并运行
  • 对象不能有重复的属性
  • 严格模式下 函数不允许有同名的参数
  • 新增一些保留字 private protected implements interface public

Object 扩展方法

Object.create(prototype,[descriptors])

Object.create 方法可以指定对象为原型创建新的对象,同时可以为新的对象设置属性,并对属性进行描述

  • value:指定值
  • writable:标识当前属性是否可修改,默认false
  • configurable:标识当前属性是否可以被删除,默认false
  • enumerable:标识当前属性是否能用for in 枚举,默认false
  • get:当获取当前属性是的回调函数
  • set:当设置当前属性时的回调函数
// 创建一个汽车对象
var car = {
  name: '汽车',
  run: function(){
    console.log('正在行驶!');
  }
};

// 以 car 为原型对象创建新对象 继承
var aodi = Object.create(car, {
  brand: {
    // 设置属性值
    value: '奥迪',
    // 属性值是否可修改
    writable: false,  
    // 属性是否可删除
    configurabel: false,
    // 属性是否可以枚举(被遍历出来)
    enumrable: false
  },
  price: {
    // get 是一个对象的方法,无需手动调用
    get: function(){
      console.log('Price被获取了')
      // 函数的返回结果作为该属性的值
      return 299999;
    },
    // set 设置 可对设置的值进行校验
    set: function(value){
      // this指的是新创建的对象
      this.jiage = value
      console.log(`值被修改为${value}`)
    }
  }
})

以上两种方式只能择其一

Object.defineProperties(object,descriptors)

直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

  • object 要操作的对象
  • descriptors 属性的描述
    • get 作为该属性的getter函数,如果没有戈塔特人则为undefined。函数返回值将被用作属性的值
    • set 作为属性的setter函数,如果没有setter则为undefined。函该将仅接受参数赋值给该属性的新值
// 定义对象
var star = {
  firstName: '刘',
  lastName: '德华'
}

// 添加对象属性
Object.defineProperties(star,{
  fullName: {
    get: function(){
      // this 指向传入的star
      return this.firstName + this.lastName
    }
  }
})

console.log(star.fullName)

call apply 和 bind

  • call 方法使用一个指定的this值和单独给出的一个或多个参数来调用一个函数
  • apply 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数
  • bind 同call相思,不过该方法会返回一个新的函数,而不会立即执行
function main(){
  console.log(this)
}
// 1.直接调用函数
main()                      // window
// 2.创建一个对象
var company = {
  name: 'Saber',
  age: 18
}
// 使用这个对象调用main方法
main.call(company)         // company
main.apply(company)        // company
// bind 修改 this 的值,返回一个新的函数
var fn = main.bind(company)
fn()                       // company

ES6

新特性

let 关键字

let 关键字用来声明变量,使用let声明的变量有几个特点:

  1. 不允许重复声明
  2. 块级作用域
  3. 不存在变量提升
  4. 不影响作用域链

声明变量使用let

const 关键字

const 关键字用来声明常量,const声明有以下特点:

  1. 声明的时候一定要赋初值
  2. 常量的名称一把为【大写】
  3. 不能修改常量的值
  4. 不允许重复声明
  5. 块级作用域
  6. 关于数组对象和元素的修改(引用类型值修改不会报错)

声明对象类型使用const,非对象类型声明使用let

变量的解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为结构赋值

// 数组的结构赋值
const arr = ['Saber','Archer','Rider','Lancer']
let [S,A,R,L] = arr

// 对象的结构赋值
const star = {
  name: '于谦',
  tags: ['抽烟','喝酒','烫头'],
  say: function(){
    console.log('说相声')
  }
}
let {name,tags,say} = star

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:

  1. 字符串中可以出现换行符
  2. 可以使用${variable}形式输出变量
let str = `<ul>
  <li>Saber</li>
  <li>Archer</li>
  <li>Rider</li>
</ul>`
let master = "卫宫士郎"
let say = `你就是我的master吗,${master}`

简化对象写法

let name = 'Saber'
let age = 18
let skill = function(){
  console.log('ex咖喱棒')
}
const servant = {
  name,
  age,
  skill,
  tag(){
    console.log('我是吃货')
  }
}
console.log(servant)

箭头函数

  1. 声明格式
  2. 函数调用
let sum = (a,b,c) => {
  let result = a + b + c
  return result
}
sum()
// sum.call({},1,2,3)
// sum.apply({},[1,2,3])

特点

  1. this 的值是静态的(指向声明时作用域的this)
  2. 不能作为构造函数使用
  3. 不能使用 arguments
  4. 箭头函数简写
  • 不写小括号,当形参有且只有一个
  • 不写大括号,当代吗体只有一条语句且语句的指向结果为函数返回值 return也可以省略
let rand = (m,n) => Math.floor(Math.random() * (n - m + 1)) + m - 1

如果回调与this的值相关的,则不能使用箭头函数
例:事件的回调、对象的方法

参数默认值

ES6 允许给函数参数赋值初始值

  1. 参数直接设置默认值 具有默认值的参数,位置一般靠后
  2. 与结构赋值结合使用 结构赋值的先后顺序不影响
function sum(a,b,c=10){
  console.log(a + b + c)
}

function connect({host = '127.0.0.1',port,pwd,dbname}){
  console.log(host)
  console.log(port)
  console.log(pwd)
  console.log(dbname)
}

connect({
  host: 'localhost',
  port: 8080,
  pwd: 'root',
  dbname: 'project'
})

rest 参数

// arguments
function main(...args){
  //1. 使用arguments获取实参
  console.log(arguments)
  //2. rest参数
  console.log(args)
}
main(1,2,3,5,7)
// 多个参数
function fun(a,b,...args){
  console.log(a)
  console.log(b)
  console.log(args)
}
fun(1,9,9,8,1,1,1,8)

针对于不定参数的函数

spread扩展运算符

  1. 数组的展开
const arr = ['Saber','Archer','Lancer']
function fn(){
  console.log(arguments)
}
fn(...arr) // ...arr => ...['Saber','Archer','Lancer']
//fn('Saber','Archer','Lancer')
  1. 对象的展开
const skillOne = {
  q: '天音波'
}
const skillTwo = {
  w: '金钟罩'
}
const skillThree = {
  e: '天雷破'
}
const skillFour = {
  r: '猛龙摆尾'
}
const LeeSin = {...skillOne,...skillTwo,...skillThree,...skillFour}
console.log(LeeSin)
  1. 应用
// 1.数组合并
const kuaizi = ['肖央','王太利']
const chuanqi = ['曾毅','玲花']
const team = [...kuaizi,...chuanqi]
console.log(team)
// 2.新数组克隆
const arr = ['e','g','m']
const arr2 = [...arr,'x','y','z']
console.log(arr2)
// 3.将伪数组转为真正的数组
const divs = document.querySelectorAll('div')
const result = [...divs]
console.log(result)

Symbol

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型

Symbol特点

  1. Symbol的值是唯一的,用来解决命名冲突的问题
  2. Symbol值不能与其他数据进行运算
  3. Symbol定义的UI对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
// 创建Symbol
let s1 = Symbol()
console.log(s1,typeof s1)

// 添加标识的Symbol
let s2 = Symbol('Saber')
let s3 = Symbol('Saber')
console.log(s2 === s3)//false

// 使用Symbol for定义
let s4 = Symbol.for('1001')
let s5 = Symbol.for('1001')
console.log(s4 === s5)//true

Symbol类型唯一合理的用法是用变量存储Symbol的值,然后使用存储的值创建对象属性

Symbol 创建对象属性

// 向对象中添加方法 up down
const method = {
  up: Symbol(),
  down: Symbol()
}
let str = 'run'
const game = {
  name: '英雄联盟',
  up: function(){
    
  },
  // 内部添加方法
  [str]: function(){
    
  },
  [method.up]: function(){
    console.log('up up up')
  }
}
// 外部添加方法
game[method.down] = function () {
  console.log("down down down")
}
game[method.up]()
game[method.down]()

Symbol 内置值

除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。

Symbol.hasInstance当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开。
Symbol.unscopables该对象指定了使用with关键字时,哪些属性会被with环境排除。
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.species创建衍生对象时,会使用该属性

在特定条件下会执行

迭代器

迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。

  1. ES6创造了一种新的遍历命令for…of循环,iterator接口主要供for…of消费
  2. 原生具备iterator接口的数据(可用for of 遍历)
    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypedArray
    • NodeList
  3. 工作原理
    • 创建一个指针对象,指向当前数据结构的起始位置
    • 第一次调用对象的next方法,指针一直往后移动,直到指向最后一个成员
    • 每调用next方法返回一个包含value和done属性的对象
const servant = ["Saber", "Archer", "Rider", "Lancer"];
for (const item of servant) {
  console.log(item);
}
const iterator = servant[Symbol.iterator]();
console.log(iterator);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

const team = {
  name: "TES",
  members: ["369", "knight", "karsa", "jacklove", "yuyanjia"],
  //添加 Symbol.iterator
  [Symbol.iterator]: function () {
    let index = 0;
    return {
      next: () => {
        //声明对象
        const result = {
          value: this.members[index],
          done: false,
        };
        //判断下标 修改 『done』属性的值
        if (index === this.members.length) {
          result.done = true;
        }
        // 下标自增
        index++;
        // 返回结果
        return result;
      },
    };
  },
};
for (const item of team) {
  console.log(item);
}

需要自定义遍历数据的时候,要想到迭代器

Promise

Promise 是 ES6引入的异步编程的新解决方案。语法上Promise是一个构造函数, 用来封装异步操作并可以获取其成功或失败的结果。

Set

ES6提供了新的数据结构Set(集合)。它类似于数组,『但成员的值都是唯一的』,集合实现了iterator接口,所以可以使用『扩展运算符』和『for…of』进行遍历集合的属性和方法:

  1. size 返回集合的元素个数
  2. add 增加一个新元素,返回当前集合
  3. delete删除元素,返回boolean值
  4. has 检测集合中是否包含某个元素,返回boolean值
  5. clear 清空集合中,返回undefined
// 创建一个空集合
const s = new Set()
// 创建一个非空集合
const s2 = new Set([1,5,9,13,17])

// 1.元素个数
console.log(s2.size)
// 2.添加
s2.add(21)
// 3.删除
s2.delete(5)
// 4.检测集合中是否包含某个元素
console.log(s2.has(9))
// 5.清空
s2.clear()

for( const item of s2){
  console.log(item)
}
//  1.数组去重
const arr = [
  "大事儿",
  "小事儿",
  "心里事儿",
  "坏事儿",
  "小事儿",
  "好事儿",
  "坏事儿",
];
const s = new Set(arr);
const result = [...s];
console.log(result);

// 2.交集
const arr1 = [1, 3, 5, 1, 2, 4, 5];
const arr2 = [3, 3, 4, 6, 5, 2, 4, 4, 1];

const result2 = [...new Set(arr1)].filter((item) => {
  return (new Set(arr2)).has(item);
});
console.log(result2);

// 并集
const result3 = [...new Set([...new Set(arr1), ...new Set(arr2)])];
console.log(result3);

// 差集
const result4 = [...new Set(arr2)].filter((item) => {
  return !(new Set(arr1)).has(item);
});
console.log(result4);

Map

ES6提供了Map数据结构。它类似于对象,也是键值对的集合。但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了iterator接口,所以可以使用扩展运算符for...of进行遍历Map的属性和方法

// 声明 Map
const m = new Map();
// 添加元素
const team = {
  name: "Tes",
  members: ["369", "knight", "jacklove"],
};
m.set("servant", "Saber");
m.set(team, "LPL");
// 获取元素
console.log(m.get("servant"));
console.log(m.get(team));
// 删除元素
m.delete('servant')
// 检测
console.log(m.has(team));
// 元素个数
console.log(m.size);
// 清空
m.clear()

...可以展开实现了iterator接口的数据

class 类

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作指示一个语法糖,他的绝大部分功能,ES5都可以做到,新的class写法只是让对象的原型的写法更加清晰、更像面向对象编程的语法而已

知识点

对象声明

// ES5
// 创建对象的方式 new Object{} 工厂函数 构造函数 Object.create
function Phone(brand,price){
  this.brand = brand
  this.price = price
}

// 添加方法
Phone.prototype.call = function(someone){
  console.log(`给${someone}打电话`);
}
Phone.prototype.sendMessage = function(someone){
  console.log(`给${someone}发短信`);
}

// 实例化对象
const nokia = new Phone('诺基亚',224)
// ES6
// 语法
class Phone{
  // 构造方法
  constructor(brand,price){
    this.brand = brand
    this.price =price
  }
  // 方法
  call(someone){
    console.log(`给${someone}打电话`);
  }
  sendMessage(someone){
    console.log(`给${someone}发短信`);
  }
}
const iphone = new Phone('苹果',10000)
  1. 构造方法不是必须的
  2. 构造方法只能有一个

静态成员

// ES5
function Phone(brand){
  // 为实例对象添加属性
  this.brand = brand
}
// 为函数对象添加属性
Phone.name = '手机' // 又称之为静态成员
Phone.change = function(){
  console.log("change the world");
}
const nokia = new Phone('诺基亚')
console.log(nokia);
console.dir(Phone)
// ES6
class Phone {
  static name = "手机";
  static change() {
    console.log("change the world");
  }
}

console.log(Phone.name);
Phone.change();

静态成员属于类而不属于实例对象

对象继承

// ES5
// 父类
function Phone(brand,price){
  this.brand= brand
  this.price = price
}
Phone.prototype.call = function(someone){
  console.log(`给${someone}打电话`);
}
Phone.prototype.sendMessage = function(someone){
  console.log(`给${someone}发短信`);
}
// 子类
function SmartPhone(brand,price,storage,soc){
  // 调用父类函数 属性的初始化
  Phone.call(this,brand,price)
  // 初始化
  this.storage = storage
  this.soc = soc
}
SmartPhone.prototype = new Phone
SmartPhone.prototype.constructor = SmartPhone
// 添加
SmartPhone.prototype.playGame = function(){
  console.log('我亚索贼6');
}
SmartPhone.prototype.takePhone = function(){
  console.log('10亿像素,照亮你的丑');
}
const mate40 = new SmartPhone('华为',6999,'256g','Kirin')
console.log(mate40);
mate40.playGame()
mate40.takePhone()
// ES6
class Phone {
  // 构造方法
  constructor(brand, price) {
    this.brand = brand;
    this.price = price;
  }
  // 方法
  call(someone) {
    console.log(`给${someone}打电话`);
  }
  sendMessage(someone) {
    console.log(`给${someone}发短信`);
  }
}
class SmartPhone extends Phone {
  // 构造方法
  constructor(brand, price, storage, soc) {
    // 调用父类的构造方法 属性初始化
    super(brand, price);
    this.storage = storage;
    this.soc = soc;
  }
  // 子类对象方法
  playGame() {
    console.log("我亚索贼6");
  }
  takePhone() {
    console.log("10亿像素,照亮你的丑");
  }
}
const onePlus = new SmartPhone('一加','3999','128g','Snapdragon888')
onePlus.playGame()
onePlus.sendMessage('马斯克')
onePlus.takePhone()

get 和 set

class Phone{
 get price(){
   return 2999
 }
 set price(value){
   this.jiage = value
 }
 static get size(){
   return '6.6inch'
 }
 static set size(value){
   this.chicun = value
 }
}
const iphone = new Phone()
// 属性获取
console.log(iphone.price);
// 属性设置
iphone.price = 6999
// 属性获取
const res = Phone.size
console.log(res);
// 静态属性的设置
Phone.size = '7.7inch'
console.dir(Phone)

数值扩展

 // Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(10)); // false
console.log(Number.isFinite(Math.PI)); // false
console.log(Number.isFinite(1/0)); // true

// Number.isNaN 检测一个数值是否为 NaN isNaN
console.log(Number.isNaN(NaN));// true

// Number.parseInt 字符串转整数
console.log(Number.parseInt('1024奥利给'));// 1024
console.log(Number('1024奥利给')); // NaN

// Math.trunc 将小数部分抹除
console.log(Math.trunc(Math.PI));// 3

// Number.isInteger 判断一个数是否为整数 is 是否 integer 整型
console.log(Number.isInteger(3.14));// false
console.log(Number.isInteger(3));// true

// 幂运算 (ES7) Math.pow()
console.log(2 ** 10);// 1024

对象扩展

// 判断两个值是否完全相等 === Object.is
let n = 100
let n2 = 200
console.log(Object.is(n,n2)); // false
console.log(Object.is(NaN,NaN)); // true
console.log(NaN === NaN); // false

// Object.assign 对象的合并
// 同名属性会覆盖,会合并到第一个对象并返回
const A = {
  name: '简自豪'
}

const B= {
  team: ['SHR','OMG','QG','RNG'],
  name: 'Uzi'
}

const C = {
  name: '小狗'
}
const res = Object.assign(A,B,C)
console.log(res === A);// true
console.log(A);

// 直接修改 __proto__ 设置原型
const D = {
  name: '父级'
}
const E = {
  test: '测试'
}
E.__proto__ = D
console.log(E);

浅拷贝

console.log('-----------1.直接复制-----------');
const arr = [1,2,3,4]
const newArr = arr
newArr[0] = 5
console.log(arr);
console.log(newArr);

console.log('-----------2.数组-----------');
const arr = [{name:'Saber'},2,3,4]
// 1.concat
const newArr = [].concat(arr)
newArr[0].name = '阿尔托莉雅·潘德拉贡'
console.log(arr);
console.log(newArr);

const arr = [{name:'Saber'},2,3,4]
// 2.slice
const newArr = arr.slice(0)
newArr[0].name = '阿尔托莉雅·潘德拉贡'
console.log(arr);
console.log(newArr);

const arr = [{name:'Saber'},2,3,4]
// 3.扩展运算符
const newArr = [...arr]
newArr[0].name = '阿尔托莉雅·潘德拉贡'
console.log(arr);
console.log(newArr);

// 使用assign方法创建对象(assign对象的合并)
const company = {
  name: 'Tencent',
  position: ['北京','上海','深圳']
}
const newCompany = Object.assign({},company)
newCompany.position[0] = 'beijing'

console.log(company);
console.log(newCompany);

深拷贝

JSON实现深拷贝

// JSON 实现深拷贝
// stringify 将JS对象转为JSON格式的字符串
// parse 将JSON格式的字符串转化为JS对象
// 缺陷:不能复制方法
const company = {
  name: "Tencent",
  position: ["北京", "上海", "深圳"],
  leader: {
    name: "小马哥",
  },
  copy: function(){
    console.log('与复制了上千种忍术的我为敌,你毫无胜算')
  }
};
// 将对象转为JSON格式字符串
let str = JSON.stringify(company)
// 将对象转为JS对象
let newCompany = JSON.parse(str)

newCompany.position[0] = 'beijing'
console.log(company);
console.log(newCompany);

递归实现深拷贝

// 封装一个函数
function deepClone(data) {
  // 创建一个容器
  let container;
  // 判断
  let type = getDataType(data);
  if (type === "Object") {
    container = {};
  }
  if (type === "Array") {
    container = [];
  }
  // 遍历数据 for in
  for (const i in data) {
    let type = getDataType(data[i]);
    if (type === "Object" || type === "Array") {
      container[i] = deepClone(data[i]);
    } else {
      container[i] = data[i];
    }
  }
  return container;
}
// 待克隆数据
const company = {
  name: "Tencent",
  position: ["北京", "上海", "深圳"],
  leader: {
    name: "小马哥",
  },
  copy: function () {
    console.log("与复制了上千种忍术的我为敌,你毫无胜算");
  },
};
// 调用函数完成深拷贝
const newCompany = deepClone(company);
newCompany.position[0] = "beijing";
console.log(company);
console.log(newCompany);
// 封装一个函数 用来获取数据类型
function getDataType(data) {
  return Object.prototype.toString.call(data).slice(8, -1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值