# JS

# 参考文档

# Nodejs 安装

// todo

# 基本语法

# 语句

  • JS 执行单位是行,它一行一行的读取并执行代码。一般情况下每一行是一个语句。语句以分号结尾,一行可以写多句,然后用分号隔开。分号前面可以没有东西,默认被读取成空语句。

  • JS 分成语句和表达式,如果后边以分号结尾的话,那么就被读取语句。

# 变量

  • JS 区分大小写。

  • 如果只是声明变量而没有赋值,则该变量的值是 undefined。undefined 是一个特殊的值,表示“无定义”。

  • 动态类型,变量的类型可以改变。

  • 变量名可以是中文。

  • 变量提升,JS 引擎解析的时候,会先把变量的声明先加载,然后再一行一行的执行程序。

  • else 代码块总是与离自己最近的那个if语句配对。

  • 标签

    label:
        语句
    
    1
    2

# 数据类型

# 六种类型

查看一个对象本身的所有属性,可以使用 Object.keys 方法。

注意,删除一个不存在的属性,delete 不报错,而且返回 true。

delete 命令只能删除对象本身的属性,无法删除继承的属性

  • number 数值,整数和小数。
    • JavaScript 内部,所有数字都是以 64 位浮点数形式储存,即使整数也是如此。所以,1 与 1.0 是相同的,是同一个数。
    • NAN,不是数字,NAN 不等于任何值,包括本身。
    • Infinity 表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非 0 数值除以 0,得到 Infinity。
    • parseInt 方法用于将字符串转为整数。
  • string 字符串,文本。
    • 在非特殊字符前面使用反斜杠,则反斜杠会被省略。如果需要使用到反斜杠的话,通过 \\ 转义自身的方式输出。
  • boolean 布尔值 ,true 和 false。
    • 注意: 空对象的布尔值为 true。
  • undefined,表示未定义和不存在,即还未定义,此处还没有任何值。
  • null,表示空值。
  • object 对象,各种值的集合。
    • 狭义的对象 object
    • 数组 array
    • 函数 function

数值、字符串、布尔值,三种叫做原始类型。

# type of 运算符

JavaScript 有三种方法,可以确定一个值到底是什么类型。

  • typeof 运算符
    • 返回一个值的数据类型。
  • instanceof 运算符
  • Object.prototype.toString 方法

# 对象

属性

  • 读取

    • 点取值
    • 双引号取值
    • 查看对象所有属性,Object.keys

    如果一个对象 obj,它有一个属性 p = 'zhang',那么取值方式有两种,obj.p 或者是 obj['p'] ,后面用方括号取值的方式中,注意,方括号中的属性名要加引号,不然的话就会被识别为变量。方括号中可以使用表达式。

  • 属性是否存在:in 运算符。

  • for...in 循环用来遍历一个对象的全部属性。

    • 注意,检查的是键名,不是键值
    • 例如: 'p' in obj // true,注意,这里继承的属性也会返回 true。
  • delete 命令用于删除对象的属性,删除成功后返回true。

    • 例如 delete obj.p
  • length 属性返回字符串的长度。

  • JavaScript 引擎无法确定是对象还是代码块,一律解释为代码块。可以在整个式子的外面加上一个 (),这时它被解析成一个对象。

  • with 语句

    格式:

    with (对象) {
      语句;
    }
    
    1
    2
    3
  • valueOf() 查看对象的原始类型的值。

# 函数

