Javascript

Js高级-ES6

本文主要是介绍Js高级-ES6,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一.let
作用:同var一样用来声明变量
特点
在块级作用域内有效
不能重复声明
变量提升
全局变量提升:会创建一个变量对象(script)用来收集全局作用域下let定义的变量
局部变量提升:会将var let定义的变量全部放到当前函数的变量对象中
同var的变量提升的区别:let提升的变量在为赋值之前不允许被使用
应用
循环遍历加监听
使用let取代var是趋势

二.const关键字
作用:定义一个常量
特点:不能修改,其他特点同let
应用:保存不用改变的数据

三.解构赋值
理解:从对象或数组中提取数据,并赋值给变量(多个)
对象的解构赋值
let {n,a} = {n:“tom” , a:12}
数组的解构赋值
let {a ,b} = {1 ,2}
用途:给多个形参赋值

四.模板字符串
作用:简化字符串的拼接
写法:模板字符串必须使用`` 包含,变化部分用 ${xxxx}定义

  let obj = {username: 'kobe', age: 43};
  let str = '我的名字是: ' + obj.username + ', 我的年龄是: ' + obj.age;
  console.log(str);
  console.log('---------------模板字符串拼接--------------------');
  let str1 = `我的名字是 ${obj.username}, 我的年龄是 ${obj.age}`
  console.log(str1);

五.对象的简写方式
同名属性可以省略–>key和value一样的时候
省略函数的function,冒号

   let username = 'kobe';
   let age = 43;
   console.log('---------------- 对象的常规书写方式---------------------');
 
   let obj = {
     username: username,
     age: age,
     showName: function () {
       console.log(this.username);
    }
 }
   console.log(obj);
   obj.showName();
 
   console.log('---------------- 对象的简写方式---------------------');
   let obj = {
     username,  // 同名的属性可省略 ---> key 和value一样的时候
     age,
     showName() { // 省略函数的function,冒号
       console.log(this.username);
    }
  }
 
   console.log(obj);
   obj.showName();

六.箭头函数
语法:

let fun = 形参 => 函数体

重点:函数体

只有一条语句或者表达式的时候,{ }可以省略
当多条语句时候,{ }不能省略
当{ }省略的时候,会自动return当前语句或者表达式的执行结果

特点:

this: 箭头函数没有自己this,不是调用的时候决定的,而是定义的时候决定的

理解:

定义的时候看外部是否有函数,如果没有函数,this指向window
如果有外部函数,this同外部函数的this指向是同一个对象
箭头函数不能用作构造函数

  console.log('------------- 箭头函数 - 没有形参  -----------------');
  // 当箭头函数没有形参的时候 () 不能省略
  let fun = () => console.log('fun()');
  fun();
 
  console.log('------------- 箭头函数 - 有一个形参  -----------------');
  // 当箭头函数只有一个形参的时候,() 可以省略,也可以不省略
  let fun1 = a => console.log('只有一个形参的时候', a);
  fun1(123);
 
  console.log('------------- 箭头函数 - 有多个形参  -----------------');
  // 当箭头函数有多个形参的时候, ()不能省略
  let fun2 = (a, b) => console.log('有多个形参的时候', a, b);
  fun2(1,2);
 
 
  console.log('------------- 箭头函数 - 函数体只有一条语句的时候  -----------------');
  // 当箭头函数的函数体只有一条语句的时候{}可以省略, 当{}省略的时候会自动 return 当前语句或者表达式的结果, 当{}不省略的时候,需要手动指定返回的结果, 否则默认执行 return value: undefined;
  let fun3 = () => console.log('函数体只有一条语句的时候'); 
  console.log(fun3());// 语句的返回结果,undefined
  let fun3 = () => 123 
  console.log(fun3());//表达式的返回结果,123
 
  console.log('------------- 箭头函数 - 函数体有多条语句的时候  -----------------');
  // 当箭头函数的函数体有多条语句的时候,{}不能省略, 当{}不省略的时候,需要手动指定返回的结果, 否则默认执行 return value: undefined;
  let fun4 = () => {
    let a = 1;
    console.log('函数体有多条语句的时候', a);
    // return a;-->1
  }
   
  console.log(fun4());//undefined

七.点点点运算符
1 …运算符去拆包指定的数组

  //把arr2数组插入到arr里面1和6中间
  let arr = [1, 6];
  let arr2 = [2,3,4,5];
   
  let arr3 = [1, ...arr2, 6];
  console.log(arr3); // [1, 2, 3, 4, 5, 6]

