三万字javaScript基础语法总结| 掘金技术征文(都是精华)

2,339 阅读26分钟

网上基础知识很多了,为什么还要写?

  • 子曰:闻之我也野,视之我也饶,行之我也明。白话就是: 就是听到的,容易忘记,看到的,会依稀记得,但只有身体力行以后,人们才能真正的理解。
  • 给新手一个我自己理解的js基础的版本
  • 给老手一个查缺补漏的版本
  • 看完,自己实践过,js可以基本入门
  • 陆续写了十天(5.1-5.10),如有疏漏,欢迎指出!!!
  • 帮忙点赞、评论、收藏!!!
  • 本文内容涵盖:

零、前提条件:

  • 安装chrome浏览器 必要条件
  • 安装vscode编辑器 必要条件(根据自己喜好可以安装其他的)
  • 安装nodejs环境(非必要条件)
  • 本文重点是学会使用js而不是弄懂原理

一、什么是javaScript(后面都简写成js替代)?

js是一门既可以运行在客户端(浏览器)也可以运行在服务器端(nodejs)的一门遵循ECMAScript规范的弱类型的脚本语言

二、 js包括什么?

  • BOM: Browser Object Model 提供给js请求后端数据等能力BOM
  • DOM:Document Object Model 提供给j s操作html的能力 DOM
  • ECMAScript(es5 es6 typescript) bomdom.png

三、js能做什么?

上面介绍了js的组成,所以就根据这几点来说明js能做什么:

  • 客户端js:
    • 操作DOM:选取对应的html元素。增加,删除,给元素添加各种事件(鼠标事件,键盘事件)等等
    • 操作BOM: 页面的导航,h5的定位api等等都通过这个对象得到
    • js基础:声明变量,给变量赋值,条件判断,循环,定义函数,执行函数,正则表达式等等
  • 服务端js(nodejs):
    • 读写文件
    • 构建服务,处理前端的请求,可以返回给前端html json 图片 视频 音频等资源
    • 作为代理,请求其他后端服务
    • 更多的后面理解深入再补充

四、第一个js程序

本文主要讲解js的语法部分:也就是上面的ECMAScript部分,以es6为主,e6是js语法的第六个版本,2015年推出

  • 客户端:
    • 浏览器控制台里输入console.log("hello js")即可
    • 用编辑器在里面新建.js文件书写js程序
  • 服务端(nodejs环境):已经安装nodejs的前提下
    • mkdir test 创建一个test文件夹
    • cd test 进入test文件夹
    • echo "console.log('hello from nodejs')" > index.js 在test文件夹里面创建index.js 内容是console.log('hello from nodejs')
    • 在test目录下执行node index.js 输出:hello from nodejs

这里举了个nodejs的例子是为了说明js不仅仅可以在浏览器运行,只是让大家知道。后面的部分主要讲浏览器端js如何书写

五、如何表示输出

js中如何表示?

  • document.write 写到html里面 不推荐,每次还要操作DOM
  • window.alert 浏览器弹框
  • window.confirm(要展示在弹框里面的内容) 弹框
  • window.promot弹框,确定后还可以输入内容,和上面两个一样,如过后面有代码,都会阻断后面的代码执行,不推荐使用
  • console.log()输出到控制台。常用 这种方法在浏览器控制台输出一个值 mdn console

六、 vscode里面写第一个js程序输出hello world

  • 上面我们介绍了如何在浏览器控制台里面写第一个js程序,打印简单的可以,通常工作中我们用编辑器写,下面就来实战一下

  • vscode里面新建一个文件夹叫什么无所谓,我这里叫LEARNJAVASCRIPT里面新建'index.html'输入! 按tab快速生成html基本结构,body里面写一个script标签。这个js代码书写的地方,里面写console.log('hello world')保存(cmd + s)以后,在浏览器里面打开这个index.html,打开浏览器控制台 按下Option + Command + J(Mac)或者Ctrl + Shift + J(Windows / Linux)打开后应该会看到效果

  • 但是我们通常会在新的.js结尾的文件表明是js文件里面写j s代码,再html里面引入,而且有一个麻烦的地方是我每次修改了j s,想浏览器里面看到最新的效果,也要刷新浏览器,所以用插件live server解决,我们改造一下代码,LEARNJAVASCRIPT目录下新建index.js 里面输入console.log(111)然后index..html改成这样,表示indx.html中引入index.js,看起来是这样:

  • 保存以后,用live server打开。浏览器里面打开控制台以后就会看到下面的效果:

  • live server是vscode插件, 它可以帮助我们保存代码以后浏览器上看到最新的效果,没安装需要安装一下。

至此我们学会了:

  • 使用vscode编辑代码
  • 使用js内置的方法console.log()来在控制台里面输出值,验证我们程序的结果
  • 使用chrome打开html文件。在chrome的控制台里面看js中console.log的值
  • 使用live server 保证这边修改代码,浏览器端自动更新

接下来我们就在index.js里面输入新的学到的语法,保存以后,借助live server插件在浏览器里面验证结果

七、注释

  • 什么是注释:

    • 给js解释器chrome 的 v8看,告诉js解释器不执行被注释的语句
    • 给开发人员看,必要的注释方便代码维护
  • js中如何注释?

    • 单行注释:用// (cmd + / 快速注释 再次按解除注释)表示。例如 // let name = 'js'

    • 多行注释:用/* 被注释的内容 */

      /* let  name = 'jam'
      console.log(name)*/
      

八、变量

  • 什么是变量

    • 就是值的容器,值可以是数字,字符串,对象等等,值可以改变
  • 如何声明:声明一个容器的过程

    • let 或者 const
  • 如何赋值:用= 的本质是给上面的变量里面存储一个值

    • 变量名字 = 变量的值
  • 如何声明一个变量并且赋值?

    • let name = 'js'
  • 变量的名字(a-zA-Z_$): 一般是让人看了就懂的英文单词,遵循驼峰命名法(多个单词的情况,除了第一个单词全部小写意外,从第二个单词起,首字母大写),例如

let first 
console.log(first)

first = 1
console.log(first)

//声明变量 并赋值,第一次赋值叫初始化
let name = 'tom'

//可以给let声明后的变量再次赋值
name = 'another name'

let NAME = 'jom'
let className = 'className'
let _test = '_test'
let $this = '$'

//声明常量 不可再次被赋值
const PI = Math.PI 

//给常量再次赋值会报错
// PI= 1 //Uncaught TypeError: Assignment to constant variable.
// console.log(PI)
console.log(name,NAME,className,_test,$this)

浏览器里面执行的结果如下:

九、js常用的数据类型:

上面学到了什么值变量,那变量可以有哪些值呢? 我们就来看看js中有哪些数据类型:

  • Numbers : store numbers
  • Strings :pieces of text
  • Booleans : true/false values
  • undefined : 未定义 或者初始值为undefined
  • null : 为空
  • Arrays : An array is a single object that contains multiple values enclosed in square brackets and separated by commas
  • Objects :In programming, an object is a structure of code that models a real-life object. You can have a simple object that represents a box and contains information about its width, length, and height, or you could have an object that represents a person, and contains data about their name, height, weight, what language they speak, how to say hello to them, and more.
let myNameArray = ['Chris', 'Bob', 'Jim'];
let myNumberArray = [10, 15, 40];

//通过下标 获取对应的元素的值 
myNameArray[0]; // should return 'Chris'
myNumberArray[2]; // should return 40


什么时候用数组?

  • 强调数据的顺序

什么时候用对象?

  • 多个属性的集合的时候,比如表示一个圆,有周长,面积等属性,也可以有计算周长和面积的方法

什么时候用函数?

  • 重复的事情,放在一个函数里面,用函数参数表示变化的部分,用函数体里面内容表示不变的地方(函数要做什么事儿)

typeof : 检查数据的类型,不能区分复杂类型(object function null),可以区分简单类型:

十、操作符

  • 赋值操作符:
    • =
    • +=
    • -=
    • *=
    • /=

  • 算数运算符:
    • +
    • -
    • *
    • /
    • %
    • **

  • 比较运算符:返回布尔值,用于继续判断真假
    • `===``严格比较,即比较值也比较类型
    • == 非严格比较,只比较值
    • !==
    • >
    • <
    • >=
    • <=

  • 逻辑操作符号

    • && 与
    • || 或
    • ! 非
    • !! 对值取布尔值
  • 位操作符号

    • & 按位与 :对应的位上同为1才是1
    • | 按位或 :对应的位上有一个是1 就是1
    • ^安位异或:相同返回0 ,不同返回1
    • 按位非 x = -(x+1)
    • >>有符号右移 左侧用0补
    • <<左移 左移,右侧用0补
    • >>>无符号右移动
    // 十转二进制
    console.log(parseInt(2).toString(2)) // 010
    console.log(parseInt(3).toString(2)) // 011
    console.log(parseInt(5).toString(2)) // 101
    console.log(parseInt(6).toString(2)) // 101
    console.log(parseInt(7).toString(2)) // 111
    console.log(parseInt(10).toString(2)) // 1010
    // 表达式是能计算出结果的一段代码
    // 5  101
    // 3  011
    console.log('5&3' , 5&3)  // 1 按位与
    console.log('5|3', 5|3)   // 111=>7 按位或
    console.log('5^3' , 5^3)  // 110 => 6 相同返回0 不同返回1  按位异或
    
    console.log('~5', ~5 ) //-6  按位或
    console.log('~3', ~3) // -4
    console.log('5>> 1', 5>>1) //无符号右移 2
    console.log('5<<1', 5<<1)  //无符号左移 10
    console.log('5>>>1' , 5>>>1)// 2 正数的有符号右移和 无符号右移一样
    console.log('-1>>>1' , -1 >>> 1)//2147483647 这样就很大
    
    
  • 三目运算:判断条件?'为真的情况' : ‘为假的情况’ 等价于后面的if else

    let score = 60
    let result  = score > 60 ? '及格':'不及格'
    console.log(result)//不及格

十一、流程控制:

  • 什么是流程控制?
    • 什么是{}语句块,let const定义的变量在{}内定义的变量只能在语句快内部使用,语句块儿外部访问不到,使用变量时候,会先在语句块儿内部找,找不到再去上层的语句块儿,有的情况下再找,再找不到就去全局作用找,找不到报错变量名 is not defined

  • 条件判断,走a不走b
    • if(express || boolean ){}else{} 判断两种情况
    • 判断多种 >2 中间加 else if即可
    • 嵌套的if else
    • switch case

  • 循环,重复做一件事,考虑用循环
    • for 循环
    • while(){}循环
    • do{}while循环 至少会执行一次

  • 死循环
//没事儿别运行!
//for 
for(;;){
    console.log(1)
}
  
//while
while(true){
    console.log(1)
}
  • 如何终止循环? break
  • 如何跳出本次循环?continue 其他循环继续
for(let i=0; i<10; i++){
  if(i==2) continue
  if(i==5) break
  console.log(i)   
}

let num =0 
whlile(true){
    
    if(num ==1) continue
    
    if(num ==5) break
    console.log(num)
    num++
}

十二、函数

  • 函数在js中特别重要,可以封装重复的代码块儿,根据不同的参数执行语句
  • 如何定义一个函数?
    • function funcNam( arg1, arg2,...argn){ statements }
  • 无返回值的函数:
  // 函数没有返回值
   function log(){
       console.log(1)
   } 
   
   //但这里每次只能输出固定的值,如何输出变化的值?加一个参数即可
   
   function log(n){
       console.log(n)
   } 
   
  • 有返回值的函数:statements 里面加return someVariable
   // 函数有返回值
   function add(num1, num2){
       return num1 + num2
   }

  • 函数如何调用(执行)? 函数名字+() ()里面加实参 ,实参是函数调用的时候传递的值, 形参是函数声明的时候指定的变量
  // 函数有返回值
  // 函数定义  形参1  形参2
  function add(num1, num2){
      return num1 + num2
  }
  
  //函数调用
  let res = add(1,2) //因为函数有返回值,所以函数调用以后的值返回出来以后,赋值给res变量
  console.log(res) //3 

  • return 两个作用:

    • 从函数体内返回一些值
    • return 下一行的代码不会执行
    function getA(a){
        if(a < 0){
            console.log('a 应该大于0')
            return 
        }
        return a 
    }
    
    
    
  • 函数的名字如何输出?以上面add函数为例子: console.log(add.name)// add

  • 函数的默认参数:

   //函数的默认参数
   function l(a = 'defaultvalue'){
       console.log(a)
   }
   l() //defaultvalue
   l(1) //1
  • arguments 是一个类数组对象,主要特点是key是index,而且有length属性,长度和key的个数相同,维护了实参的数据,想使用数组的方法,先转成数组,再使用
//arguments 计算任意个数字之和
function sum(){
   let res = 0;//1声明一个变量,存储结果
   console.log(arguments)
   //2循环 累加所有值 求和
   for(let i=0; i< arguments.length; i++){
       res += arguments[i]
   }
   return res//3因为是求和,所以要将结果返回
}
sum(1,2,3)

//类数组转数组
 let normalArray1 = Array.prototype.slice.call(arguments);
 // -- or --
 let normalArray2 = [].slice.call(arguments);
 // -- or --
 let normalArray3 = Array.from(arguments);
 

  • 剩余参数 ...
   function sumWithArgs(...theArgs){
       // console.log(theArgs)
       let res = 0;
       for(let i=0; i< theArgs.length; i++){
           res += theArgs[i]
       }
       return res
   }
   console.log(sumWithArgs(1,2,3,4,5)) //15
   console.log(sumWithArgs(1,2,3)) //6
   
   
   用数组的reduce 改写
   function sumWithArgsAndReduce(...theArgs){
        return theArgs.reduce( (acc ,next) =>  acc += next , 0)
   }
   console.log(sumWithArgsAndReduce(1,2,3,4,5))
   console.log(sumWithArgsAndReduce(1,2,3))

  • 作用域:变量的生效范围
    • 局部作用域 : 定义在函数内部的变量,只能在函数内部使用,局部作用域可以访问全局作用域内的变量
    • 全局作用域 : 函数外部的

  • 如何写好一个函数? 采用自顶向下的方式,先实现大框(主干),再针对每个函数填充细节,让代码清晰,表达力强 clean code book review
  • 函数有哪些形式?
    • function 关键字声明的函数:
    • 箭头函数: es6函数的简写形式
    • 函数表达式 : 函数赋值给一个变量
    • IEFE:Immediately Invoked Function Expression
    • callback: 函数作为参数

var num1 = 10 
;(function(){
    //自执行函数会有自己的函数作用域,避免和全局同名变量冲突
    var num1 = 1
    console.log(num1)//1
})()
console.log(num1)//10

//IEFE Immediately Invoked Function Expression

let IEFE = (function(){
    console.log(1)
})()
let IEFE1 = +(function(){
    console.log(1)
})()
let IEFE2 = -(function(){
    console.log(1)
})()
let IEFE3 = ~(function(){
    console.log(1)
})()

  • 函数在js中是一等公民(first-class functions)
    • 函数也是对象
    • 函数可以赋值给一个变量
    • 函数可以当参数传递给另一个函数
    • 函数可以作为另一个函数的返回值
    • HOC(higher-order functions)高阶函数
      • 什么是高阶函数?函数作为另一个函数的参数或者返回值,就是高阶函数 Functions that operate on other functions, either by taking them as arguments or by returning them, are called higher-order functions

      HOC有利于抽象重复(循环) 有利于函数式编程FP(一种编程范式,纯函数,无状态,还有面向过程编程(每一步应该干什么,把所有步骤解决,问题就解决了),还有面向对象编程OOP:Object Oriented Programming OOP 注重的是数据和行为的打包封装以及程序的接口和实现的解耦,解决问题的过程就是调用对象相关方法的过程),还有AOP面向切面编程,一种横向的切面,每个类里面都要执行这个步骤,把这个步骤抽离出来,统一处理,给需要的类再添加如何触发,什么时候触发等等,工作中应该用哪种编程范式? 什么时候需要什么范式就用什么范式,需要积累才能有体会

      • HOC如何抽象重复的?
      • 我们先来看看不用HOC如何实现[1,2,3]变成[2,3,6]?
      let res = [1,2,3]
      let result = []
      for(let i = 0; i< res.length; i++){
          result.push(res[i] * 2)   
      }
      
      • 用HOC如何实现?
      let result = res.map( x => x * 2 )
      
      • Array.prototype.map就是一个HOC,因为参数是一个函数。 Array.prototype是数组的原型,就是个对象,里面存储多个供数组实例使用的方法,什么是数组实例? [] || new Array(2)

      • 实现一个数组的map函数?

      //实现一个简单的map 没有开始的参数校验和this的处理
      // 1有返回值 所以要声明一个数组
      // 2因为是高阶函数,所以要有一个回调函数cb
      // 3因为是多个,所以循环处理。里面调用传进来回调函数,传递需要的值,将处理好的结果push进声明的数组里
      // 4返回处理好的数组
      Array.prototype._map = function(cb ){
          //Array.prototype 里面的this是数组实例 可以使用原型上的方法
          let result = []
          for(let i=0; i < this.length; i++){
              result.push( cb(this[i], i, this))
          }
          return result
      }
      
      res2 = res._map( x => x*2) //[2,4,6]
      

  • closure: 闭包 什么是闭包? Closures preserve the outer scope inside an inner scope

first-class functionsHOCclosure的区别是?

- `first-class functions`: 函数可以作为参数赋值给变量 
- `HOC`:函数的参数哦或者返回值可以是函数
- `closure`:Closures preserve the outer scope inside an inner scope

十三、数组

  • 什么是数组:顺序存储一个或多个同类型或者不同类型的数据结构,一般存储同类型的。

  • 数组如何创建?

    • 字面量的方式:
    • 构造函数的方式:
    • new Array方式:声明指定数量的空元素
    • Array.of方式:设置一个参数不会创建空元素,设置多个会创建多个空元素
    • Array.from方式:也可以将类数组转成数组
    • [...arrayLike]
        
    //创建数组
    //1字面量 常用
    let arr = [1,2,3]
    console.log(arr) //[1,2,3]
    // //2构造函数 
    let arr2 = Array(3)
    console.log(arr2)//[empty × 3]
    // //3 new Array(3)
    let arr3 = new Array(3)
    console.log(arr3) //[empty × 3]
    // //4 Array.of(3) 创建一个
    let arr4 = Array.of(3) , arr4Multi = Array.of(3,4,5)
    console.log(arr4) //[3]
    console.log(arr4Multi)// [3,4,5]
    // //5 Array.from({length:3}, (v,i)=> i) 快速创建多个数组使用
    let arr5 = Array.from({length:3}, (v,i)=> i)
    console.log(arr5)//[0,1,2]
    let str ='alex'
    console.log(Array.from(str))// ['a','l','e','x']
    
    let arr3Hello = Array.from({length:3}, (v,i)=> 'hello')
    console.log(arr3Hello)//["hello", "hello", "hello"]
    
    let divs = document.querySelectorAll("div");
    [...divs].map
    
    
    
    
  • 数组的语法: let arr = [ 'item1','item2']

  • 数组数据的存取:

    • 数组长度: arr.length
    • 数组下标从零开始 到arr.length-1结束
    • 存:
      • arr[index] =val
    • 取:
      • arr[index]0<=index <= arr.length-1

  • 数组构造函数上的方法:构造函数Array使用
    • Array.from
    • Array.isArray()
    • Array.of()
        
    //数组构造函数上的方法
    console.log(Array.isArray(arr)) //false
    console.log(Array.isArray("foobar")) //false
    console.log(Array.of(7)) // [7]
    console.log(Array.of(1, 2, 3) )// [1, 2, 3]
    //生成指定长度对的数组 或者类数组转数组
    console.log(Array.from({length:3}, (v,i)=> i)) //[0,1,2]
    //Array.from(document.getElementsByName('div')) 
    
    
    
    
  • 数组原型上的方法:实例可以直接使用.
  • 删除元素
let arr = [1,2,3,4,5,6]
//删除最后一项
arr.length = arr.length-1
console.log(arr)//[1, 2, 3, 4, 5]

//删除指定下标的元素 比如下标为2的元素就是3 可以用数组内置的方法(可以直接用) splice
arr.splice(2, 1) // 3
console.log(arr) //[1,2,4,5]
//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
//从第 2 位开始删除 0 个元素,插入“drum”
let  myFish = ["angel", "clown", "mandarin", "sturgeon"];
myFish.splice(2, 0, "drum");
console.log(myFish)// ["angel", "clown", "drum", "mandarin", "sturgeon"]


  • 数组的遍历
    • for循环 输出数组每一项和对应下标
    • for of 输出数组每一项目 遍历可迭代对象,数组是可迭代的对象
    • forEach 输出数组的每一项,下标,数组本身
    //数组遍历
    let myFish1 = ['hello','array'];
    
    //for 循环
    for(let i=0,len=myFish1.length; i<len; i++){
        console.log(myFish1[i])
    }
    //for of 循环
    for(let i of myFish1){
        console.log(i)
    }
    //[].forEach((ele, index, arrSelf)=> {})
    ['hello','array'].forEach((ele, i, myFish)=>{
        console.log(ele,i ,myFish)
    })
    
     let names1 = ['alex','tom']
    const iterator = names1.entries()
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator)
    for(let [key,value] of names1.entries()){
        console.log(key,value)
    }
    
    

  • 数组的栈模式和队列模式
//js数组本身实现了栈和队列的功能和双端队列的功能
//栈模式 栈是一种后进先出LIFO( Last In First Out )的数据结构,进出都在栈顶操作,离栈顶远处的叫栈底
let stack = []
//入栈
stack.push(1)                   // | 3 | 
stack.push(2,3)                 // | 2 |   
console.log(stack)//[1,2,3]     // | 1 |
//出栈                                      
console.log(stack.pop()) //3从栈顶移除         // | 2 | 
                                             // | 1 |
console.log(stack.pop()) //2从栈顶移除
console.log(stack)//[1]
console.log(stack.pop()) //undefined
console.log(stack.pop())

//数组的队列模式,这里应是双端队列,既可以从尾部插入,可以从尾部删除
//既可以从头部插入元素,也可以从头部删除元素
let queue = []

queue.push(1,2,3)
console.log(queue)

//从头部移除一个元素
let firstRemoved = queue.shift()
console.log(firstRemoved)
console.log(queue)
//从头部添加一个元素
queue.unshift('first')
console.log(queue)
  • 数组查找元素

    • indexOf 从前往后找元素出现的位置,找不到返回-1,严格比较,第二个参数可以指定查找的位置
    • lastindexOf
    • includes查找字符串返回值是否是布尔值,只能找基本类型
    • find 可以找基本和引用类型
    • findIndex返回索引值,找不到返回-1
        //indexOf 从前往后找基本类型在数组中的index
    const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
    console.log(beasts.indexOf('bison'));//1
    console.log(beasts.indexOf('giraffe'))// -1
    
    //lastindexOf  从后往前找基本类型在数组中的index 
    const animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo'];
    console.log(animals.lastIndexOf('Dodo'))//3
    console.log(animals.lastIndexOf('Tiger'))//1
    // //find  满足条件返回对应项,否则返回undefined
    //找基本类型的那一项
    const array1 = [5, 12, 8, 130, 44];
    const found = array1.find(element => element > 10)// 12
    //找引用类型的那一项
    var inventory = [
        {name: 'apples', quantity: 2},
        {name: 'bananas', quantity: 0},
        {name: 'cherries', quantity: 5}
    ];
    console.log(inventory.find(fruit.name === 'cherries')); // { name: 'cherries', quantity: 5 }
    
    // //findIndex  找到返回下标否则返回-1 
    //找基本类型的索引
    const array11 = [5, 12, 8, 130, 44];
    const isLargeNumber = (element) => element > 13;
    console.log(array11.findIndex(isLargeNumber) , array1);//3  Array [5, 12, 8, 130, 44]
    
    
  • 数组排序

    • reverse:反转数组
    • sort : 每次使用两个值比较,默认从小到大排序数组,也可以自己定义排序规则
        //反转数组
    let testArr = [1,2,3]
    console.log(testArr.reverse()) //[3, 2, 1]
    //非数组先转成数组 再revese
    let helloStr = 'hello'
    let rervesedStr = helloStr
                        .split('')//字符串方法 按空字符串切割成数组
                        .reverse()//上一步变成数组了,可以使用数组方法 反转数组
                        .join('')// 数组方法 用空格拼接,将数组转成字符
    console.log(rervesedStr) // olleh
    
    let sortArr1 = [1,3,7,5]
    console.log(sortArr1.sort() ,sortArr1)//[1,3,5,7] 升序 会改变原数组
    console.log(sortArr1.sort( (a,b)=> a-b))//[1,3,5,7] 升序 会改变原数组
    console.log(sortArr1.sort( (a,b)=> b-a)) //[7,5,3,1] 降序  会改变原数组
    
    
    • toLocaleString, flat:扁平化数组
            //toLocaleString
    const array111 = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
    const localeString = array111.toLocaleString('en', { timeZone: 'UTC' });
    console.log(localeString);//1,a,12/21/1997, 2:12:00 PM
    
    
    //flat 扁平化数组
    var arr1 = [1, 2, [3, 4]];
    arr1.flat(); 
    // [1, 2, 3, 4]
    
    var arr2 = [1, 2, [3, 4, [5, 6]]];
    arr2.flat();
    // [1, 2, 3, 4, [5, 6]]
    
    var arr3 = [1, 2, [3, 4, [5, 6]]];
    arr3.flat(2);
    // [1, 2, 3, 4, 5, 6]
    
    //使用 Infinity,可展开任意深度的嵌套数组
    var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
    arr4.flat(Infinity);
    // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    • some every
        
    //every 都会遍历
    const isBelowThreshold = (currentValue) => currentValue < 40;
    const array1 = [1, 30, 39, 29, 10, 13];
    console.log(array1.every(isBelowThreshold), array1);// true , [1, 30, 39, 29, 10, 13] 不会改变原数组
    
    // some 找到了就返回true 不一定全遍历
    const array = [1, 2, 3, 4, 5];
    // checks whether an element is even
    const even = (element) => element % 2 === 0;
    console.log(array.some(even), array) //true [1, 2, 3, 4, 5] 不会改变原数组
    
    • map filter reduce
        //filter
    const words = ['spray', 'destruction', 'present'];
    const result = words.filter(word => word.length > 6);
    console.log(result ,words);
    
    //map 
    const arr = [1,2,3]
    const arr2 = arr.map( x=>x*2)
    console.log(arr, arr2)//[1, 2, 3]  [2, 4, 6] 不改变原数组 返回新数组
    
    //reduce 
    console.log(arr.reduce( ( acc ,next )=> acc += next))  // 求和 6 
    console.log(arr.reduce( ( acc ,next )=> acc += next, 100 ) ) //指定初始值求和 100+ 6 = 106
    
    • 数组裁切:slice
        //slice 裁切 返回新的数组 不改变原数组
    let arr12345 = [1,2,3,4,5]
    console.log(arr12345.slice(), arr12345)//[1, 2, 3, 4, 5] (5) [1, 2, 3, 4, 5]
    console.log(arr12345.slice(0))//[1, 2, 3, 4, 5] 复制数组
    //包括前面 不包括后面
    console.log(arr12345.slice(1))//[2, 3, 4, 5]
    //-1 从右往左找第一个
    console.log(arr12345.slice(1,-1)) // [2, 3, 4]
    
    • 数组的解构
    //数组解构
    
    let numbers = [3,4,{name:1}]
    let [a, b , c] = numbers
    //取 对应的元素
    console.log(a,b ,c)
    //取剩余元素
    let [a1, ...args] = numbers
    console.log(a1, args)
    // 取name的值 
    let [,, {name}] = numbers
    console.log(name) //1 
    

    • 二维数组
        //二维数组
    let arr = [ ['alex'], ['age']]
    console.log(arr[0][0])// alex
    

十四、对象

常用,用来表示多个属性或者方法的集合,不要求顺序

  • 对象如何创建?

    • 字面量方式: let person = {name:1,age:2 }
    • new Object():
    let person = new Object()
    person.name = 'alex'
    person.age = 18
    //console.dir 控制台输出对象
    console.dir(person)
    
  • 对象的语法 :只有key和value有对应关系。而key和key直接的顺序不能保证

//语法:
 let obj = {
    key1 : value1,
    key2 : value2
 }
 
 let person = {
     name : 'alex',
     age : 18
     sayName : ()=> conole.log(this.name)
 }
 
 
  • 对象属性的存取
    • 赋值: obj.key = value 或者 obj['newKeyName'] = value
    • 取值: obj.key 或者 obj['key'] 或者 解构赋值 let{name,age} = {name:1,age:2}

  • 省略key

    //
     let name = 'alex'
     let person = {
         name : name,
         sayName: function(){
             console.log(1)
         }
     }
     //key value相同的时候  或者简写function
     let person={
         name,
         sayName(){
             console.log(1)
         }
     }
    
    
    
  • "use strict"; 严格模式

    • 如何开启:为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 "use strict"; (或 'use strict';)
    • 有什么用?减少不必要的错误等等详细参考:mdn use strict
  • 删除key: delete :对象本身可以被删除的时候才能删除掉

    let person={
        name,
        sayName(){
            console.log(1)
        }
    }
    //Object.keys 获取对象的所有key 返回数组
    console.log(Object.keys(person))//["name", "sayName"]
    delete person.name
    console.log(Object.keys(person))//["sayName"]
    
    // configurable 决定对象的属性是否可以被删除
    var o = {};
    Object.defineProperty(o, 'a', {
      get() { return 1; },
      configurable: false
    });
    console.log(o.a); //1 
    delete o.a
    console.log(o.a) //1 还是1 没有删除成功
    
  • Object.defineProperty 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。该方法允许精确地添加或修改对象的属性,vue2.0 一个前端框架,封装一些常用功能,加速开发,使用它要遵循它的规则使用的这个api实现的双向绑定(数据修改会自动更新绑定的dom,更新界面,不用手动操作dom,dom修改会自定改变绑定的数据)

    Writable 属性:当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。

    Enumerable 属性: enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。 Configurable 属性:configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。 自定义 Setters 和 Getters

        function Archiver() {
        var temperature = null;
        var archive = [];
      
        Object.defineProperty(this, 'temperature', {
          get: function() {
            console.log('get!');
            return temperature;
          },
          set: function(value) {
            temperature = value;
            archive.push({ val: temperature });
          }
        });
      
        this.getArchive = function() { return archive; };
      }
      
      var arc = new Archiver();
      arc.temperature; // 'get!'
      arc.temperature = 11;
      arc.temperature = 13;
      arc.getArchive(); // [{ val: 11 }, { val: 13 }]
    
  • hasOwnProperty判断对象自身是否含有某个属性

    //判断对象自身是否含有某个属性 
    let p= {}
    console.log(p.hasOwnProperty('time'))//false
    p.name = 'alex'
    console.log(p.hasOwnProperty('name')) //true
    
    
  • 对象常用方法

    • 合并两个对象:
        let config = {name:1,age:2}
        let newConfig = {name:2, time:'2020-05-'}
        let  finalObj = {...config, ...newConfig}
        console.log(finalObj)
        
        //只更新对象的一个属性 比如name属性
        finalObj = {...finalObj, name:'testName'}
    
    • 遍历对象
    let p = {
        name :'alex',
        age : 18,
        sayname(){
            console.log('1')
        }
    }
    
    let keys = Object.keys(p)
    let values= Object.values(p)
    console.log(keys,values)//(3) 
    //["name", "age", "sayname"] (3) ["alex", 18, ƒ]
    
    // for in 
    for(let key in p ){
        console.log(key, p[key])
    }
    
    • this : 当前执行代码的环境对象,在非严格模式下,总是指向一个对象,在严格模式下可以是任意值,下面讨论的都是客户端的this,不包括nodejs端的js

    • 作用域包括:全局作用域 函数作用域 eval作用域 模块作用域

    • 全局作用域中的this指的是全局对象 window:无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。

          // 在浏览器中, window 对象同时也是全局对象:
       console.log(this === window); // true
       console.log(this === top); // true 
       console.log(window === top);// true
       
       //不建议这么做 不声明的变量会变成window的属性
       a = 37;
       console.log(window.a); // 37
       
       this.b = "MDN";
       console.log(window.b)  // "MDN"
       console.log(b)         // "MDN"
      
      
    • 函数作用域中this指的是 函数调用时候决定,一般看.前面是谁就是谁

    • window.setTimeout()和window.setInterval()的函数中的this有些特殊,里面的this默认是window对象。

    • 构造函数和原型中的this指的是对应的实例

    • 箭头函数中this:箭头函数没有绑定this,它的this取决于该函数外部非箭头函数的this 值

    • 作为对象的方法,它们的 this 是调用该函数的对象

    • getter 与 setter 中的 this :用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。

        function sum() {
      return this.a + this.b + this.c;
    }
    
    var o = {
      a: 1,
      b: 2,
      c: 3,
      get average() {
        return (this.a + this.b + this.c) / 3;
      }
    };
    
    Object.defineProperty(o, 'sum', {
        get: sum, enumerable: true, configurable: true});
    
    console.log(o.average, o.sum); // logs 2, 6
    
    
    • 当函数被用作事件处理函数时,它的this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)
    
    // 被调用时,将关联的元素变成蓝色
    function bluify(e){
      console.log(this === e.currentTarget); // 总是 true
    
      // 当 currentTarget 和 target 是同一个对象时为 true
      console.log(this === e.target);        
      this.style.backgroundColor = '#A5D9F3';
    }
    
    // 获取文档中的所有元素的列表
    var elements = document.getElementsByTagName('*');
    
    // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
    for(var i=0 ; i<elements.length ; i++){
      elements[i].addEventListener('click', bluify, false);
    }
    
    
    • 作为一个内联事件处理函数this指向监听器所在的DOM元素
    // this 是button
    <button onclick="alert(this.tagName.toLowerCase());">
      Show this 
    </button>
    
    // window 在这种情况下,没有设置内部函数的this,所以它指向 global/window 对象(即非严格模式下调用的函数未设置this时指向的默认对象)
    <button onclick="alert((function(){return this})());">
      Show inner this
    </button>
    
  • 如何改变this?

    • call 第一个参数是要改变的this 后面依次接受多个参数 立即执行
    
    function greet() {
      var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
      console.log(reply);
    }
    
    let  obj = {
      animal: 'cats', sleepDuration: '12 and 16 hours'
    };
    
    greet.call(obj);  // cats typically sleep between 12 and 16 hours
    
    
    • apply 第一个参数是要改变的this 后面数组形式 立即执行

    • bind 改变this 再次调用才能执行

    • 先来一波 this指向问题

        let person = {
    name :'alex',
    sayName :function(){
        console.log(`name 是 ${this.name}`)
    },
    say(){ console.log(`arrow say ${this.name}`)},
    group:{
        name :'groupName',
        logName(){
            console.log(`group name is ${this.name}`)
        }
    }
    }
    function windowSayName(){
        console.log(`windonw say name is : ${this.name}`)
    }
    console.log(person.sayName()) // name 是 alex
    console.log(person.say())//arrow say alex
    console.log(person.group.logName()) //group name is groupName 
    //没输出 因为window上没有name
    console.log(windowSayName())//windonw say name is :  
    
    • 使用call apply bind
    //call apply bind   修改this 指向
    let person = {
        name :'alex',
    }
    function windowSayName(age,group){
        console.log(`windonw say name is : ${this.name},age:${age},group:${group}`)
    }
    console.log(windowSayName.call(person , 18,'fe' ))
    //windonw say name is : alex,age:18,group:fe
    
    console.log(windowSayName.apply(person, [18, 'fe']))
    //windonw say name is : alex,age:18,group:fe 
    
    console.log( typeof windowSayName.bind(person, [18, 'fe']) )// function
    console.log( typeof windowSayName.bind(person, [18, 'fe'])() )
    //windonw say name is : alex,age:18,fe,group:undefined
    
    

  • 构造函数: 类比现实:人类是 构造函数 具体某个人是 实例 js中 构造函数函数名一般首字母大写,通过new 调用来生成实例

    
    // function Person(name,age){
    //     this.name = name
    //     this.age = age
    // }
    // let p1 = new Person('alex',18)
    
    
    • 构造函数和普通函数的区别:

      • this :构造函数内部this指向新创建的对象实例,普通函数this.如果在严格模式下,this表示undefined。非严格模式下,this指向的是window。
      • new :构造函数需要new 调用,普通函数不用
      • return :普通函数return后面 有值正常返回,没有值或者没有写return就返回undefined。 构造函数一般不需要使用return,如果返回基本类型值,可以忽略return语句。 如果返回值是引用类型时,会直接返回引用类型本身。
    • 实例 构造函数 原型之间的关系,两张图搞定:

- 什么是原型链

  • 获取对象的原型:Object.getPrototypeOf

  • 改变原型指向Object.setprototypeOf() Object.setprototypeOf mdn

  • getter setter

  • Object.create
      
      function Person(name,age){
          this.name = name
          this.age = age 
      
      }
      
      Person.prototype.sayName = function(){
          console.log(this.name)
      }
      
      Person.prototype.one = function(){
          return 1
      }
      
      let person = new Person('alex', 18)
      let student = Object.create(person)
      
      
      //for in 可以遍历原型上的方法和属性
      for(let keyStu in student){
          console.log(keyStu, student[keyStu])
      }
      console.log(student.time)
      
      student ={
          name: 'tom',
          age:'20'
      }
      
      console.log(student)
      //只遍历自己的属性和方法
      for(let key in student){
          if(student.hasOwnProperty(key)){
              console.log(key, student[key])
          }
      }
      
      
      //多继承
      
      // function SuperClass(){}
      // function OtherSuperClass(){}
      
      // function MyClass() {
      //     SuperClass.call(this);
      //     OtherSuperClass.call(this);
      // }
      
      // // 继承一个类
      // MyClass.prototype = Object.create(SuperClass.prototype);
      // // 混合其它
      // Object.assign(MyClass.prototype, OtherSuperClass.prototype);
      // // 重新指定constructor
      // MyClass.prototype.constructor = MyClass;
      
      // MyClass.prototype.myMethod = function() {
      //     // do a thing
      // };
    

  • 字面量声明的空对象和Object.create(null)的区别

  • 对象应用:

    • 避免书写多个if else:
    //根据不同的状态码,提示不同的消息
let nowCode = 2
switch(nowCode){
    case 0:
    case 1:
        alert('成功')
        break
    case 2:
        alert('失败')
        break
    case 4:
        alert('请求中')
        break
    default:
        alert('未知的状态码')
}
//改写成对象存储 key : 状态码  value : 对应的文案 再新增需求,就新增statueCode对象的属性即可
function judgeCodeStatus(nowCode = 0){
    let statueCode  ={
        0 : '成功',
        1 : '成功',
        2 : '失败',
        4 : '请求中'
    }
    if(statueCode[nowCode]){
        alert(statueCode[nowCode])
    }else{
        //defalut情况
        alert('未知的状态码')
    }
}
judgeCodeStatus(prompt('请输入状态码'))


- 存贮一个多个信息:
```
let student = 
{
    'name' :'lili',
    'age' : 18,
     math : 100,
     english : 90
}