# 函数的声明 (3 种)

  • function 命令

    格式:

    function print(s) {
      console.log(s);
    }
    
    1
    2
    3
  • 函数表达式(匿名函数)

    var print = function(s) {
      console.log(s);
    };
    
    1
    2
    3

    这里可以不要函数名,如果给了函数名的话,那么函数名只在函数体内生效。

  • Function 构造函数

    var add = new Function(
      'x',
      'y',
      'return x + y'
    );
    // 等同于
    function add(x, y) {
      return x + y;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。

如果一个函数被重复声明,那么这个后面的声明会覆盖前面的。函数和值的地位同等

因为函数和值的地位相等,所以函数和值一样,也有函数名的提升,即运行之前先将函数进行声明。但是,如果采用赋值语句定义函数,JavaScript 就会报错。

# 函数属性

  • name 属性返回函数的名字。
  • length 属性返回函数预期传入的参数个数,即函数定义之中的参数个数。
  • toString() 方法返回一个字符串,内容是函数的源码。

# 作用域

作用域(scope)指的是变量存在/生效的范围。

  • var 命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。

# 参数

  • 省略参数

    • 只可以省略后面的。
  • 传递方式

    • 原始类型(数值、字符串、布尔值),传植传递。
    • 复合类型(数组、对象、其他函数),地址传递。
      • 注意,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。

        例如:

        var obj = [1, 2, 3];
        function f(o) {
        o = [2, 3, 4];
        }
        f(obj);
        obj // [1, 2, 3]
        
        1
        2
        3
        4
        5
        6

        上面代码中,在函数 f() 内部,参数对象 obj 被整个替换成另一个值。这时不会影响到原始值。这是因为,形式参数(o)的值实际是参数 obj 的地址,重新对 o 赋值导致 o 指向另一个地址,保存在原地址上的值当然不受影响。

  • 同名参数

    • 如果有同名的参数,则取最后出现的那个值。
    • 如果要传入两个同名参数,只传入了第一个值,那么这个参数的取值就成了 undefined。
  • 取参数

    • arguments 对象包含了函数运行时的所有参数,arguments[0] 就是第一个参数,arguments[1] 就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。

# 闭包

闭包简单理解成“定义在一个函数内部的函数”。

闭包最大的特点,就是它可以“记住”诞生的环境,比如 f2 记住了它诞生的环境 f1,所以从 f2 可以得到 f1 的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的另一个用处,是封装对象的私有属性和私有方法。

注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

# IIFE

根据 JavaScript 的语法,圆括号 () 跟在函数名之后,表示调用该函数。比如,print() 就表示调用 print 函数。

有时,我们需要在定义函数之后,立即调用该函数。这时,你不能在函数的定义之后加上圆括号,这会产生语法错误。产生这个错误的原因是,function 这个关键字既可以当作语句,也可以当作表达式。

解决办法是:把整个式子用圆括号包起来,这样的话,引擎就会将括号内的内容识别为表达式。

# 数组

# 简介

index 从 0 开始。

格式:

    var arr = ['a', 'b', 'c']; // 一维数组
1
    var a = [[1, 2], [3, 4]]; // 二维数组
    a[0][1] // 2
    a[1][1] // 4
1
2
3

# 数组的键

  • JavaScript 语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。之所以可以用数值读取,是因为非字符串的键名会被转为字符串。

  • 对象有两种读取成员的方法:点结构(object.key)和方括号结构(object[key])。但是,对于数值的键名,不能使用点结构。

# length 属性

  • length 属性,返回数组的成员数量。
  • 该属性是一个动态的值,等于键名中的最大整数加上 1。
  • 数组的数字键不需要连续。它是一种动态的数据结构,可以随时增减成员。
  • length 属性是可写的。
    • 这样的话,直接设置 length 为 0,就表示清空这个数组。

    • 如果将值扩大,那么将会自动填充空值(undefined)。

    • 例如:

      var arr = [ 'a', 'b', 'c' ];
      arr.length // 3
      arr.length = 2;
      arr // ["a", "b"]
      
      1
      2
      3
      4

# in 运算符

  • 键名是否存在的运算符 in,适用于对象,也适用于数组。

  • 例如:

    var arr = [ 'a', 'b', 'c' ];
    2 in arr  // true
    '2' in arr // true
    4 in arr // false
    
    1
    2
    3
    4
  • 注意,如果数组的某个位置是空位,in 运算符返回 false。

# for...in 遍历

  • for...in 循环不仅可以遍历对象,也可以遍历数组,毕竟数组只是一种特殊对象。
  • 在遍历时,也会遍历到非整数键。
  • 可以考虑使用 for 循环或 while 循环。
  • forEach () 方法也可以。

# 空位

  • 空位不影响 length。
  • 空位与 undefined,是不一样的。如果是空位,使用数组的 forEach 方法、for...in 结构、以及 Object.keys 方法进行遍历,空位都会被跳过。

实例:

    var array = [ , 2, undefined, ,]
    console.log(array) // [ <1 empty item>, 2, undefined, <1 empty item> ]
    console.log(array.length) // 4
    delete array[2]
    console.log(array) // [ <1 empty item>, 2, <2 empty items> ]
    console.log(array.length) // 4
1
2
3
4
5
6

# 运算符

# 算数运算符

  • x + y 加法运算符

    • 相加

    • 连接

      实例:

      '3' + 4 + 5 // "345"
      3 + 4 + '5' // "75"
      
      1
      2
  • x - y 减法运算符

  • x * y 乘法运算符

  • x / y 除法运算符

  • x ** y 指数运算符

    • 右结合

      // 相当于 2 ** (3 ** 2)
      2 ** 3 ** 2
      // 512
      
      1
      2
      3
  • x % y 余数运算符

    • 正负号由前面的值的正负号决定。
  • ++x 或者 x++ 自增运算符

  • --x 或者 x-- 自减运算符

  • +x 数值运算符

  • -x 负数值运算符

# 比较运算符

  1. 先看两个运算子是否都是字符串,如果是的,就按照字典顺序比较(实际上是比较 Unicode 码点);
  2. 否则,先将两个运算子都转成数值,再比较数值的大小。
  • > 大于运算符

  • < 小于运算符

  • <= 小于或等于运算符

  • >= 大于或等于运算符

  • == 相等运算符

    • 实例:
        1 == true // true
        // 等同于 1 === Number(true)
    
        0 == false // true
        // 等同于 0 === Number(false)
    
        2 == true // false
        // 等同于 2 === Number(true)
    
        2 == false // false
        // 等同于 2 === Number(false)
    
        'true' == true // false
        // 等同于 Number('true') === Number(true)
        // 等同于 NaN === 1
    
        '' == 0 // true
        // 等同于 Number('') === 0
        // 等同于 0 === 0
    
        '' == false  // true
        // 等同于 Number('') === Number(false)
        // 等同于 0 === 0
    
        '1' == true  // true
        // 等同于 Number('1') === Number(true)
        // 等同于 1 === 1
    
        '\n  123  \t' == 123 // true
        // 因为字符串转为数字时,省略前置和后置的空格
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
  • === 严格相等运算符

    • 注意,对于两个对象的比较,严格相等运算符比较的是地址,而大于或小于运算符比较的是值。
  • != 不相等运算符

  • !== 严格不相等运算符

# 布尔运算符

  • ! 取反运算符
    • 两次取反,将一个值转化成对应的布尔值。
  • && 且运算符
  • || 或运算符
  • ? : 三元运算符

# 二进制/位运算符

位运算符只对整数起作用,如果一个运算子不是整数,会自动转为整数后再执行。另外,虽然在 JavaScript 内部,数值都是以64位浮点数的形式储存,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。

  • | 或(or)
  • & 与(and)
  • ~ 否/取反(not)
    • 连续两次取反,得到取整后的数值。
  • ^ 异或(xor)
  • << 左移(left shift)
  • >> 右移(right shift)
  • >>> 头部补零的右移(zero filled right shift)

# 其他运算符

  • void

    格式:

    void (内容)
    
    1

# 运算顺序

使用 () 提高运算优先级。

# 语法

# 数据类型转换

  • Number(),将任意类型的值转化成数值。

    • 注意:null 转为数值时为 0,而 undefined 转为数值时为 NaN。

    • 参数是对象时,将返回 NaN,除非是包含单个数值的数组。

    • 整体转换,parseInt() 逐个转换。

    • 自动过滤一个字符串前导和后缀的空格。

    • 实例:

      console.log(Number('12qw')) // NaN
      console.log(parseInt('12qw')) // 12
      
      1
      2
  • String(),将任意类型的值转化成字符串。

  • Boolean(),将任意类型的值转为布尔值。

# 错误处理机制

  • Error() 构造函数

    • message:错误提示信息
    • name:错误名称(非标准属性)
    • stack:错误的堆栈(非标准属性)
  • Error() 的派生对象

    • SyntaxError 对象是解析代码时发生的语法错误。
    • ReferenceError 对象是引用一个不存在的变量时发生的错误。
    • RangeError 对象是一个值超出有效范围时发生的错误。
    • TypeError 对象是变量或参数不是预期类型时发生的错误。
    • URIError 对象是 URI 相关函数的参数不正确时抛出的错误,主要涉及 encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape() 和 unescape() 这六个函数。
  • 自定义错误

    • 实例:

      function UserError(message) {
        this.message = message || '默认信息';
        this.name = 'UserError';
      }
      UserError.prototype = new Error();
      UserError.prototype.constructor = UserError;
      
      1
      2
      3
      4
      5
      6
  • throw 语句

  • try...catch 结构

    • catch 代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。但是在 try 代码块中,throw 的后面不执行,catch 后边的代码会继续执行。
  • finally 语句

    • try...catch 结构允许在最后添加一个 finally 代码块,表示不管是否出现错误,都必需在最后运行的语句。
    • 如果出现错误,那么将执行完 finally 中的代码,才会继续报错。

# console 对象与控制台

# 静态方法

  • console.log(),console.info(),console.debug()

    • console.debug方法与console.log方法类似,会在控制台输出调试信息。但是,默认情况下,console.debug输出的信息不会显示,只有在打开显示级别在verbose的情况下,才会显示。
  • console.warn(),console.error()

  • console.table()

    • 对于某些复合类型的数据,console.table方法可以将其转为表格显示。

      实例:

      var languages = [
        { name: "JavaScript", fileExtension: ".js" },
        { name: "TypeScript", fileExtension: ".ts" },
        { name: "CoffeeScript", fileExtension: ".coffee" }
      ];
      console.table(languages)
      
      1
      2
      3
      4
      5
      6
  • console.count()

    • 方法用于计数,输出它被调用了多少次。
  • console.dir(),console.dirxml()

    • dir 对一个对象进行检查(inspect),并以易于阅读和打印的格式显示。
  • console.assert()

    • 主要用于程序运行过程中,进行条件判断,如果不满足条件,就显示一个错误,但不会中断程序执行。这样就相当于提示用户,内部状态不正确。它接受两个参数,第一个参数是表达式,第二个参数是字符串。只有当第一个参数为 false,才会提示有错误,在控制台输出第二个参数,否则不会有任何结果。
  • console.time(),console.timeEnd()

    • 成对使用
  • console.group(),console.groupEnd(),console.groupCollapsed()

  • console.trace(),console.clear()

    • trace 显示当前执行的代码在堆栈中的调用路径。
    • clear 清除当前控制台的所有输出,将光标回置到第一行。如果用户选中了控制台的“Preserve log”选项,console.clear 方法将不起作用。

# 控制台命令 API

# debugger 语句

  • debugger 语句主要用于除错,作用是设置断点。如果有正在运行的除错工具,程序运行到 debugger 语句时会自动停下。如果没有除错工具,debugger 语句不会产生任何结果,JavaScript 引擎自动跳过这一句。

    Chrome 浏览器中,当代码运行到 debugger 语句时,就会暂停运行,自动打开脚本源码界面。

# 标准库

# Array 对象

  • Array.isArray 方法返回一个布尔值,表示参数是否为数组。

  • push(),新增,在尾部。并返回新增的值。参数为要添加的值。

  • pop(),移除,在尾部。无参数。返回删除的值。

  • shift(),删除第一个元素,并返回。

  • unshift(),在第一位添加元素,并返回新数组的长度。

  • join(),以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。

  • concat(),连接,将新数组放在后面。

  • reverse(),倒序排列。

  • slice(),提取一部分,参数为(start,end)。参数为负数,则表示倒数。

  • splice(),删除并插入新数据,参数为(start,删除的个数,要插入的数据)。返回删除的数据。

    只是单纯地插入元素,splice 方法的第二个参数可以设为 0,如果只提供第一个参数,等同于将原数组在指定位置拆分成两个数组。并返回从指定位置一直截取到最后的数组。原数组只剩下截取后剩下的。

  • sort(),不是按照大小,而是按照字典排序。

    • 接受函数进行排序,sort 的参数函数本身接受两个参数,表示进行比较的两个数组成员。如果该函数的返回值大于 0,表示第一个成员排在第二个成员后面;其他情况下,都是第一个元素排在第二个元素前面

    • 实例:

      [
        { name: "张三", age: 30 },
        { name: "李四", age: 24 },
        { name: "王五", age: 28  }
      ].sort(function (o1, o2) {
        return o1.age - o2.age;
      })
      // [
      //   { name: "李四", age: 24 },
      //   { name: "王五", age: 28  },
      //   { name: "张三", age: 30 }
      // ]
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
  • map()

    • 将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。

    • 实例:

      var numbers = [1, 2, 3];
      
      numbers.map(function (n) {
        return n + 1;
      });
      // [2, 3, 4]
      
      numbers
      // [1, 2, 3]
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
    • 接受一个函数作为参数。该函数调用时,map() 方法向它传入三个参数:当前成员、当前位置和数组本身。即 elem, index, arr

    • 接受第二个参数,用来绑定回调函数内部的 this 变量。

      实例:

      var arr = ['a', 'b', 'c'];
      
      [1, 2].map(function (e) {
        return this[e];
      }, arr)
      // ['b', 'c']
      
      1
      2
      3
      4
      5
      6
  • forEach()

    • 不会跳过 undefined 和 null,但会跳过空位。

    • 参数是一个函数、

      实例:

          var array = [9, 8, 2, 78, 69, 2, 58];
      
          array.forEach(function (x, index) {
              console.log( x + '=' + index);
          })
      
      1
      2
      3
      4
      5
  • filter()

    • 过滤数组成员,满足条件的成员组成一个新数组返回。

    • 实例:

      var array = [1, 2, 3]
      
      console.log(
        array.filter(function (x) {
        return x > 2;
      }));
      
      1
      2
      3
      4
      5
      6
  • some(),every()

    • some 方法是只要一个成员的返回值是 true,则整个 some 方法的返回值就是 true,否则返回 false。
    • every 方法是所有成员的返回值都是 true,整个 every 方法才返回 true,否则返回 false。
  • reduce(),reduceRight()

  • indexOf(),lastIndexOf()

    • 元素在数组中第一次出现的位置,如果没有出现则返回 -1。
    • last 用于检测数组中有两个相同的值,最后一次出现的位置。

# String 对象

  • concat(),连接,将新字符串添加在后面。如果参数不是字符串,则会先转成字符串再连接。
  • slice(),提取一部分,参数为(start,end)。start > end 的时候,会返回空串。
  • subString(),参数为(start,end),返回结果不包含 end 位置,即到 end 的前一个位置的字符。
  • indexOf(),用于确定一个字符串在另一个字符串中第一次出现的位置,返回结果是匹配开始的位置。如果返回 -1,就表示不匹配。可以接受第二个参数,表示从该位置开始向后匹配。
  • trim(),用于去除字符串两端的空格,返回一个新字符串,不改变原字符串。
  • toLowerCase() toUpperCase(),转化大小写。

# Math 对象

  • Math.abs() 绝对值
  • ceil() 向上取整
  • floor() 向下取整
  • max() 最大值
  • min() 最小值
  • pow() 幂运算
  • sqrt() 平方根
  • log() 自然对数
  • exp() e 的指数
  • round() 四舍五入
  • random() 随机数

# Json 对象

值的要求

  • 复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
  • 原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和 null(不能使用 NaN, Infinity, -Infinity 和 undefined)。
  • 字符串必须使用双引号表示,不能使用单引号。
  • 对象的键名必须放在双引号里面。
  • 数组或对象最后一个成员的后面,不能加逗号

静态方法

  • JSON.stringify(),将一个值转为 JSON 字符串。
  • JSON.parse(),还原符合 JSON 格式的字符串。

# 面向对象编程

# 异步操作

# 单线程模型

  • 事件循环机制,Event Loop。

# 同步和异步

程序里面所有的任务,可以分成两类:同步任务(synchronous)和异步任务(asynchronous)。

# 异步操作

模式

  • 回调函数
  • 事件监听
  • 发布/订阅

流程控制

  • 串行执行
  • 并行执行
  • 并行与串行结合

# 定时器

  • setTimeout() 用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号,以后可以用来取消这个定时器。

    • 实例:

      function a() {
        console.log(22222)
      }
      console.log('hello');
      setTimeout(a, 1000);
      console.log('hi')
      // 先输出1和3,然后等待1000毫秒再输出2。
      
      1
      2
      3
      4
      5
      6
      7

      实例 2:

      setTimeout(function () {console.log(111111);}, 0)
      console.log(2222);
      console.log(3333);
      // 2222
      // 3333
      // 111111
      
      1
      2
      3
      4
      5
      6

      注意: 必须要等到当前脚本的同步任务,全部处理完以后,才会执行setTimeout指定的回调函数f。也就是说,setTimeout(f, 0)会在下一轮事件循环一开始就执行。

  • setInterval(),定时执行无限次。

  • setTimeoutsetInterval(),都返回一个整数值,表示计数器编号。将该整数传入clearTimeout和clearInterval函数,就可以取消对应的定时器。

  • debounce (防抖动)

# DOM

# 事件

# 浏览器模型

# 讨论区

由于评论过多会影响页面最下方的导航,故将评论区做默认折叠处理。

点击查看评论区内容,渴望您的宝贵建议~
Last Updated: 12/19/2023, 5:04:08 PM