2 …运算符去拆包不能直接去遍历对象

  let obj2 = {name: 'kobe', age: 43};
  console.log(...obj2);//报错

八.Symbol
前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
概念:ES6中的添加了一种原始数据类型symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象)
特点:

1、Symbol属性对应的值是唯一的,解决命名冲突问题
2、Symbol值不能与其他数据进行计算,包括同字符串拼串
3、for in, for of遍历时不会遍历symbol属性

使用:
1、调用Symbol函数得到symbol值

 let symbol = Symbol();
      let obj = {};
      obj[symbol] = 'hello';

2、传参标识

  let symbol = Symbol('one');
      let symbol2 = Symbol('two');
      console.log(symbol);// Symbol('one')
      console.log(symbol2);// Symbol('two')

3、内置Symbol值
* 除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
- Symbol.iterator
* 对象的Symbol.iterator属性,指向该对象的默认遍历器方法

九.Iterator遍历器(迭代器)
概念: iterator 是一种接口机制,为各种不同的数据结构提供统一的访问机制
作用:
1、为各种数据结构,提供一个统一的、简便的访问接口;
2、使得数据结构的成员能够按某种次序排列
3、ES6创造了一种新的遍历命令 for…of循环,Iterator接口主要供for…of消费。
工作原理:
- 创建一个指针对象(遍历器对象),指向数据结构的起始位置。
- 第一次调用next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
- 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
* value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
* 当遍历结束的时候返回的value值是undefined,done值为false
原生具备iterator接口的数据(可用for of遍历)
1、Array
2、arguments
3、set容器
4、map容器
5、String

 let arr = [2,3,4,5];
     console.log(arr);
 for(let item of arr){
     console.log(item);
}
 //for of 遍历实现原理,调用了数组Array里面的Symbol.iterator 接口
 function iteratorUtil(target) { 
   let index = 0; //  标识指针的起始位置
     return { // 生成iterator遍历器对象
        next: function () {
           return index < target.length?{value: target[index++], done: false}:{value: target[index++], done: true}
    }
  }
}
 
 let iteratorObj = iteratorUtil(arr); // 生成iterator遍历器对象
 console.log(iteratorObj.next());//{value:2 , done:false }
 console.log(iteratorObj.next());//{value:3 , done:false }
 console.log(iteratorObj.next());//{value:4 , done:false }
 console.log(iteratorObj.next());//{value:5 , done:false }
 console.log(iteratorObj.next());//{value:undefeined , done:true }

Iterator接口实现底层原理,修改底层源码,拿来给自己用

 function iteratorUtil( ) {
    console.log('我的方法被调用了', this); // this是遍历的目标数组
   
    // 缓存this
    let that = this;
    let index = 0; //  标识指针的起始位置
    let keys = Object.keys(that);// 获取对象中所有key的数组
    if(this instanceof Array){ // 遍历数组
      return { // 生成iterator遍历器对象
        next:  function (){ // 可以使用缓存this解决this的指向问题,也可以使用箭头函数解决this的指向问题
          return index < that.length?{value: that[index++], done: false}:{value: that[index++], done: true}
        }
      }
    }else {// 遍历对象
      return { // 生成iterator遍历器对象
        next:  function (){ 
          return index < keys.length?{value: that[keys[index++]], done: false}:{value: that[keys[index++]], done: true}
        }
      }
    }
  }
 
  Array.prototype[Symbol.iterator] = iteratorUtil;
  Object.prototype[Symbol.iterator] = iteratorUtil;
  
  let arr = [2,3,4,5];
  for(let item of arr){
    console.log(item);
  }
   
  // for of 消费 iterator接口
  // 三点运算符消费 iterator接口
  console.log(...arr);
   
  let obj = {
    username: 'kobe',
    age: 43
  }
  for(let item of obj){
    console.log(item);
  }
   // console.log(Object.keys(obj));输出--> (2) ["username", "age"]

十.class类详解
class类的理解
1.关键字
2.class类本质上是function
3.和函数表达式和函数声明式一样,class类也具:有类的表达式和类声明
4.类和模块的内部,默认就是严格模式,所以不需要使用 use strict 指定运行模式

类的声明:即class关键字后面跟一个类名

 class Person {
	constructor(name, age) {
    this.name = name
    this.age = age
  }
}

1.类声明不会被提升,需要先进行声明,再去访问,否则会报错,而函数声明则会提升

 var person= new Person()
 class Person {
	constructor(name, age) {
    this.name = name
    this.age = age
  }
}
//报错:Person is not defined