```

  • 对象的解构:方便快速取值

  • 基本类型按值传递,引用类型(对象数组)按引用传递,修改之后,所有用到该引用的值都会变化

十五、class

  • 面向对象,class写法,本质是语法糖 还是基于原型链的

    • 定义一个类:class关键字

    • 类上的静态方法 static 相当于构造函数上的方法,不用new就可以通过类.方法名使用

    • 类的构造函数:用来初始化实例的属性

    • 类的上的方法相当于原型上的方法:用来给实例在原型上添加方法,便于多个实例使用,方法定义在原型上,通过原型链查找,节省内存

    • 类的继承:extends关键字

    • es5写法 如何定义一个构造函数,并且在原型上添加方法 和实例化对象

    
    function PersonEs5(name,age){
    	this.name = name
      	this.age = age 
    }
    
    //给构造函数这个对象添加他自己使用的方法
    PersonEs5.hello = function(){console.log(1)}
    
    PersonEs5.prototype.sayName = function(){
    	return this.name
    }
    
    //多个方法继续在 PersonEs5.prototype.xx  = function(){} 上赋值即可
    
    //new + 构造函数 实例化一个 实例p1 
    let p1 = new PersonEs5('alex',18)
    
    //打印p1实例
    console.log(p1)
    
    //调用p1的sayName方法 本身没有会去对应的原型链上找,找到使用
    console.log(p1.sayName())
    //打印构造函数上的方法 
    console.log(PersonEs5.hello())
    
    
    

  • es6写法:

- 继续添加类的静态方法,也就是构造函数使用的方法

  • 把babel右侧的代码放在vscode里面,方便查看,分析一下代码

  • 所以本质class就是语法糖

十六、字符串

  • 字面量创建,单引号或者双引号都可以

十七 正则表达式,处理字符串的利器 TODO 后面再补充完整

  • 举个例子
    let str = '0123123123helloworld';
    //不用正则 找出所有数字
    let num = [...str].filter( s => !Number.isNaN(parseInt(s))).join("")
    console.log(num)//0123123123
    
    //使用正则
    console.log(str.match(/\d/g).join(""))//0123123123
  • 如何创建
    • 字面量方式:
    • new Regexp方式:

十七、内置对象,知道用的时候找对应的对象即可

  • Number
let str = '123', str1 = '12.3'
console.log(Number(str), Number.parseFloat(str1))
console.log(Number.isNaN(str))
let num = 12.324234
let numStr = num.toFixed(2)
console.log(numStr)

console.log(Number.MAX_SAFE_INTEGER)
console.log(Number.MIN_SAFE_INTEGER)
console.log(Number.MAX_VALUE)
console.log(Number.POSITIVE_INFINITY)
console.log(Number.NEGATIVE_INFINITY)

  • Math
    // Math 数学相关的 常用方法
    console.log(Math.PI)//3.141592653589793
    //绝对值
    console.log(Math.abs(-1)) //1
    console.log(Math.sin(Math.PI /2)) //1
    
    //向上取整
    console.log(Math.ceil(.99)) //1
    //向下取整 
    console.log(Math.floor(1.99)) //1
    //随机数 返回一个 0 到 1 之间的伪随机数。
    console.log(Math.random())
    
    //返回一个数的 y 次幂。
    console.log(Math.pow(10,2))//100
    
    //返回一个数的整数部分,直接去除其小数点及之后的部分。
    console.log(Math.trunc(9.45)) // 9
  • Date
    //Date
    let date = new Date()
    //get 
    console.log(date)
    console.log(date.getFullYear()) // 2020
    console.log(date.getMonth()) // 4  + 1 = 5月 0-11 需要加一
    console.log(date.getDay())//周几 0 
    console.log(date.getDate())//几号  10 
    
    console.log(date.getHours()) //20
    console.log(date.getMinutes()) //56
    console.log(date.getSeconds()) //32
    // 1970到现在的毫秒数
    console.log(date.getTime()) //1589115447269
    //本地表示方法
    console.log(date.toLocaleDateString()) //2020/5/10
    //set 
    console.log(date.setFullYear(2030))
    console.log(date.toLocaleDateString())//2030/5/10
    
    date.setTime(1404648371937)
    console.log(date.toLocaleDateString())//2014/7/6
  • Json
    • JSON.parse json字符串转json对象
    • JSON.stringify json对象字符串化
        let postJSON = `{
        "id" : 1,
        "title" : "标题",
        "comments":[
            {
                "userId":1,
                "comment":"评论1"
            },
            {
                "userId":2,
                "comment":"评论2"
            }
        ],
        "isPublished" : false,
        "author": null
    }`
    //转成json对象
    console.log(JSON.parse(postJSON))
    let JSONObj ={
        name:'alex',
        skills:['js','html','css']
    }
    //输出 js字符串
    console.log(JSON.stringify(JSONObj))
    
    //格式化输出
    console.log(JSON.stringify(JSONObj, null, 2))
    //简单判断 json字符串是否合法
    const isJSON = (jsonStr)=>{
        if(typeof jsonStr  ==='string'){
            try{
                if(typeof  JSON.parse(jsonStr)){return true}
            }catch(e){
                return false
            }
        }
    }
    console.log(isJSON(postJSON)) // true
    

  • Set 没有重复元素的集合
    //Set  的curd
    let arr = [1,1,2,3,3,4,4]
    console.log([...new Set(arr)])//数组去重 [1, 2, 3, 4] 
    
    let set = new Set()
    set.add(1)
    set.add(2)
    set.add(4)
    console.log(set) //Set(3) {1, 2, 4}
    set.add(4)//添加重复的元素 不会生效
    console.log(set)//Set(3) {1, 2, 4}
    //判断是否含有
    console.log(set.has(2), set.has(10)) // true false
    
    //遍历
    set.forEach( val => console.log(val)) //1 2 4 
    
    //清空
    set.clear()
    console.log(set ,set.size)//Set(0) {} 0
    
    //set 里面的元素是对象
    let obj1 = {id :1} , obj2 = {id:1}
    set.add(obj1)
    set.add(obj2)
    console.log(set)
    set.add(obj1)
    console.log(set)

  • Map:是一种键值对的数据结构,跟对象类似,但是map的key,value可以是任意类型

    let map = new Map()
    let objKey = {key : 2}
    map.set(1,'val1')
    map.set( objKey ,'val2')
    map.set('key 3', 'val 3')
    console.log(map)
    
    //通过key获取值 key可以是变量
    console.log(map.get(1), 
             map.get(objKey),
             map.get('key 3'),
             map.get('123'))//val1 val2 val 3 undefined
    //通过key判断是否含有 返回布尔值         
    console.log(map.has(objKey)) //true
    map.forEach( (val, key) => 
        console.log(key, val)
    )
    //迭代器
    let iterator = map.entries()
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())
    
    //for of 遍历
    for(let [key, val] of map){
        console.log(key, val)
    }

十八、异常处理

  • try{}catch(e){}finally{}
  • throw 主动抛出异常
  • 程序错误异常
  • 如何自定义异常?
  • 如何处理多个异常?
       // ok always
    try{
        console.log('ok')
    }catch(err){
        console.log(err)
    }finally{
        console.log('always')
    }
    
    //throw 主动抛出异常
    //diy err always 如何走到catch里面 ? try里面主动抛出错误
    try{
        throw new Error('diy err')
        console.log('ok')
    }catch(err){
        console.log(err)
    }finally{
        console.log('always')
    }
    
    //自定义异常
    
    class ErrorApi extends Error{
        constructor(url , ...args){
            super(...args)
            this.url = url
            this.name = 'errorApi'
        }
    }
    
    function getPostData( url = '/post/blogs', code = '404'){
        console.log('开始获取数据...')
        throw new ErrorApi(url, code)
    }
    
    try {
        getPostData()
    } catch (e) {
        let {name, url, message} = e
        console.log(e)
        console.log(name,url,message)
    }
    
    //处理多个异常
    console.clear()
    //自定义异常
    class ErrorApi extends Error{
        constructor(url , ...args){
            super(...args)
            this.url = url
            this.name = 'errorApi'
        }
    }
    
    function getPostData( url = '/post/blogs', code = '404'){
        console.log('开始获取数据...')
        console.log(aaa)
        throw new ErrorApi(url, code)
    }
    
    try {
        getPostData()
    } catch (e) {
        // instanceof 处理不同类型的异常
        if( e instanceof ReferenceError){
            console.log('程序异常')
        }else if(e instanceof ErrorApi){
            console.log('API 异常')
        }
    }


  • 处理多个异常

  • 十九、异步

js代码分同步和异步,同步代码就是比较耗时的操作,同步会一直等待,直到完成,异步代码就是不会等待,会在其他地方执行完毕后,把结果返回给同步执行的地方,常见得异步有setTimeout``fetch``自定义的Promise等

  • setTimeout
    //setTimeout 指定秒后执行
    let timer1 = setTimeout(()=> console.log('1s后执行'), 1000)
    console.log(timer1)
    console.log('第一行代码')
    console.log('第二行代码')
    
    
    //clearTimeout + timerId 中断代码执行
    setTimeout( ()=>{
        if(timer1){
            clearTimeout(timer1)
            console.log('中断了timer1的执行')
        }
    },500)

  • setInterval
    //setInterval 每隔多少秒执行
    let intervalId = setInterval( ()=>{
        let date = new Date()
        console.log(`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`)
    },1000)
    
    //15秒后停止 
    setTimeout(()=>{
        intervalId && clearInterval(intervalId)
    },15000)

  • Promise
//Promsie + then 成功的处理
let delay = (time) => new Promise( succ =>{
    setTimeout( ()=>{ succ('success after ' + time * 1000)}, time * 1000)
})

console.log(1)
delay(2).then( res => console.log(res))
console.log(2)

```
//错误处理
let delay = (time) => new Promise( (succ ,fail)=>{
    setTimeout( ()=>{ fail('fail after ' + time * 1000)}, time * 1000)
})

