JS必备知识点

JS必备知识点

将工作中遇到的问题记录在此


  • 数据类型 null对象

    值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
    引用数据类型:对象(Object)、数组(Array)、函数(Function)。

  • NAN数值型

    NaN 即非数值(Not a Number),NaN 属性用于引用特殊的非数字值,该属性指定的并不是不合法的数字。
    NaN 属性 与 Number.Nan 属性相同。
    提示: 请使用 isNaN() 来判断一个值是否是数字。原因是 NaN 与所有值都不相等,包括它自己。

    是Number中的一个值

  • undefined和null的区别

    undefined表示一个未声明的变量,或已声明但没有赋值的变量,或一个并不存在的对象属性。

    nulLL定义并赋值了,只是值为nuLL

  • 数组属不属于对象

    数组是一种特殊类型的对象。 在 JavaScript 中对数组使用 typeof 运算符会返回 “object”。

  • typeof与instanceof区别是什么

    typeof主要用来判断基础数据类型,instanceof则是用来判断引用数据类型。

  • 事件的绑定 三种

    1. 在DOM元素中直接绑定;

    2. 在JavaScript代码中绑定;

    • 3.绑定事件监听函数。

      element.addEventListener()

      使用removeEventListener() 方法来移除 addEventListener() 方法添加的事件句柄。

      element.addEventListener(event, function, useCapture)

      参数描述
      event必须。字符串,指定事件名。注意: 不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”。提示: 所有 HTML DOM 事件,可以查看我们完整的 HTML DOM Event 对象参考手册
      function必须。指定要事件触发时执行的函数。 当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如, “click” 事件属于 MouseEvent(鼠标事件) 对象。
      useCapture可选。布尔值,指定事件是否在捕获或冒泡阶段执行。 可能值: * true - 事件句柄在捕获阶段执行 * false- false- 默认。事件句柄在冒泡阶段执行

      移除 addEventListener() 方法添加的 “mousemove” 事件:

      // 向 <div> 元素添加事件句柄  
      document.getElementById("myDIV").addEventListener("mousemove", myFunction);  
      
      // 移除 <div> 元素的事件句柄  
      
      document.getElementById("myDIV").removeEventListener("mousemove", myFunction);
      
      
  • 鼠标事件哪几个 七个

    事件类型说明
    click单击鼠标左键时发生,如果右键也按下则不会发生。当用户的焦点在按钮上并按了 Enter 键时,同样会触发这个事件
    dblclick双击鼠标左键时发生,如果右键也按下则不会发生
    mousedown单击任意一个鼠标按钮时发生
    mouseout鼠标指针位于某个元素上且将要移出元素的边界时发生
    mouseover鼠标指针移出某个元素到另一个元素上时发生
    mouseup松开任意一个鼠标按钮时发生
    mousemove鼠标在某个元素上时持续发生
  • 事件冒泡,事件捕获

    • 事件冒泡

      冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即: <p> 元素的点击事件先触发,然后会触发 <div> 元素的点击事件。false

    • 事件捕获

      捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即: <div> 元素的点击事件先触发 ,然后再触发 <p> 元素的点击事件。true

  • 事件委托

    事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown…)的函数委托到另一个元素;

    一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。

  • 闭包的概念

    闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。

    直观的说就是形成一个不销毁的栈环境。

    • 写个例子

      var add = (function () {
          var counter = 0;
          return function () {return counter += 1;}
      })();
       
      add();
      add();
      add();
       
      
  • 变量提升

    解析器会先解析代码,然后把声明的变量的声明提升到最前,这就叫做变量提升。

    使用 var 定义的代码,声明会被提升到前面(依旧在函数内部),赋值还在原位置

    ES6之前我们一般使用var来声明变量,提升简单来说就是把我们所写的类似于var a = 123;这样的代码,声明提升到它所在作用域的顶端去执行,到我们代码所在的位置来赋值。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    在这里插入图片描述

    console.log(v1);//undefined
    var v1 = 100;
    
    function foo() {
    
      console.log(v1);//undefined
    
      var v1 = 200;
    
      console.log(v1);//200
    
    }
    
    foo();
    
    console.log(v1); //100
    
    
  • this

    • 在方法中,this 表示该方法所属的对象。

    • 如果单独使用,this 表示全局对象。

    • 在函数中,this 表示全局对象。

    • 在函数中,在严格模式下,this 是未定义的(undefined)。

    • 在事件中,this 表示接收事件的元素。

    • 类似 call() 和 apply() 方法可以将 this 引用到任何对象。

  • getEID和getEclass区别

    id只会获取一个对象

    class会获取一个伪数组

  • 浏览器加载顺序

    1. 用户输入网址(假设是个 HTML 页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回 HTML 文件;

    2. 浏览器开始载入 HTML 代码,发现 <head> 标签内有一个 <link> 标签引用外部 CSS 文件;

    3. 浏览器又发出 CSS 文件的请求,服务器返回这个 CSS 文件;

    4. 浏览器继续载入 HTML 中 <body> 部分的代码,并且 CSS 文件已经拿到手了,可以开始渲染页面了;

    5. 浏览器在代码中发现一个 < img > 标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;

    6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;

    7. 浏览器发现了一个包含一行 JavaScript 代码的 <script> 标签,赶快运行它;

    8. JavaScript 脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个 <div>(style.display=”none”)。杯具啊,突然就少了这么一个元素,浏览器不得不重新渲染这部分代码;

    9. 终于等到了 </html> 的到来,浏览器泪流满面……

    10. 等等,还没完,用户点了一下界面中的“换肤”按钮,JavaScript 让浏览器换了一下 <link> 标签的 CSS 路径;

    11. 浏览器召集了在座的各位 < div><span>< ul>< li> 们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。

  • 回调函数的理解

    回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。

  • 数组创建

    • 字面量方式(json方式)

      var arr1 = [];                    //创建一个空数组
      var arr2 = [5];                   //创建一个具有单个元素的数组
      var arr3 = [5,6,7];               //创建一个具有多个元素的数组
      
      
    • 构造函数方式

      var arr1 = new Array();          //创建一个空数组
      var arr2 = new Array(5);         //创建一个长度为5,值为空的数组
      var arr3 = new Array(5,6,7);     //创建一个具有多个元素的数组
      
  • 数组的方法

    方法名对应版本功能原数组是否改变
    concat()ES5-合并数组,并返回合并之后的数据no
    join()ES5-使用分隔符,将数组转为字符串并返回no
    pop()ES5-删除最后一位,并返回删除的数据yes
    shift()ES5-删除第一位,并返回删除的数据yes
    unshift()ES5-在第一位新增一或多个数据,返回长度yes
    push()ES5-在最后一位新增一或多个数据,返回长度yes
    reverse()ES5-反转数组,返回结果yes
    slice()ES5-截取指定位置的数组,并返回no
    sort()ES5-排序(字符规则),返回结果yes
    splice()ES5-删除指定位置,并替换,返回删除的数据yes
    toString()ES5-直接转为字符串,并返回no
    valueOf()ES5-返回数组对象的原始值no
    indexOf()ES5查询并返回数据的索引no
    lastIndexOf()ES5反向查询并返回数据的索引no
    forEach()ES5参数为回调函数,会遍历数组所有的项,回调函数接受三个参数,分别为value,index,self;forEach没有返回值no
    map()ES5同forEach,同时回调函数返回数据,组成新数组由map返回no
    filter()ES5同forEach,同时回调函数返回布尔值,为true的数据组成新数组由filter返回no
    every()ES5同forEach,同时回调函数返回布尔值,全部为true,由every返回trueno
    some()ES5同forEach,同时回调函数返回布尔值,只要由一个为true,由some返回trueno
    reduce()ES5归并,同forEach,迭代数组的所有项,并构建一个最终值,由reduce返回no
    reduceRight()ES5反向归并,同forEach,迭代数组的所有项,并构建一个最终值,由reduceRight返回no

    链接:https://www.jianshu.com/p/7e160067a06c

  • ==与===的区别

    ===绝对相等,类型数值

    ==类型可自动转化

  • 计时器

    1.在JavaScript中,我们可以在设定的时间间隔之后来执行代码,而不是在函数被调用后立即执行。

    2.计时器类型:

    (1)一次性计时器:仅在指定的延迟时间之后触发一次。

    (2)间隔性触发计时器:每隔一定的时间间隔就触发一次

    3.方法描述

    setTimeout() 指定的延迟时间之后来执行代码

    clearTimeout() 取消setTimeout的设置

    setInterval() 每隔指定的时间执行代码

    clearInterval() 取消setInterval的设置

  • 正则表达式

    • 一、正则表达式概述

      正则表达式(Regular Expression) 是用于匹配字符串中字符串组合的模式,在js中,正则表达式是对象(js万物皆对象) 用于:创建密码 提交表单,匹配字符串,过滤敏感词,提取特定的字符串用于搜索 前端目前主要利用正则表达式来完成表单的验证 通俗来说就是匹配信息主要有精准匹配和模糊匹配两种

    • 二、正则表达式的创建

      两种方式:

      1.RegExp 创建 Var regexp = new RegExp(/123/)
      2.利用正则表达式自变量来创建(最常用的方法) Var rg = /123/
      创建完成肯定要检查字符串是否符合正则表达式。 测试正则表达式text 检测字符是否符合正则表达式 会返回true和false。其参数是测试字符串regexobj .test(str) str是我们写的字符串的内容

    • 三、正则表达式内容具体含义

      因为我也是初学者,就 尽可能用通俗的语言去写,没有使用倒专业名词,请见谅。

      边界符(一般用于精准匹配)

      ^以它开始 $以它结束

      量词符

      *重复零次或更多次
      +重复一次或更多次
      ?重复零次或一次
      {n}重复n次
      {n,}重复n次或更多次
      {n,m}重复n到m次
      - 或者 或|

      括号总结

      中括号字符总结匹配方括号里面的任意字符[] 大括号{ }量词符,里面表示重复次数; 小括号,表示优先级;

      常见的字符简写形式

      \d就是[0-9] 表示一位数字 英文是digit(数字)
      \D[^0-9] 表示除了数字外的任意字符。
      \w[0-9a-zA-Z].表示数字,大小写字母和下划线。记忆方式:w是Word的简写字符
      \W(大写W)[^0-9a-zA-Z].非单词字符。
      \s是[ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式:s是space character的首字母。
      \S是[^ \t\v\n\r\f]。 非空白符。
      .就是[^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号…中的每个点,都可以理解成占位符,表示任何类似的东西。

      i执行对大小写不敏感的匹配。
      g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
      m执行多行匹配。
      元字符描述
      \d查找数字。
      \s查找空白字符。
      \b匹配单词边界。
      \uxxxx查找以十六进制数 xxxx 规定的 Unicode 字符。
      [abc]查找方括号之间的任何字符。
      [0-9]查找任何从 0 至 9 的数字。
      (x|y)查找任何以 | 分隔的选项。
    • 四、常见的正则验证代码

      验证字母:/^[a-zA-Z]+$/

      验证长度为3的字符:/^.{3}$/

      验证由26个英文字母组成的字符串:/^[A-Za-z]+$/

      验证日期YYYY-MM-DD:/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/

      验证邮编:/^\d{6}$/

      验证整数:/^[-+]?\d*$/

      验证小数:/^[-+]?\d+(.\d+)?$/

      验证中文:/^[\u0391-\uFFE5]+$/

      验证邮箱:/^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$/

      验证手机号:/^1[3456789]\d{9}$/

      验证身份证:/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/

    • 五、js中常用的正则表达式

      // 验证输入的内容是否是空
      isNull:function(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /\S/;
      
        if(!regex.test(str)){
      
          alert("文本框不能为空,请输入内容!");
      
        }
      
      }
      
      // 验证输入的字符是否是英文字母
      
        isLetter:function(idStr){
      
          var str = document.getElementById(idStr).value.trim();
      
          var regex = /^[a-zA-Z]+$/;
      
          if(!regex.test(str)){
      
            alert("请输入正确的英文字母!");
      
          }
      
        }
      
      //  验证日期格式是否为YYYY-MM-DD格式
      
      isDate:function(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/;
      
        var r = str.match(regex); // 使用match方法获取指定字符串的值
      
        if(r==null){
      
          alert("请输入正确的日期格式!");
      
        }
      
      }
      
      //  验证日期格式是否为YYYY-MM-DD hh:mm:ss格式
      
      isDateTime:function(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/;
      
        var r = str.match(regex); // 使用match方法获取指定字符串的值
      
        if(r==null){
      
          alert("请输入正确的日期格式!");
      
        }
      
      }
      
      // 验证整数
      
      isInteger:function(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^[-+]?\d*$/;
      
        if(!regex.test(str)){
      
          alert("请输入正确的整数!");
      
        }
      
      }
      
      // 验证双精度
      
      isDouble:function(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^[-+]?\d+(.\d+)?$/;
      
        if(!regex.test(str)){
      
          alert("请输入正确的小数!");
      
        }
      
      }
      
      // 验证中文
      
      isChinese(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^[\u0391-\uFFE5]+$/;
      
        if(!regex.test(str)){
      
          alert("请输入正确的中文!");
      
        }
      
      }
      
      // 验证邮箱
      
      isEmail(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*$/;
      
        if(!regex.test(str)){
      
          alert("请输入正确的邮箱格式!");
      
        }
      
      }
      
      // 验证手机号
      
      isPhone(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^1[3456789]\d{9}$/;
      
        if(!regex.test(str)){
      
          alert("请输入正确的手机号!");
      
        }
      
      }
      
      // 验证身份证
      
      isIdCard(idStr){
      
        var str = document.getElementById(idStr).value.trim();
      
        var regex = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/;
      
        if(!regex.test(str)){
      
          alert("请输入正确的身份证号码!");
      
        }
      
        }
        //注:正则表达式里面不许要加引号,不管是字符串型还是数字型
      
  • 原型原型链

    在这里插入图片描述

  • JS异步同步

    JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

    Promise

    学习异步时,对函数里面的 resolve() 不太理解,后来上网查了查,知道了他的作用:
    Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。
    通过回调里的 resolve(data) 将这个 promise 标记为 resolverd,然后进行下一步 then((data)=>{//do something}),resolve 里的参数就是你要传入 then 的数据。

    new Promise(function (resolve, reject) {
        var a = 0;
        var b = 1;
        if (b == 0) reject("Divide zero");
        else resolve(a / b);
    }).then(function (value) {
        console.log("a / b = " + value);
    }).catch(function (err) {
        console.log(err);
    }).finally(function () {
        console.log("End");
    });
    
  • DOM对象获取

    • 通过 id 找到 HTML 元素

      var x=document.getElementById("intro");
      
    • 通过标签名查找 HTML 元素

      var x=document.getElementById("main");  
      var y=x.getElementsByTagName("p");
      
    • 通过类名找到 HTML 元素

      var x=document.getElementsByClassName("intro");
      
  • 伪数组

    1,function内的arguments 。

    2,通过document.forms,Form.elements,Select.options,document.getElementsByName() ,

    document.getElementsByTagName() ,childNodes/children 等方式获取的集合(HTMLCollection,NodeList)等。

    3,特殊写法的对象 ,如

    Js代码 收藏代码

    var obj={};

    obj[0] = “一”;

    obj[1] = “二”;

    obj[2] = “三”;

    obj.length = 3;

    它们不具有数组的一些方法如push, pop, shift, join等。有时候需要将这些伪数组转成真正的数组,这样可以使用push, pop等方法。

    function log(){  
    var args = Array.prototype.slice.call(arguments); 
    //为了使用unshift数组方法,将argument转化为真正的数组  
    args.unshift('(app)'); console.log.apply(console, args);  
    
    };
    
    
  • ES6

    • let、const和block作用域

      let创建块级作用域

      const创建块级作用域,声明常量

      const 声明的常量类似于指针,它指向某个引用,也就是说这个「常量」并非一成不变的


      • let 关键词声明的变量不具备变量提升(hoisting)特性

      • let 和 const 声明只在最靠近的一个块中(花括号内)有效

      • 当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING

      • const 在声明时必须被赋值

    • 箭头函数

      去掉function在括号后面添加=>

      var getPrice = function() {
        return 4.55;
      };
      // Implementation with Arrow Function
      var getPrice = () => 4.55;
      
      
    • 函数参数默认值

      传入参数时就可以设置默认值

      let getFinalPrice = (price, tax=0.7) => price + price * tax;
      getFinalPrice(500); // 850
      
    • Spread/Rest操作符( …Arr)

      将数组展开

      function foo(...args) {
        console.log(args);
      }
      foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
      
    • 对象词法扩展

      function getCar(make,  value) {
        return {
          // 简写变量
          make,  // 等同于 make: make
          value, // 等同于 value: value
          // 属性可以使用表达式计算值
          ['make' + make]: true,
          // 忽略 `function` 关键词简写对象函数
          depreciate() {
            this.value -= 2500;
          }
        };
      }
      let car = getCar('Barret',  40000);
      // output: {
      //     make: 'Barret',
      //     value: 40000,
      //     makeBarret: true,
      //     depreciate: [Function: depreciate]
      // }
      
    • 二进制和八进制字面量

      数字前面添加 0o 或者0O 即可将其转换为八进制值

      let oValue = 0o10;
      console.log(oValue); // 8
       
      let bValue = 0b10; // 二进制使用 `0b` 或者 `0B`
      console.log(bValue); // 2
      
    • 对象和数组解构

      function foo() {
        return [1,2,3];
      }
      let arr = foo(); // [1,2,3]
       
      let [a, b, c] = foo();
      console.log(a, b, c); // 1 2 3
       
      function bar() {
        return {
          x: 4,
          y: 5,
          z: 6
        };
      }
      let {x: x, y: y, z: z} = bar();
      console.log(x, y, z); // 4 5 6
      
    • 对象超类(没看懂)

      ES6 允许在对象中使用 super 方法:

      var parent = {
        foo() {
          console.log("Hello from the Parent");
        }
      }
       
      var child = {
        foo() {
          super.foo();
          console.log("Hello from the Child");
        }
      }
       
      Object.setPrototypeOf(child, parent);
      child.foo(); // Hello from the Parent
                   // Hello from the Child
      
    • 模板语法和分隔符

      • ${ … } 用来渲染一个变量

      • ` 作为分隔符

      let user = 'Barret'; 
      console.log(Hi ${user}!); // Hi Barret!
      
    • for…of VS for…in

      for…in:遍历键名,会遍历对象的整个原型链,性能差

      for…of:后者遍历键值,只遍历当前对象不会遍历原型链,将异步循环变成同步循环

      在ES5中可以使用forEach循环数组,但无法中途跳出break命令或者return。而使用for…of循环可以与break、continue、return配合使用,跳出循环。

      for…in用来遍历对象而生,不适用数组。

      for…of可以用来遍历数组、类数组对象、字符串、set、Map等。

    • Map 和 WeakMap

      • Map

        • Map 的特点

          • Map 默认情况下不包含任何键,所有键都是自己添加进去的。不同于 Object 原型链上有一些默认的键。

          • Map 的键可以是「任意类型」数据,就连函数都可以。

          • Map 的键值对个数可以「轻易」通过size属性获取,Object 需要手动计算。

          • Map 在频繁增删键值对的场景下「性能」要比 Object 好。

        • 什么时候用 Map

          • 要添加的键值名和 Object 上的默认键值名冲突,又不想改名时,「用 Map」

          • 需要 StringSymbol 以外的数据类型做键值时,「用 Map」

          • 键值对很多,有需要计算数量时,「用 Map」

          • 需要频繁增删键值对时,「用 Map」

        • Map 实例属性和方法

          • set

            set方法设置键名key对应的键值为value,然后会返回整个Map结构,如果设置的key已经存在,则会更新value值,否则会新生成该键

            方法一:

            const dataMap = new Map();
            dataMap.set('name','小黑');
            
            

            方法二:

            const longMap = new Map().set(1,'a').set(2,'b');
            console.log(longMap);
            
          • get

            通过get方法读取key对应的键值,如果传入的键值不存在,则会返回undefined

            const dataMap = new Map();
            dataMap.set('name','小黑');
            console.log(dataMap.get('name'));
            
          • has

            判断传入的键是否存在当前Map对象中,该方法返回一个布尔值

            const dataMap = new Map();
            dataMap.set('name','小黑');
            console.log(dataMap.has('name')); //true
            console.log(dataMap.has('sex')); // false
            
          • delete

            删除传入的键,返回true,如果删除失败,则返回false

            const dataMap = new Map( );
            dataMap. set( 'name' ,'小黑' );
            //在删除之前查询是否存在该键
            console.log(dataMap.has('name'));// true
            //删除该键
            dataMap.delete('name')
            //再次查看是否存在该键,发现已移除
            console.log( dataMap.has('name'));// false
            
            
        • 遍历方法

          可以采用for…of循环和forEach两种方法。由于Map实例会维护键值对的插入顺序,因此可以根据插入顺序进行遍历采用「for…of」

          for…of可以遍历有iterator接口的数据结构

          • keys():返回键名的遍历器

          • values():返回键值的遍历器

          • entries():返回键值对的遍历器

          • forEach():使用回调函数遍历每个成员

        • Map类型转化

          Map 转为数组

          let map = newMap()
          let arr = [...map]
          

          数组转为 Map

          let map = newMap(arr)
          

          Map 转为对象

          let obj = {}
          for (let [k, v] of map) {
            obj[k] = v
          }
          //对象转为 Map
          for( let k ofObject.keys(obj)){
            map.set(k,obj[k])
          }
          
      • WeakMap

        WeakMap是 ES6 中新增的一种集合类型,叫做“弱映射”。它和Map是兄弟关系,与Map的区别就在于这个「弱字」,API 还是Map的那套(只有set get has delete)

        这其实描述的是 JS 中「垃圾回收」程序对待“弱映射”中键的方式

        • WeakMap的特点

          1. WeakMap 只能将对象作为键名

            只接受对象作为键名(null 除外),不接受其他类型的值作为键名

          2. WeakMap 的键名引用的对象是弱引用

            WeakMap 保持了对键名所引用的对象的弱引用,即垃圾回收机制不将该引用考虑在内。只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。

          3. 不可遍历

            正因为WeakMap对键名所引用的对象是弱引用关系,因此WeakMap内部成员是会「却决于垃圾回收机制有没有执行」,运行前后成员个数很可能是不一样的,而垃圾回收机制的执行又是「不可预测」的,因此不可遍历

      • Map 和 WeakMap 的区别

        • Map 的键可以是任意类型,WeakMap 只接受对象作为键(null除外),不接受其他类型的值作为键

        • Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键;WeakMap 的键是弱引用,键所指向的对象可以被垃圾回收,此时键是无效的

        • Map 可以被遍历, WeakMap 不能被遍历

      详解 Map 和 WeakMap 区别以及使用场景_javascript技巧_脚本之家 (jb51.net)

    • Set 和 WeakSet

      • Set

        Set是ES6 提供的新的数据结构。它类似于数组,只有属性值,并且成员的值都是唯一的,没有重复的值

      • WeakSet

        WeakSet 结构与 Set 类似,weakSet的成员值是唯一的,并且 WeakSet 的成员只能是对象,而不能是其他类型的值

      • 传递参数的讲究

        Set、WeakSet传递的参数必须具备迭代接口,比如:数组,字符串,arguments等,迭代接口就是指在原型上有:Symbol(Symbol.iterator)

      • Set 与 WeakSet 之间的区别

        1. 与Set相比,WeakSet 只能是对象的集合,而不能是任何类型的任意值。

        2. WeakSet持弱引用:集合中对象的引用为弱引用。 如果没有其他的对 WeakSet中对象的引用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储当前对象的列表。 WeakSet 是不可枚举的。

      ES6之深入Set 与 WeakSet的知识讲解_huangyangquan3的博客-CSDN博客_weakset和set区别

    • 类是用于创建对象的模板。

      我们使用 class 关键字来创建一个类,类体在一对大括号 {} 中,我们可以在大括号 {} 中定义类成员的位置,如方法或构造函数。

      每个类中包含了一个特殊的方法 constructor(),它是类的构造函数,这种方法用于创建和初始化一个由 class 创建的对象。

      class ClassName {
        constructor() { ... }
      }
      
      使用类

      定义好类后,我们就可以使用 new 关键字来创建对象:

      class People {
        constructor(name, sex) {
          this.name = name;
          this.sex = sex;
        }
      }
       
      let site = new People("小黑",  "男");
      

      创建对象时会自动调用构造函数方法 constructor()。

      类表达式

      类表达式是定义类的另一种方法。类表达式可以命名或不命名。命名类表达式的名称是该类体的局部名称

      // 未命名/匿名类
      let People = class {
         constructor(name, sex) {
          this.name = name;
          this.sex = sex;
        }
      };
      console.log(People.name);
      // output: "People"
       
      // 命名类
      let People = class People2 {
        constructor(name, sex) {
          this.name = name;
          this.sex = sex;
        }
      };
      console.log(People.name);
      // 输出: "People2"
      
      构造方法

      构造方法是一种特殊的方法:

      • 构造方法名为 constructor()。

      • 构造方法在创建新对象时会自动执行。

      • 构造方法用于初始化对象属性。

      • 如果不定义构造方法,JavaScript 会自动添加一个空的构造方法。

      JavaScript 类(class) | 菜鸟教程 (runoob.com)

    • Symbol

      什么是Symbol

      JavaScript标准中规定对象的key只能是 String 或 Symbol 类型,区别在于 String 类型的key可以重复而 Symbol 类型的key是唯一的。Symbol 的本质是表示一个唯一标识。每次创建一个Symbol,它所代表的值都不可能重复,该值的内部实现可以视为一段数字(类似:3423498431987719455…)。所以理论上 Symbol 的存在只有一个意义:用于必须使用唯一值的场景

      创建Symbol

      创建 Number、String等基本类型的实例有两种方法:通过构造函数(或者叫工厂函数)和文字语法糖。比如:

      // 构造函数
      const num = Number(3);
      const str = String(‘hi’);

      // 语法糖
      const num = 3;
      const str = ‘hi’;

      显然使用语法糖更加简洁。但是 Symbol 只能通过构造函数 Symbol() 进行创建:

      const sym = Symbol();

      或者,我们可以传入一个字符串参数(descriptor)用于描述该Symbol:

      const sym = Symbol('cat');

      注意:传入的参数对 Symbol 值的产生并无影响,因为就算每次传入的参数都一样,生成的Symbol值也是不等的。该参数的作用仅用于描述被创建的Symbol,以便debug时可以识别出Symbol的含义。 所以,下列等式结果为 false:

      Symbol(‘cat’) === Symbol(‘cat’) // false
      Symbol.for(key)

      和 Symbol() 类似,Symbol.for(key) 也可以创建一个Symbol,不一样的是:创建的 Symbol 是全局的(在全局Symbol表中注册),而如果全局已经存在相同 key 的Symbol,则直接返回该Symbol。所以,下列等式结果为 true:

      Symbol.for('cat') === Symbol.for('cat') // true

      如何使用Symbol

      其实 Symbol 本身很简单,但是如何把它用好、且用的恰到好处却使人困惑,因为在平常工作中并没有多少非Symbol不用的场景。但是用对了Symbol会对你的代码质量有不少提升。

    • 迭代器(Iterators)

      简介

      迭代器是一种设计模式,可在容器对象 如 链表、数组上遍历,无需关心容器对象的内存分配的实现细节。简单的理解就是可以一个一个的依次拿到其中的数据,类似一个移动的指针,但是会告诉我们什么时候结束。

      js 中的迭代器是什么样子的

      在javascript 中迭代器是一个特殊对象,这个迭代器对象有一个next()方法,每次调用都返回一个对象(结果对象)。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,它是一个布尔类型的值,如果已经迭代到序列中的最后一个值,则它为 true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可用的值,类似下面这个对象的结构。

      {
        next: function () {
              return {
                  value:'',
                  done: true / false
              }  
          }
      } 
      

      迭代协议

      随着javascript 语言的能力进一步提升,新增了一些新的数据类型 如 Map、Set、WeakMap 等,为了这些不同的数据结构,可以统一的迭代,es6 增加了迭代协议这个东西。

      迭代协议并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。

      迭代协议具体分为两个协议:可迭代协议和迭代器协议。

      简单的理解就是在js 中任何对象只要满足迭代协议就可以遍历

      可迭代协议

      要成为可迭代对象, 一个对象必须实现 @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性:

      简单的理解,你想让一个东西可以遍历,那么这个东西要有一个 @@iterator ,这个属性可以通过Symbol.iterator 访问

      属性
      [Symbol.iterator]一个无参数的函数,其返回值为一个符合迭代器协议的对象。

      迭代器协议

      迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。

      只有实现了一个拥有以下语义(semantic)的 next() 方法,一个对象才符合迭代器协议:

      属性
      next一个无参数函数,返回一个应当拥有以下两个属性的对象: done(boolean) next() 方法必须返回一个对象,该对象应当有两个属性: done 和 value,如果返回了一个非对象值(比如 false 或 undefined),则会抛出一个 异常(“iterator.next() returned a non-object value”)。

      迭代过程

      当一个对象需要被迭代的时候(比如被写入一个 for…of 循环时),首先,会不带参数调用它的 @@iterator 方法( 此时返回的是结构是这样的 { next: function () {}}),然后使用此方法返回的迭代器获得要迭代的值(其实就是不断的调用这个next()方法)

      迭代总结

      迭代协议可以总结为,一个东西要遍历,必须满足可迭代协议跟迭代器协议

      • 可迭代协议:这个对象必须有@@iterator,可以通过Symbol.iterator 访问

      • 迭代器协议:是一个对象,这个对象的next() 函数返回一个对象,这个对象包括两个属性,一个是value,一个是done(boolean,是否是最后一个元素,done 为 true 时 value 可省略)

      也就是说 迭代器对象本质上,就是一个指针对象。通过指针对象的next(),用来移动指针。

      自定义迭代

      对象是没有实现迭代器,所以不能遍历对象,为了可以实现对象的遍历,我们需要在对象上实现上面说的迭代器,通常有两种写法,一种是传统的写法,这种需要自己去控制内部的状态,另外一种是利用生成器函数返回的Generator的迭代器来实现,代码如下:

      • 传统写法

        let obj = {
          name: 'joel',
          adress: 'gz',
          [Symbol.iterator]: () => {
             // 这里不要用this, 因为是return fn, this 会丢失
            let index = -1, atrrList = Object.keys(obj);
            const objIterator = {
              next: () => {
                let result = ''
                index++
                if (index < atrrList.length) {
                  result = {
                    value: atrrList[index],
                    done: false
                  }
                } else {
                  result = {
                    done: true
                  }
                }
                return result
              }
            }
            return objIterator
          }
        }
        
        for (const item of obj) {
            console.log('atrrs:' + item + ',value:' + obj[item])
        }
        
        
        
      • 生成器函数写法

        // 为不可迭代的对象添加迭代器
        let obj = {
          a: 1,
          b: 2
        }
        obj[Symbol.iterator] = function* () {
          let keys = Object.keys(obj);
          //取到key值的长度
          let len = keys.length;
          //定义循环变量
          let n = 0;
          //条件判断
          while (n <= len - 1) {
              yield { k: keys[n], v: obj[keys[n]] };
              n++
          }
        }
        //返回的是个对象的key和value
        for (let { k, v } of obj) {
          console.log(k, v);
        }
        
        

      学会javascript之迭代器_javascript技巧_脚本之家 (jb51.net)

    • Generators

      什么是生成器?

      生成器是在函数内部运行的一些代码

      • 返回值后,它会自行暂停,

      • 调用程序可以要求取消暂停并返回另一个值

      这种“返回”不是传统的从函数 return。所以它被赋予了一个特殊的名称——yield。

      在 javascript 中,如果想要使用生成器,则需要:

      • 定义特殊的生成器函数

      • 调用该函数创建一个生成器对象

      • 在循环中使用该生成器对象,或直接调用其 next 方法

      // File: sample-program.js
      //function 后面的 * 告诉 javascript 这是一个生成器函数。
      function *createGenerator() {
       for(let i=0;i<20;i++) {
       yield i
       }
      }
       
      const generator = createGenerator()
       
      console.log(generator.next())
      console.log(generator.next())
      

      如果运行这段代码,则会得到以下输出:

      $ node sample-program.js

      { value: 0, done: false }
      { value: 1, done: false }

      Javascript生成器(Generator)的介绍与使用_javascript技巧_脚本之家 (jb51.net)

    • Promises

      什么是 Promise

      Promise 是抽象的异步处理对象,以及对其进行各种操作的组件。

      Javascript 为什么要引入 Promise

      有了Promise对象,就可以将异步操作以同步操作的流程表达出来。 这样在处理多个异步操作的时候还可以避免了层层嵌套的回调函数。 此外,Promise对象提供统一的接口,必须通过调用 Promise#thenPromise#catch 这两个方法来结果,除此之外其他的方法都是不可用的,这样使得异步处理操作更加容易。

      基本用法

      三种办法创建 Promise 实例(对象)

      1. 构造方法

        let promies = new Promise((resolve, reject) => {
         resolve(); //异步处理 
        });
        
        
      2. 通过 Promise 实例的方法,Promise#then 方法返回的也是一个 Promise 对象

        promise.then(onFulfilled, onRejected);
        
      3. 通过 Promise 的静态方法,Promise.resolve(),Promise.reject()

        var p = Promise.resolve();
        p.then(function(value) {
         console.log(value); 
        });
        

      Promise 的状态

      Fulfilled: has-resolved, 表示成功解决,这时会调用 onFulfilled.

      Rejected: has-rejected, 表示解决失败,此时会调用 onRejected.

      Pending: unresolve, 表示待解决,既不是resolve也不是reject的状态。也就是promise对象刚被创建后的初始化状态.

      在这里插入图片描述

      Javascript Promise用法详解_javascript技巧_脚本之家 (jb51.net)

  • 函数和方法的区别

    函数(function)是一段代码,需要通过名字来进行调用。它能将一些数据(函数的参数)传递进去进行处理,然后返回一些数据(函数的返回值),也可以不返回数据。

    方法(method)是通过对象调用的javascript函数。也就是说,方法也是函数,只是比较特殊的函数。

    当将函数和对象和写在一起时,函数(function)就变成了方法(method)。只能对象里方法形式,方法里在函数形式写法,不能对象里函数,正确写法:

    结果:这是一个 this指向的问题,第一个:{m: ƒ} ,第二个:window

    var o={                       //对象
           m:function(){          //方法
               console.log(this);
                f();              //方法里可以函数
                f:function f(){
                    console.log(this)
                }
           }
       }
      o.m();    //对象o的m方法,this作为方法被调用,指向调用它的对象。
                //作为函数调用指向window,或undefined(严格模式)   
    
  • 模块开发

    • commons js 模块化开发

      exports导出 (module.exports={ … 导出方法 …})

      require 导入 (const m = require(‘./路径’))

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值