2.不可重复声明

 class Person {}
 class Person {}
// 报错: Identifier 'Person' has already been declared

3.必须使用 new 调用,否则会报错,而普通构造函数不用 new 也可以执行

 class Person {
	constructor(name, age) {
    this.name = name
    this.age = age
  }
}
Person()
// 报错: Class constructor Person cannot be invoked without 'new'

类表达式:可以为匿名或命名

//匿名类
 let Person = class {
   constructor(name, age) {
    this.name = name
    this.age = age
  }
}

//命名的类 
 let Person = class Person {
   constructor(name, age) {
    this.name = name
    this.age = age
  }
}

类的方法
1.constructor 方法:类的默认方法,通过 new 命令生成对象实例时,自动调用该方法(默认返回实例对象 this)

class Person {
   constructor(name, age) {
    this.name = name    // 默认返回实例对象 this
    this.age = age
  }
  toString() {
    console.log(this.name + ', ' + this.age)
  }
}

注意:
1.在类中声明方法的时候,方法前不加 function 关键字
2.方法间不能加分号,否则会报错
3.一个类中有且只有一个 constructor 方法

2.static静态方法:1.使用static可以给 类对象 自身添加属性,2.通过类名调用,不能通过实例对象调用,否则会报错

class Person {
    static sum(x , y) {
        console.log(x + y)
    }
}
var p = new Person()
Person.sum(1, 2)  // 3
p.sum(1,2)     //报错: p.sum is not a function

3.原型方法:1.类的所有方法都定义在类的 prototype 属性上面,在类的实例上面调用方法,其实就是调用原型上的方法,2.原型方法可以通过实例对象调用,但不能通过类名调用,会报错

class Person {
	constructor( ) {// 默认返回实例对象 this
		
	}
    sum( ) {
    	
    }
    toString( ) {
    	console.log(123)
  	}
}
// 给 Person 的原型添加方法
Person.prototype.showName = function() {
	console.log('My name is kobe')
}

// 等同于
Person.prototype = {
  constructor( ) {},
  sum( ) {},
  toString( ) {}
}

var p = new Person()
p.toString( )       // 123
p.toVal( )          // My name is kobe
Person.toString( )  //报错: Person.toStringis not a function
Person.toVal( )  //报错: Person.toVal is not a function

4.实例方法:通过实例对象调用,但同样不能通过类名调用,会报错

class Person {
    constructor() {
        this.sum = function(x, y) {
            console.log(x + y)
        }
    }
}
var p = new Person()
p.sum(1,2)       // 3
Person.sum(1,2)  //报错: Person.sum is not a function

class类的继承

class Person {
    // 静态资源修饰符,使用static可以给 类对象 自身添加属性
    static num = 123;
    // 类的构造方法
    constructor(name, age){
      console.log('--- constructor() ---');
      this.name = name;
      this.age = age;
    }
    // 类的一般方法
    showInfo(){ // userInfo
      console.log(this.name, this.age);
    }
  }
 
  console.log('--------------- 实现类的继承: extends -----------------');
  // 定义一个 子类
  // 回顾原型继承: 子类的原型 成为 父类的实例
  // 子类的构造函数.prototype = new 父类的构造函数()
  class Child extends Person { // 子类的原型 成为 父类的实例
    constructor(name, age, sex) {
      // super做的事情: 1. 调用父类的构造方法,2. 改变父类构造方法的this指向为子类的实例
      super(name, age); // super调用父类的构造方法
      this.sex = sex;
    }
    //  父类的方法重写:当父类原型的方法不能满足子类实例需求的时候
    showInfo(){
      console.log(this.name, this.age, this.sex);
    }
  }
 
 
  let child1 = new Child('xiaoming', 18, '男');
  console.log(child1);
  child1.showInfo();
 
 
 
  console.log('--------------- 回顾之前的继承方式 -----------------');
  function Person1(name, age) {
    this.name = name;
    this.age = age;
  }
 
  Person1.prototype.showInfo = function(){
    console.log(this.name, this.age);
  }
 
  let person2 = new Person1('kobe', 43);
 
  console.log(person2);
  person2.showInfo();
 
  // 子类的原型     成为 父类的实例
  Child1.prototype = new Person1();
  Child1.prototype.constructor = Child1;
  function Child1(name, age, sex) {
    // this.name = name;
    // this.age = age;
    Person1.call(this, name, age); // 借用构造函数继承
    this.sex = sex;
  }
 
  let child2 = new Child1('xiaoming', 18, '男');
  console.log(child2);
  child2.showInfo();