console.log(1)
delay(2).then( res => console.log(res))
        // .catch( err => console.log(err + )) //捕获错误
console.log(2)

```

    let delay = (time) => new Promise( (succ ,fail)=>{
    setTimeout( ()=>{ fail('fail after ' + time * 1000)}, time * 1000)
})

console.log(1)
delay(2).then( res => console.log(res))
        .catch( err => console.log(err + 'catch 捕获错误')) //捕获错误
console.log(2)


  • 链式调用promise
        //promsie 链式调用 catch 可以写在最后一个then的后面
    // console.log('strat')
    // new Promise( (resolve, reject)=>{
    //     setTimeout(()=>{
    //         resolve(1)
    //     }, 1000)
    // }).then( res =>{
    //     console.log(res) //1
    //     return res + 10
    // }).then( res =>{
    //     console.log(res) //11
    //     return new Promise( resolve => resolve( res + 20))
    // }).then( a =>{
    //     console.log(a) //31 
    // })
    // console.log('end')
    
    // then catch 以后还会返回一个新的promise
    //promsie  catch可以捕获 promise里面 或者then里面的错误 可以写在最后一个then的后面
    console.log('strat')
    new Promise( (resolve, reject)=>{
        setTimeout(()=>{
            // reject('reject in 1')//捕捉 promsie里面的错误
            resolve(1)//捕捉 promsie里面的错误
        }, 1000)
    }).then( res =>{
        console.log(res) //1
        throw 'then 异常'
        return res + 10
    }).then( res =>{
        console.log(res) //11
        return new Promise( resolve => resolve( res + 20))
    }).then( a =>{
        console.log(a) //31 
    }).catch( err =>{
        // console.log(err)//reject in 1
        console.log(err)//then 异常
    })
    console.log('end')
  • 多个promsie 使用Promise.all
        let p1 = new Promise( resolve =>{
        setTimeout( ()=>{
            resolve(1)
        },1000)
    })
    
    let p2 = new Promise( resolve =>{
        setTimeout( ()=>{
            resolve(2)
        },1000)
    })
    
    
    let p3 = new Promise( resolve =>{
        setTimeout( ()=>{
            resolve(3)
        },1000)
    })
    
    Promise.all([p1, p2, p3])
            .then( res =>{
                let [a,b, c] = res
                console.log(a,b,c)
            })

  • async/await 美化异步代码
    console.log(1)
    async function as1(){
        setTimeout( ()=>{
            console.log('as1 执行完毕')
        },1000)
    }
    as1()
    console.log(as1() )
    console.log(2)

    async function as1(){
        try {
            let result2  = await as2()
            let result3  = await as3()
            console.log(result2) // 10 
            console.log(result3) // 333 
        
        } catch (e) {
            console.log(e)
        }
    }
    
    async function as2(){
        return new Promise( resolve =>{
            setTimeout( ()=>{
                resolve(10)
            }, 1000)
        })
    }
    
    async function as3(){
        return new Promise( resolve =>{
            setTimeout( ()=>{
                resolve(333)
            }, 500)
        })
    }
    as1()

二十、模块化TODO

下一步做什么?

- DOM
- AJAX
- 框架学习
- 后端探索?
- 不断学习,不断练习

参考资料: