zoukankan      html  css  js  c++  java
  • 看完我的笔记不懂也会懂----ECMAscript 567

    ECMAscript 567

    严格模式

    如何开启严格模式?

    function strictMode(){
        'use strict'
        //something
    }
    

    开启严格模式的特性:

    1. 必须用var关键字声明变量
      'use strict'
      name = 'Fitz'
      console.log(name)   //报错 nams is not defined
      
    2. 自定义函数中的this不能指向window
      'use strict'
      function Test(){
          this.name = 'Fitz'
      }
      
      Test(); //此时直接执行函数相当于  window.name = 'Fitz'
      // 但是在严格模式下自定义函数this不能指向window  所以  报错
      
    3. eval()中的代码有独立作用域
      'use strict'
      var i=666
      eval('var i=3; console.log(i)')   //i=3
      console.log(i)    //i=666
      
    4. 对象中的属性名不能出现相同
      'use strict'
      obj = {
          name: 'dd',
          name: 'cc'
      }   //报错
      
    5. 全局对象是undefined
      非严格模式中 ==>  window
      严格模式    ==>  undefined
      

    字符串扩展

    1. str.includes(str): 判断是否包含指定的字符串

      let str = 'this is a string'
      console.log(str.includes('is'))        //true
      console.log(str.includes(' '))         //true        
      console.log(str.includes('das'))       //false      
      console.log(str.includes('a s'))       //true
      
    2. str.startsWith(str): 判断是否以指定字符串开头

      let str = 'this is a string'
      console.log(str.startsWith('t'))       //true        
      console.log(str.startsWith('a'))       //false   
      
    3. str.endsWith(str): 判断是否以指定字符串结尾

      let str = 'this is a string'
      console.log(str.endsWith('g'))         //true 
      console.log(str.endsWith('h'))         //false
      
    4. str.repeat(count): 重复指定次数

      let str = 'this is a string'
      console.log(str.repeat(2))             //this is a stringthis is a string 
      

    数值的扩展

    1. Number.isFinite(i): 判断是否是有限大的数

      let num = 666
      let num2 = 666.0
      let num3 = 3.1415926535
      
      console.log(Number.isFinite(num))   //true
      console.log(Number.isFinite(Infinity))//false
      
    2. Number.isNaN(i): 判断是否是判断是否是NaN

      let num = 666
      let num2 = 666.0
      let num3 = 3.1415926535
      
      console.log(Number.isNaN(num))      //false
      console.log(Number.isNaN(NaN))      //true
      
    3. Number.isInteger(i): 判断是否是整数

      let num = 666
      let num2 = 666.0
      let num3 = 3.1415926535
      
      console.log(Number.isInteger(num))  //true
      console.log(Number.isInteger(num2)) //true
      
    4. Number.parseInt(i): 将字符串转换为对应数值

      let num = 666
      let num2 = 666.0
      let num3 = 3.1415926535
      console.log(Number.parseInt(num2))  //666
      console.log(Number.parseInt(num3))  //3
      
    5. Number.trunc(i): 直接去除小数部分

      let num = 666
      let num2 = 666.0
      let num3 = 3.1415926535
      console.log(Math.trunc(num2))       //666
      console.log(Math.trunc(num3))       //3
      

    Object对象方法扩展

    1. Object.create(prototype,[descriptors])

      1. 作用:
        1. 以指定对象为原型创建新的对象
        2. 为新对象指定新属性,并对属性执行描述

      2. 常用的属性

        1. value: 自定义属性值
        2. writable:标识描述属性是否能修改,默认为false
        3. configurable: 标识当前属性是否可以被删除,默认为false
        4. enumerable: 标识当前属性能够使用for in 枚举, 默认为false
      var obj = {
                  username: 'dd',
                  age: 30
              }
      
      var obj1 = Object.create(obj,{
              att1: {
                  value: '我是att1的属性值',
                  writable: true,
                  enumerable: true,
                  configurable: true
              },
              password: {
                  value: '666',
                  writable: true,
                  enumerable: true,
                  configurable: true
              }
          })
      
    2. Object.defineProperties(object,[descriptors])

      //扩展原型属性
      var obj3 = {
          name: 'Lx',
          age: 20
      }
      Object.defineProperties(obj3,{
          //info属于扩展属性
          //this --->  obj3
          info: {
              //当扩展属性改变时,自动调用该方法(obj.info = xx)
              set: function(data){
                  console.log('data -->' + data)
                  var splitData = data.split(' ')
                  this.name = splitData[0]
                  this.age = splitData[1]
              },
      
              //获取扩展属性的值,自动调用该方法  (obj.info)
              get: function(){
                  return this.name + '->' + this.age
              }
          }
          //扩展属性的set与get本质上调用的是
          //set propertyName()
          //get propertyName()
      })
      
      console.log(obj3.info); //Lx->20
      obj3.info = 'ddd 99'    //data -->ddd 99
      console.log('change success --> ' + obj3.info)  //change success -->ddd->99
      
      var obj4 = {
          name: 'sun',
          age: 999,
          get personInfo(){
              console.log('get()')
              return 'name is -> ' + this.name + 'age is -> ' + this.age
          },
          set personInfo(info){
              console.log('set()')
              var spliter = info.split(' ')
              this.name = spliter[0]
              this.age = spliter[1]
          }
      }
      
      console.log(obj4.personInfo);   //get()    name is -> sunage is -> 999
      obj4.personInfo = 'Liu 13'  //set()
      console.log(obj4.personInfo);   //get()    name is -> Liu age is -> 13
      
    3. Object.is(v1,v2) 判断两个数据是否完全相等

      1. 原理是先转换成字符串再判断两者是否相等
      console.log(0 === -0)           //true
      console.log(NaN === NaN)        //false
      console.log(Object.is(0,-0))    //false
      console.log(Object.is(NaN,NaN)) //true
      
    4. Object.assign(target,source1,source2..) 将原对象的属性复制到目标对象上

      let myObj = {}
      let myObj2 = {name: '我会被复制到另一个对象中'}
      let myObj3 = {age: 999}
      let myObj4 = {gender: 'male'}
      Object.assign(myObj,myObj2,myObj3,myObj4)
      console.log(myObj)  //{name: "我会被复制到另一个对象中", age: 999,gender: "male"}
      
    5. 直接操作__proto__属性

      //直接操作 __proto__
      let myObj5 = {}
      let myObj6 = {dream: 'rich'}
      myObj5.__proto__ = myObj6
      console.log(myObj5)
      console.log(myObj5.dream)   //rich
      

    数组的扩展

    1. map(function(item,index)}{})
      遍历数组返回一个新数组,数组中的值是在加工后的

      var arr = [1,3,4,5,67,12,4]
      var newArr = arr.map(function(item,index){
          return item ** 2
      })
      console.log(newArr)  //[1, 9, 16, 25, 4489, 144, 16]
      console.log(arr)    //不会改变元素组
      
    2. filter(function(item,index)}{})
      遍历数组返回一个新数组,数组中的值是在条件为true的

      var arr = [1,3,4,5,67,12,4]
      var newArr2 = arr.filter(function(item,index){
              return index > 2    //过滤条件
          })
          console.log(newArr2)  //[5,67,12,4] 值为: 过滤条件 === true
          console.log(arr)    //不会改变元素组
      

    数组方法的扩展

    1. Array.from(v) 将伪数组对象或可遍历对象转换为真数组

      //定义一个伪数组
      let fakeArr = {
          0: 'first!',
          1: 'hello',
          2: '3',
          length: 3
      }
      
      Array.from(fakeArr).forEach((item,index) => {
          console.log(`item ==> ${item}  index ==> ${index}`);
      })
      
      //伪数组不能直接调用真数组的方法
      /* Array.forEach((item,index) => {
          console.log(`item ==> ${item}  index ==> ${index}`);
      }) */
      
    2. Array.of(v1,v2,v3) 将一系列值转换为数组

      let result = Array.of(1,false,'da')
      console.log(result)     //[1, false, "da"]
      
    3. find(function(value,index,arr){return true}) 找出第一个且只有一个满足条件返回true的元素

      let arr = [1,3,5,6,7,19]
      let result = arr.find(function(item,index){
          //只会返回第一个且只有一个满足条件的元素
          return item > 4
      })
      console.log(result) //5
      
    4. findeIndex(function(value,index,arr){return true}) 找出第一个且只有一个满足条件返回true的元素下标

      let arr = [1,3,5,6,7,19]
      let result = arr.findIndex(function(item,index){
          //只会返回第一个且只有一个满足条件的元素的下标
          return item > 4
      })
      console.log(result) //2
      

    bind、call、apply用法详解

    bind()、call()、apply()
    三者区别:

    1. 三者都能指定this
    2. bind()是将函数返回而不是立即调用,通常用在为回调函数指定this
    3. call()与apply()是立即调用函数
    4. call()传参方式是传入多个参数
    5. apply()传参方式是将多个参数放到数组中传入

    call()与apply()

    var obj = {
            name: 'fitz'
        }
    function foo(name){
        console.log(this)
        console.log('my name is -->' + name);
    }
    
    foo('alpha')   //window    alpha
    foo.call(obj,'logo')  //obj logo
    

    bind()

    var obj = {
            name: 'fitz'
        }
    function foo(name){
        console.log(this)
        console.log('my name is -->' + name);
    }
    
    foo('alpha')   //window    alpha
    
    //bind()
    var bar = foo.bind(obj,'success')
    bar()  //obj    my name is --> success
    
    //bind()
    foo.bind(obj,'success')()  //obj my name is --> success
    
    
    
    //bind()主要用于为回调函数指定this
    setTimeOut(function(){
        console.log(this)
    }.bind(obj),1000)
    

    let const

    let的作用类似于var,用于声明变量
    let声明变量的特点:

    1. let有块级作用域

      var name = 'test var'
      {
         var name = 'dd'
      }
      console.log(name);  //dd var没有块级作用域
      
      
      let name = 'test var'
      {
          let name = 'dd'
      }
      console.log(name);  //test var let有块级作用域
      
    2. let 不能再同一作用域内重复声明变量

      let name = 'dd'
      let name = 'cc' //报错Uncaught SyntaxError: Identifier 'name' has already been declared
      
    3. let不会变量提升

      //var声明变量会有变量提升的特点
      console.log(name)   //undefined 此时name已经被声明但是没有复制
      var name = 'test'
      
      //上面的代码等同于
      var name
      console.log(name)
      name = 'test'
      
      
      
      //let没有变量提升
      console.log(name)   //报错Cannot access 'name' before initialization
      let name = 'let is good'
      
      //let的优势在 循环遍历监听 中的体现
      
      //使用var
      //1s过后打印10个10
      for (var i=0; i<10; i++){
          setTimeout(function(){
              console.log(i) // 10 10 10 ... 10
          },1000)
      }
      
      //使用let
      //1s过后打印 1-9
      for (let i=0; i<10; i++){
          setTimeout(function(){
              console.log(i) // 1 2 3 4 5 6 7 8 9
          },1000)
      }
      
    4. 形成一个暂时性死区(TDZ)

      //暂时性死区表现在,在声明变量前无法打印变量值,而是会引发ReferenceError错误
      console.log(name)
      let name = 'Error will be happen'
      //ReferenceError: Cannot access 'name' before initialization
      

    const作用是定义一个常量
    const声明变量的特点:

    1. 定义赋值后,值不能再被修改
      const name = 'can not change'
      name = 'test to change' //报错Uncaught TypeError: Assignment to constant variable.
      
    2. 其他与let特性相同

    let与const声明的变量在全局对象window中访问不到

    let a = 'A'
    const b = 'B'
    
    //var声明的变量会被挂载到window上,但是let与const声明的变量不会,直接访问便可
    console.log(window.a)   //undefined
    console.log(a)
    console.log(window.b)   //undefined
    console.log(b)
    

    变量的解构赋值

    从对象或者数组中提取数据,并赋值给多个变量

    let myObj = {
            name: 'Fitz',
            age: 20
        }
    
        let myArray = [1,3,5,7,9]
    
        //变量的结构赋值 ===> 对象
        let {name, age} = myObj
        console.log(name)
        console.log(age)
            
            
            
    //变量的结构赋值 ===> 数组
    let [a,b] = myArray
    console.log(a)
    console.log(b)
    
    //取特定位置的值
    let [,,,four,five] = myArray
    console.log(four)
    console.log(five)
    

    用途介绍: 给函数的形参赋值

    //用途
    //这是一种需要被改善的用法
    function foo(obj){
        console.log(obj.name)
        console.log(obj.age)
    }
    foo(myObj)
    
    //这是改善后使用变量结构赋值的用法
    function bar({name,age}){
        console.log(name)
        console.log(age)
    }
    bar(myObj)
    

    模板字符串

    作用: 简化字符串的拼接

    var obj = {
        name: 'Fitz'
    }
    
    //这是需要改进的方法(拼接字符串)
    console.log('my ' + obj.name + 'is cool')
    //这是改进的方法(模板字符串)
    console.log(`my ${obj.name} is cool`)
    

    对象的简写方式

    对象属性名与变量名相同时,可以省略不写

    //引子
    let name = 'Fitz'
    let age = 20
    let obj = {
        name: name,
        age: age,
    }
    console.log(obj)
    
    //简写属性
    let obj2 ={
        name,
        age,
    }
    console.log(obj2)
    

    对象内的方法也能简写

    //引子
    let name = 'Fitz'
    let obj = {
        name: name,
        sayHello: function(){
            return `${this} and hello!`
        }
    }
    console.log(obj)
    console.log(obj.sayHello())
    
    //简写属性
    let obj2 ={
        name,
        sayHello(){     //方法简写
            return `${this} and hello!`
        }
    }
    console.log(obj2)
    console.log(obj2.sayHello())
    

    箭头函数(arrow)

    作用: 定义匿名函数

    //使用箭头函数方式一
    var func = () => console.log('i am a arrow func')
    func()
    
    //使用箭头函数方式二
    (() => console.log('i am a arrow func too'))()
    

    形参个数与语法

    //没有形参时候,()  不能省略
    () => console.log('dd')
    
    //一个形参时候,()  可以省略
    a => console.log(a)
    
    //多个形参时候,()  不能省略
    (x,y) => console.log(x,y)
    

    函数体与语法

    //函数体内只有一个语句或表达式
    (x,y) => x+y    //此时函数会自动 return 结果, {}省略
    
    //如果{}不省略则需要手动 return 返回结果
    
    
    //函数体内有多个语句或表达式
    var func = (x,y) => {
        let result = x**y
        return result + 1
    }
    
    console.log(func(2,3))   //9
    

    箭头函数的特点

    1. 箭头函数没有自己的this
    2. 箭头函数不是在调用的时候决定的,而是在定义的时候箭头函数所处在的对象(包裹住箭头函数的对象)就是它的this
      ===> 透彻理解
      1. 箭头函数的this取决于箭头函数是否被函数包裹着(外层是否有函数)
      2. 如果箭头函数被外层函数包裹,箭头函数的this就是包裹住箭头函数的那个函数的this(箭头函数的this === 外层函数的this)
      3. 没有被函数包裹的话就是this就是window
    //测试箭头函数的this
    (() => console.log(this))()    //window
    
    let outerFunc = {
        flag: 'i am outerFunc',
        testArrow: function(){
            let innerArrowFunc = () => console.log(this)//outerFunc
            innerArrowFunc()//箭头函数被testArrow包裹这
            //所以this就是testArrow这个函数的this
        }
    }
    outerFunc.testArrow() //此时testArrow的this ==> outerFunc
    

    三点运算符

    用于替代arguments但是比arguments更加灵活
    ...args 比 arguments 优点在于:...args收集后是一个真数组可以进行遍历,而arguments是一个伪数组不能直接遍历

    function foo(...args){
        console.log(args)
        args.forEach(function(item,index){
            console.log(item, index);
        })
    }
    
    foo(1,3,5)
    

    三点运算符必须放在最后

    function bar(a,b,...inLastest){
        console.log(a)
        console.log(b)
        console.log(inLastest)
    }
    

    ...args 与 args

    1. ...args是遍历数组中的每一个元素
    2. args是一整个数组
    let arr = [1,2,3,4,5]
    function test(x,y,...args){
        console.log(...args)    //3,4,5
        console.log(args)       //[3,4,5]
    }
    

    使用三点运算符进行扩展运算

    let arr = [2,3,4,5]
    let arr2 = [1, ...arr , 6]
    console.log(arr2)   //[1,2,3,4,5,6]
    console.log(...arr2)//1,2,3,4,5,6
    

    形参默认值

    function foo(x=3,y=6){
        return x * y
    }
    
    console.log(foo()); //9
    

    promise对象

    promise的三种状态

    1. pending 初始化状态
    2. fullfilled 成功状态
    3. rejected 失败状态
    let promise = new Promise( (resolve,reject) => {
        //此时状态为pending
        console.log('第一')
        //执行异步操作
        setTimeout(()=>{
            console.log('我是定时器')
    
            //修改状态为 fullfilled,调用成功回调
            resolve('resolve() ==>')
    
            //修改状态为rejected,调用失败回调
            //reject('reject() ==>')
        },2000)
        
        console.log('我是第二')
    })
    
    promise.then(
        //成功的回调函数
        (data)=>{
        console.log(data + ' success');
        },
        
        //失败的回调函数
        (error)=>{
        console.log(error + ' fail');
        }
    )
    

    promise封装ajax

    function getNews(url){
        //使用promise
        let promise = new Promise((resolve,reject)=>{
            let xhr = new XMLHttpRequest()
            //xhr.open('GET','http://localhost:1080/promise-ajax.js')
            xhr.open('GET',url)
            xhr.send()
            xhr.onreadystatechange = function(){
                if (xhr.readyState === 4){
                    if (xhr.status >= 200 && xhr.status < 300){
                        //成功收到ajax请求结果,更改为成功状态
                        resolve('Success' + xhr.responseText)
                    }else{
                        reject('Error 没有新闻内容')
                    }
                })
            }
        })
        return promise
    }
    
    getNews('http://localhost:1080/promise-ajax.js')
        .then(
            (responseText)=>{
            console.log(responseText)
            //成功后,向另一个路由发送评论ajax请求
            //这里return的也是promise对象
            return getNews('http://localhost:1080/comment.js')
            },
            (error)=>{
                console.log(error)
            }
        )
        //这个then用于处理评论的ajax请求
        .then(
            (comment)=>{
            console.log(comment)
            },
            (error)=>{
                console.log(error)
            }
        )
    

    Symbol数据类型

    引子
    JavaScript中ES6以前总共有6种数据类型,其中5种(String,Boolean,Number,Null,Undefined)是基本数据类型,1种(Object)是引用数据类型

    Symbol的作用

    1. 用于解决ES5中由于属性名都是字符串,导致的重名、污染环境的问题

    symbol的使用

    let obj = {
            username: 'Fitz',
            age: 20
        }
    
    //symbol可以作为对象的一个属性
    //但是不能通过obj.symbol这种方式使用
    //只能通过obj[symbol]的方式使用
    obj[symbol] = 'i am symbol'
    console.log(obj);   //{username: "Fitz", age: 20, Symbol(): "i am symbol"}
    

    Symbol的特点

    1. Symbol属性对应的值是唯一的,解决命名冲突的问题
    2. Symbol的值不能与其他数据进行计算,也不能与字符串进行拼串操作
      console.log(`${symbol1} compare of ${symbol2}`) //报错Uncaught TypeError: Cannot convert a Symbol value to a string
      
    3. for...in 与 for...of遍历时不会遍历出symbol属性
      let obj = {
          username: 'Fitz',
          age: 20
      }
      obj[symbol] = 'i am symbol'
      
      //使用for in或者 for of进行遍历无法获取到symbol
      for (let item in obj){
          console.log(item);  //username  age
      }
      

    Iterator迭代器

    概念:iterator是一种接口机制,为不同的数据结构提供统一的访问机制
    作用:

    1. 为各种数据结构提供一个统一、简便的访问接口
    2. 是数据结构中的城院按某种次序排列
    3. 主要为for...of循环使用

    工作原理:

    1. 创建一个迭代器对象(指针对象),指向数据结构中的起始位置
    2. 当第一次调用next方法时,指针会往后移动,一直到数据结构中的最后一个成员
    3. 每次调用next方法返回的是一个包含value与done的对象 ==> {value: 当前成员的值,done: 布尔值(遍历是否结束)}
      1. 遍历结束后{value: undefined, done: true}

    简单模拟实现iterator

    let arr = [1,3,5,'abc']
    
    function myIterator(obj){
        let i = 0
        let isDone = false;
        return {
            //返回一个next方法
            next(){
                if(arr[i] === undefined){
                    isDone = true
                }
                return {
                    value: arr[i++],
                    done: isDone
                }
            }
        }
    }
    
    var iter = myIterator(arr)
    console.log(iter.next());   //{value: 1, done: false}
    console.log(iter.next());   //{value: 3, done: false}
    console.log(iter.next());   //{value: 5, done: false}
    console.log(iter.next());   //{value: 'abc', done: false}
    console.log(iter.next());   //{value: undefined, done: true}
    

    将iterator接口部署到指定的数据类型后可以使用for...of去循环遍历

    1. 已经默认部署了iterator的对象:数组,字符串,arguments,set容器, map容器
      let arr2 = [1,2,3,4,5,6]
      let str = 'iterator'
      function testIterator(){
          for (i of arguments){
              console.log(`${i} <== arguments`);
          }
      }
      
      for (i of arr2){
          console.log(`${i} <== arr2`);
      }
      for (i of str){
          console.log(`${i} <== str`);
      }
      testIterator('arg1','arg2','arg3','arg4','arg5')
      

    iterator与symbol.iterator的关系
    在指定的数据结构中添加Symbol.iterator的作用是部署iterator接口,当使用for...of去遍历某一个数据结构的时候,会首先去找Symbol.iterator

    let target = {
            [Symbol.iterator]: function(){
                let i = 0
                let isDone = false;
                let that = this
                return {
                    //返回一个next方法
                    next(){
                        if(that[i] === undefined){
                            isDone = true
                        }
                        return {
                            value: that[i++],
                            done: isDone
                        }
                    }
                } 
            }
        }
    

    三点运算符与对象解构赋值都运用了iterator

    let arr2 = [2,3,4,5]
    let arr = [1,...arr2,6]
    console.log(arr)
    let [item1,item2] = arr
    console.log(item1,item2)
    

    Generator生成器

    概念

    1. ES6提供的解决异步编程的方案之一
    2. Generator是一个状态机,内部封装了不同状态的数据
    3. 是一个用来生成Iterator的对象
      1. Generator包含Iterator
    4. 可以惰性求值,yield可暂停,next()可以启动,每次返回的都是yield后表达式的结果

    特点:

    1. 语法:function与函数名之间有一个*号
    2. 内部用yield表达式定义不同的状态
      function* aGenerator(){
          //我是一个Generator
          yield something
      }
      

    向next()方法传入实参可以在启动Generator时,作为yield的返回值
    next()方法时从上一次yield的地方开始运行

    执行流程分析

    //创建一个Generator
    //Generator需要next()启动,遇到yield就停止
    function* aGenerator(){
        console.log('开始遍历')
        yield 'create by Fitz'
        let value = yield '返回值是next()方法的实参'
        console.log(value)
        console.log('遍历完成')
    }
    
    let gen = aGenerator()
    console.log(gen.next()) //遇到yield停止
    /* 
    开始遍历
    {value: "create by Fitz", done: false}
     */
    console.log(gen.next())
    /* 
    {value: "返回值是next()方法的实参", done: false}
     */
     //此时停止在let value = yield '返回值是next()方法的实参'
    console.log(gen.next('我是返回值')) 
    /*
    调用next('我是返回值')方法
    此时在let value = yield '返回值是next()方法的实参'这一句开始运行
    所以返回值value就是next()方法传入的实参 ==> '我是返回值'
    */
    
    /* 结果:
    我是返回值
    遍历完成
    {value: undefined, done: true}
     */
    

    async异步函数

    概念: 真正意义上去解决异步回调的问题,以同步的流程表达异步操作
    本质: 就只是Generator的语法糖

    语法:

    async function foo(){
        await 异步操作  //遇到await就暂停等待异步操作完成后,再往下执行
        await 异步操作
    }
    

    特点:

    1. 不需要像Generator那样需要调用next(),而是在完成await后面定义的异步操作后,自动往下运行
    2. 返回的总是 promise对象 这意味着可以使用.then(()=>{},()=>{})进行操作
      async foo(){
          return 'Fitz'
      }
      console.log(foo())  //promise{fullfill: 'Fitz'}
      
      foo().then(
          data => console.log(data),
          error => console.log(error)
      )
      

    class类

    class类的例子

    class Person{
        //类的构造方法
        constructor(name,age){
            this.name = name
            this.age = age
        }
    
        //类的一般方法
        //只能使用对象方法的简写方式
        sayName(){
            console.log(this.name);
        }
    }
    
    let person = new Person('Fitz',20)
    console.log(person)
    person.sayName()
    

    通过constructor定义类的构造方法

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

    类的继承

    //定义一个 中国明星 类
    //因为明星也是人,所以从 人类  中继承
    class Person{
        constructor (name,age){
        this.name = name
        this.age = age
        }
    
        //类的一般方法
        //只能使用对象方法的简写方式
        sayName(){
            console.log(this.name)
        }
    }
    
    //定义一个 外国明星 类
    //因为明星也是人,所以从 人类  中继承
    class ChineseStar extends Person{
    
    }
    
    let chineseStar = new ChineseStar('jack chen',60)
    console.log(chineseStar)
    

    通过super来调用父类的构造方法

    class Person{
        constructor (name,age){
        this.name = name
        this.age = age
        }
    
        //类的一般方法
        //只能使用对象方法的简写方式
        sayName(){
            console.log(this.name)
        }
    }
    
    class Student extends Person{
        constructor (name,age,grade){
            super(name,age)//调用父类的构造方法
    
            //super()的实参是由ForeignStar这个类的constructor提供
            //而constructor的实参是在类实例中传入
            /* 
                super()的作用相当于直接将父类的constructor复制过来
                //类的构造方法
                constructor(name,age){
                    this.name = name
                    this.age = age
                }
             */
    
            this.grade = grade
        }
    }
    let student = new Student('Fitz',20,'phd')
    console.log(student)
    

    重写从父类中继承的一般方法

    class Person{
        constructor (name,age){
        this.name = name
        this.age = age
        }
    
        //类的一般方法
        //只能使用对象方法的简写方式
        sayName(){
            console.log(this.name,this.age)
        }
    }
    
    class Student extends Person{
        constructor (name,age,grade){
            super(name,age)
            this.grade = grade
        }
    
        /*父类中有一个sayName方法,但是只能打印name与age。此时如果还需要打印grade的话
        就需要重写父类的sayName方法
        */
        sayName(){
            console.log(this.name,this.age,this.grade)
        }
    }
    let student = new Student('Fitz',20,'phd')
    console.log(student)
    student.sayName()   //'Fitz',20,'phd'
    //遵循的是就近原则,所以调用的是子类中的sayName方法
    

    克隆/拷贝

    克隆数据有两种方式:

    1. 深克隆: 克隆生成新的数据,修改这个数据不会影响到原数据
      let str = 'abc'
      let str2 = str  //深克隆
      str2 = 'bcd'
      console.log(str)    //'abc'
      
    2. 浅克隆:克隆后不会产生新的数据,而是克隆、引用内存的地址值,修改数据会影响到原来的数据
      let obj = {name: 'Fitz'}
      let obj2 = obj      //浅克隆
      obj2.name = 'Lx'
      console.log(obj.name)   //'Lx'
      

    克隆数据的几种方法 (深浅拷贝针对的是数组、对象):

    1. 直接复制给一个变量 浅拷贝

      let obj = {name: 'Fitz'}
      let obj2 = obj      //浅克隆
      obj2.name = 'Lx'
      console.log(obj.name)   //'Lx'
      
    2. Object.assign() 浅拷贝

      let obj = {name: 'Fitz'}
      let obj2 = Object.assign(obj)      //浅克隆
      console.log('obj ==>',obj) 
      console.log('obj2 ==>',obj2) 
      
      console.log(obj.name)   //'Fitz'
      obj2.name = 'Lx'
      console.log(obj.name)   //'Lx'
      console.log(obj2.name)   //'Lx'
      
    3. Array.prototype.concat() 浅拷贝

      let arr = [1,2,{name: 'Fitz'}]
      arr2 = arr.concat()     
      arr2[0] = 666       //深克隆
      arr2[2].name = 'LX' //浅克隆
      console.log(arr)    //[1, 2, {…}]
      console.log(arr2)   //[666, 2, {…}]
      
    4. Array.prototype.slice() 浅拷贝

      let myArr = [1,2,3,{name: 'Fitz'}]
      let myArr2 = myArr.slice()
      myArr2[0] = 666
      myArr2[3].name = 'Change'
      console.log(myArr)
      console.log(myArr2)
      
    5. JSON.parse(JSON.stringify()) 深拷贝

      let toJsonStr = {name: 'Fitz'}
      let result = JSON.stringify(toJsonStr)
      console.log(result) //{"name":"Fitz"}
      let clone = JSON.parse(JSON.stringify(toJsonStr))   //深克隆
      console.log(clone)  //{name: "Fitz"}
      clone.name = 'LX'
      console.log(clone)      //{name: "LX"}
      console.log(toJsonStr)  //{name: "Fitz"}
      

    实现深度克隆

    深克隆主要的目标是对象、数组,因为普通数据类型都是深克隆

    现深度克隆方法的主要思路:

    1. 找到数据结构中的所有对象与数组
    2. 将其中的值全部遍历出来(遍历出的必须是基本数据类型)
    3. 然后进行复制,这个复制一定是深克隆

    需要知道的知识:

    1. 检测数据的2种方法

    2. typeof
      返回值只有:Symbol,String,Number,Boolean,Function,Object,Undefined
      NaN ==> Number
      null,array ==> Object

    3. Object.prototype.toString()

      //该函数可以检测数据结构的类型
       function checkType(target){
           return Object.prototype.toString.call(target).slice(8,-1)
       }
      
    4. for...in枚举 对数组、对象的作用

      let obj = {name: 'Fitz',age: 20}
      let arr = [1,3,5,7,9]
      
      for (let i in obj){
          console.log(i)  //name age
      }
      
      for (let i in arr){
          console.log(i)  //0,1,2,3,4
      }
      /* 
          结论:
              对象枚举出的是属性值
              数组枚举出的是下标值
       */
      

    实现深度克隆

    //该函数可以检测数据结构的类型
    function checkType(target){
        return Object.prototype.toString.call(target).slice(8,-1)
    }
    
    
    //实现深度克隆
    function deepClone(target){
        let type = checkType(target)   //得到数据类型
        let result     //初始化
    
        //处理最终的包装容器
        if(type === 'Object'){
           result = {}
        }else if(type === 'Array'){
           result = []
        }else{
            //当数据类型是基本数据类型时
           return target   //递归的基线条件
        }
    
        //处理目标数据
        //同时使用Object与Array
        for (let i in target){
           //当是Object时,返回属性值
           //当是Array时,返回下标
           let value = target[i]   //都能拿到obj与arr中所有的元素
           
           //当是多维的Object与Array
           if(checkType(value) === 'Object' || checkType(value) === 'Array'){
               //例如: [1,[2],{a: 1}]   {a: [1,[2],{b: 2}]}
               //使用递归
               result[i] = deepClone(value)
           }else{  //当Object与Array是一维的
               result[i] = value
           }
        }
    
        return result
    }
    
    
    //测试
    let arrForDeepClone = [1,[2],{a: 1}]
    let objForDeepClone = {a: [1,[2],{b: 2}]}
    let arrForDeepClone2 = deepClone(arrForDeepClone)
    let objForDeepClone2 = deepClone(objForDeepClone)
    arrForDeepClone2[1][0] = 666
    console.log(arrForDeepClone,arrForDeepClone2)
    objForDeepClone['a'][2]['b'] = 666
    console.log(objForDeepClone,objForDeepClone2)
    

    Set容器

    什么是Set容器?
    概念: Set容器是有无序、不可重复的多个value的集合体

    Set容器的方法

    1. Set()

      //创建一个set容器实例
      let set = new Set()
      console.log(set)    //Set(0) {}
      
    2. Set(Array)

      //创建一个set容器实例
      let set = new Set([1,1,2,3,4,2,3,6,2,54])
      console.log(set)    //Set(6) {1, 2, 3, 4, 6, 54}
      
    3. add(value)

      //创建一个set容器实例
      let set = new Set([1,1,2,3,4,2,3,6,2,54])
      console.log(set)    //Set(6) {1, 2, 3, 4, 6, 54}
      
      set.add(666)
      console.log(set)    //Set(7) {1, 2, 3, 4, 6, 54, 666}
      
    4. delete(value)

      //创建一个set容器实例
      let set = new Set([1,1,2,3,4,2,3,6,2,54])
      console.log(set)    //Set(6) {1, 2, 3, 4, 6, 54}
      
      set.delete(4)
      console.log(set)    //Set(6) {1, 2, 3, 6, 54, 666}
      
    5. has(value)

      //创建一个set容器实例
      let set = new Set([1,1,2,3,4,2,3,6,2,54])
      console.log(set)    //Set(6) {1, 2, 3, 4, 6, 54}
      
      console.log(set.has(3))    //true
      
    6. clear()

      //创建一个set容器实例
      let set = new Set([1,1,2,3,4,2,3,6,2,54])
      console.log(set)    //Set(6) {1, 2, 3, 4, 6, 54}
      
      set.clear()        
      console.log(set)           //Set(0) {}
      
    7. size

      //创建一个set容器实例
      let set = new Set([1,1,2,3,4,2,3,6,2,54])
      console.log(set)    //Set(6) {1, 2, 3, 4, 6, 54}
      
      console.log(set.size)      //6
      

    Map容器

    什么是Map容器?
    概念: Map容器是无序的key不重复的 多个key-value集合体

    Map容器的方法:

    1. Map()

      let map = new Map()
      console.log(map)    //Map(0) {}
      
    2. Map(Array)

      let map = new Map([
          ['name1','Fitz'],
          ['name2','Da'],
          ])
      console.log(map)    //Map(2) {"name1" => "Fitz", "name2" => "Da"}
      
    3. set(key,value)

      let map = new Map([
          ['name1','Fitz'],
          ['name2','Da'],
          ])
      console.log(map)    //Map(2) {"name1" => "Fitz", "name2" => "Da"}
      
      map.set('name3','Lx')
      console.log(map)    //{"name1" => "Fitz", "name2" => "Da", "name3" => "Lx"}
      
    4. get(key)

      let map = new Map([
          ['name1','Fitz'],
          ['name2','Da'],
          ])
      console.log(map)    //Map(2) {"name1" => "Fitz", "name2" => "Da"}
      
      console.log(map.get('name2'))   //da
      
    5. delete(key)

      let map = new Map([
          ['name1','Fitz'],
          ['name2','Da'],
          ])
      
      map.delete('name3')
      console.log(map)    //Map(2) {"name1" => "Fitz", "name2" => "Da"}
      
    6. has(key)

      let map = new Map([
          ['name1','Fitz'],
          ['name2','Da'],
          ])
      
      console.log(map.has('name2'))   //true
      
    7. clear()

      let map = new Map([
          ['name1','Fitz'],
          ['name2','Da'],
          ])
      console.log(map)    //Map(2) {"name1" => "Fitz", "name2" => "Da"}
      
      map.clear()
      console.log(map)    //Map(0) {}
      
    8. size

      let map = new Map([
          ['name1','Fitz'],
          ['name2','Da'],
          ])
      console.log(map)    //Map(2) {"name1" => "Fitz", "name2" => "Da"}
      
      console.log(map.size)   //2
      

    Array.prototype.includes

    
    
  • 相关阅读:
    判断字符串是否为数字
    Javascript to validate HKID number
    ServiceNow 中Reference 的 dynamic creation script
    Dynamic CRM 中修改实体中主字段的长度
    字符串的压缩与解压
    JDBC中重要的类/接口-Connection、DriverManager、ResultSet、Statement及常用方法
    java读取指定package下的所有class
    mybatis由JDBC的演化过程分析
    Java类与对象初始化的过程(一道经典的面试题)
    StringBuffer和StringBuilder区别?
  • 原文地址:https://www.cnblogs.com/fitzlovecode/p/learn_ECMAScript567.html
Copyright © 2011-2022 走看看