ES6其他新增加属性?

十一:Set和Map数据结构
1.Set理解:
Set的存储结构与数组类似,Set中不允许 存放重复数据,而且没有下标,即无序不可重复的多个value的集合体
声明一个重复的数组,中有重复的数据

var arr = [111,444,333,111,222,333,444]

使用Set

var newArr = new Set(arr);//Set(4){111,444,333,222}

将结果变为数组,使用展开运算符

var arr1 = [...newArr]//(4){111,444,333,222}

Set方法:
1.添加元素–>add(value)

let a = new Set( )
a.add(8)//Set(1){8}

2.删除方法–>delete(value)

let a = new Set( )
v.add(8)
v.add(6)
v.delete(8)//Set(1){6}

3.判断 Set 中是否包含某个元素–>has(value)

let a = new Set()
a.add(8)
a.add(6)
a.has(8)//true

4.clear()

let a = new Set([1,2,3,4,5])
a.clear( )

5.获取 Set 中元素个数–>size

let a = new Set( )
a.add(8)
a.add(6)

6.遍历Set
for of 形式

let a = new Set([1,2,3,3,4,5])
			
for(let item of a) {
    console.log(item)
}//1,2,3,4,5

十二.数组的去重
ES5数组去重:indexOf

let arr = [1,2,3,4,5,1,2,3,4];
  console.log(arr.indexOf(9)); // -1
  function uniqArr(arr) {
    let result = [];
    arr.forEach(function (item, index) {
      // 判断新的数组中是否包含原数组中的元素
      if(result.indexOf(item) === -1){
        result.push(item);
      }
    })
     
    return result;
  }
  console.log(uniqArr(arr));

ES6数组去重: set容器

let arr = [1,2,3,4,5,1,2,3,4];
  function uniqArr2(arr) {
    let set = new Set(arr);
     console.log(set);
    let result = [];
    for(let item of set){
     result.push(item);
    }
 
    return result;
  }

代码优化

let arr = [1,2,3,4,5,1,2,3,4];
 let uniqArr2 = arr => [...new Set(arr)];
  console.log(uniqArr2(arr));

十三.检查数据类型通用方法

function checkoutType(target){
  return Object.prototype.toString.call(target).slice(8,-1);
}

十四.深度克隆_复制数据
- 基本数据类型存放的就是实际的数据,可直接复制
let number2 = 2;
let number1 = number2;
- 克隆数据:对象/数组
1、区别: 浅拷贝/深度拷贝
判断深拷贝还是浅拷贝:修改拷贝之后的数据会不会影响原数据,如果没有影响则是深拷贝
知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
let obj = {username: ‘kobe’}
let obj1 = obj; // obj1 复制了obj在栈内存的引用
2、常用的拷贝技术
1). arr.concat(): 数组浅拷贝
2). arr.slice(): 数组浅拷贝
3). JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 缺陷是不能处理函数数据
4). 浅拷贝包含函数数据的对象/数组
5). 深拷贝包含函数数据的对象/数组

3、手写一个深拷贝

   function checkoutType(target) {
    return Object.prototype.toString.call(target).slice(8, -1);
  }
  function clone(target) {
    let result; // 最终加工拷贝完的数据
    // 判断拷贝的数据是对象 || 数组 || 其他(基本数据类型,函数), 检测数据类型
    let targetType = checkoutType(target);
    if(targetType === 'Array'){
      result = [ ];
    }else if(targetType === 'Object'){
      result = { };
    }else {
      return target;
    }
    // 拷贝
    // arr = [1,2,3] ====> []arr2
    // obj = {username: 'kobe'} ===> {}obj2
    for(let item in target){
      // item: 对象(key), 数组(index)
      // target[item] 可以获取对应的value
      let value = target[item];
      // arr2[item] = arr[item]
      // 判断是否是引用数据类型,因为Array或者Object里面可能还会包含Array,Object
      if(checkoutType(value) === 'Object' || 'Array'){
        result[item] = clone(value);
      }else {
        result[item] = value;
      }
    }
    return result;
  }
   
   
  let obj = {username: 'kobe', age: 43, sex: ['男', '女']};
  let obj2 = clone(obj);
  console.log(obj, obj2);
  obj.username = 'wade';
  console.log(obj, obj2);
   
   
  obj2.sex[0] = '混合';
  console.log(obj, obj2);
这篇关于Js高级-ES6的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!