# 变量

声明:使用关键词生成局部变量/不使用关键词生成全局变量。

运算:undefined在boolean中为false,在number中则为NaN,对应的null则会转为0,boolean中同样为false。

变量提升:

  • var:允许先使用变量后声明变量,但使用时变量的值为undefined
  • const/let:同样会被提升到代码块的顶部但是不会赋予初始值,使用时会抛出错误(ReferenceError)。这个变量从代码块一开始时处于一个“暂时性死区”,直到这个变量被声明为止。
  • 函数:函数声明(直接用function定义函数)会被提升到顶部,但函数表达式(var baz = function(){})无法被提升,哪怕是用var定义。

# 数据类型与结构

基本数据类型: boolean、null、undefined、number、bigInt、string、symbol、object

数据类型的转换:

  • 数字转字符串:+运算符即可,注意-运算符时会将string转为number。
  • 字符串转数字:一元加法运算符
 (+"1.1") + (+"1.1") = 2.2;
// 加入括号是为了清楚展示,并非必需的

# 字面量

字面量是脚本中按字面意思给出的固定的值,而不是变量。 注意:

  1. 在es6中,对象字面值扩展了:支持在创建时设置原型、简化了属性值与属性名相同时的写法、方法定义、支持父方法调用以及动态计算属性名
let obj = {
  // __proto__ 设置原型
  __proto__: theProtoObj,
  // Shorthand for ‘handler: handler’
  handler,
  // Methods
  toString() {
      // Super calls
      return "d " + super.toString();
  },
  // Computed (dynamic) property names 动态属性名
  ["prop_" + (() => 42)()]: 42,
};

2.在字符串字面值上使用字符串对象的所有方法,js会自动将字符串字面值转换一个临时的字符串对象,调用该方法,然后废弃到临时的字符串对象。在字符串中使用的特殊字符

字符 意思
\0 Null字节
\b 退格符
\f 换页符
\n 换行符
\r 回车符
\t Tab
\v 垂直Tab
' 单引号
'' 双引号
\ \

# 异常处理语句

  1. throw语句 使用throw语句抛出一个异常,当你抛出异常,一个含有值的表达式要被抛出
throw "Error2"; // String type
throw 42; // Number type
throw true; // Boolean type
throw {
  toString: function () {
    return "I'm an object!";
  },
};
// 抛出异常时声明一个对象,catch中可以查询到对象属性
// Create an object type UserException
function UserException(message) {
  this.message = message;
  this.name = "UserException";
}

// Make the exception convert to a pretty string when used as
// a string (e.g. by the error console)
UserException.prototype.toString = function () {
  return this.name + ': "' + this.message + '"';
};

// Create an instance of the object type and throw it
throw new UserException("Value too high");

  1. try...catch 一个或多个try+0个或1个catch try中语句块若抛异常,立即进入catch语句块 try中语句块无异常,则跳过catch语句块 finally语句块在try...catch后执行,finally返回的值,将是整个try-catch-finally流程返回值,不管try...catch发生了什么
  2. 使用Error对象 根据错误类型,可以使用'name'和'message'获取信息,name提供了常规的错误类,而message提供了一条错误对象转字符串的简明信息。抛出个人异常的时候,应该使用Error构造函数
throw (new Error('出错了'))

# 循环

# 循环的几种方式

  • for
  • do...while
  • while
  • for...in
  • for...of

# label语句

添加label可以跳出整个循环,如

outPoint: for (var i = 0; i < 10; i++) {
  for (var j = 0; j < 10; j++) {
    if (i == 5 && j == 5) {
      break outPoint; // 在 i = 5,j = 5 时,跳出所有循环,
      // 返回到整个 outPoint 下方,继续执行
    }
    num++;
  }
}
// 此时num是55;跳出outPoint标识的循环,如果是continue,则是跳出本次循环,并跳转到标签后的循环内

# for...in与for...of的区别

  • for...in:循环一个指定变量来循环一个对象的所有可枚举属性
  • for...of:在可迭代对象上创建一个循环,对值的每一个独特属性调用一个迭代。

for...in循环数组的结果是元素的下标,而for...of是元素的值

# 函数

# 定义函数

  • 函数声明:function关键词+函数名
  • 函数表达式:
// 匿名函数
const func = function(){}
// 非匿名函数,为function提供名称,可以通过该名字调用。
const func = function fac(n){
n++;
return n>2?2:fac(n);
}
  • Function对象构造函数:直接调用此构造函数可以动态创建函数,但构造函数创建的函数只能在全局作用域中运行。因此不会创建当前环境的闭包,因为它们总是被创建于全局环境。也就不能访问它们被构造函数创建时所在的作用域变量。
  • 自定义构造函数:通过new关键词,首先创造出一个新的对象,然后将该对象的上下文作为构造函数的this。最后再将得到的对象返给变量
function getNewStudent(){
    this.name =function(){
        return this    
    }
    return 1
}
const student = new getNewStudent(); //{ name:function(){return this}}
const student1 = getNewStudent() //1

注意:当构造函数的返回值是一个对象时,对传入的this设置的任何操作都无效,最终new 返回的就是这个指定对象而不是额外构造的对象。仅当值的类型不为对象时,构造函数将无视返回值,返回一个构造完毕的对象。

# 调用函数

函数根据调用方式分为三种

  • 立即执行函数
  • 方法
  • 构造函数

不同类型函数调用之间的区别主要在于:隐式传入的this指向不同,方法中的函数传入对象,立即执行函数传入window,构造函数传入对象实力。而apply和call可以显示地传递this指向。唯一的区别就是apply的传参是数组形式,call是列表形式。第一个参数是this指向,剩余参数就是函数的传参。

juggle.apply(ninja,[1,2,3,4]);
juggle.call(ninja,1,2,3,4);`

# 闭包与作用域链

在一个函数内嵌套一个函数,嵌套函数对于容器函数来说是私有的,而嵌套函数自身也形成了一个闭包。

闭包的概念:封闭了表达式,闭包可以拥有独立变量以及绑定了这些变量的环境的表达式。嵌套函数可以“继承”容器函数的参数和变量,也就是包含了容器函数的作用域。容器函数却不能使用它的参数和变量。

作用域链:多层嵌套函数的关系中,如a中嵌套了b,b中嵌套了c,那么c的闭包包含了b的函数作用域,但是由于b的闭包包含了a的函数作用域,因此它们递归的包含了所有包含它的作用域,这就是作用域链。

在作用域链中,链的第一个元素就是最里面的作用域,最后一个是最外层的,所以当变量命名冲突时,更近的作用域拥有更高的优先级。

当然,由于这种优先级的存在,一旦出现冲突,内部函数将无法访问外部函数的这个变量,因为已经被内部函数的同名变量覆盖了。

# arguments对象

arguments对象保存函数的实参数,它是一个类数组,它可以使用索引访问数组,也可以使用数组的length属性,但是不具备其他Array对象的数组操作方法,所以称为类数组。

# 函数参数

  • 默认参数:参数设置默认值,不设置即为undefined
function multiply(a, b = 1) {
  return a * b;
}
  • 剩余参数:使用...收集剩余的参数进一个数组。
function multiply(multiplier, ...theArgs) {
  return theArgs.map((x) => multiplier * x);
}

const arr = multiply(2, 1, 2, 3);

# 表达式与运算符

# 逻辑运算符

运算符 范例 说明
逻辑与&& a&&b a为true时,返回b
逻辑或|| a||b a为false时,返回b
逻辑非! !a 返回true/false

注:短路求值的时候第二个表达式不会执行(如true||表达式)

# 一元操作符

  • delete 删除一个对象的属性或者数组中的一个值。如果操作成功,返回true。删除数组中的元素时,只是将该索引的值变为了undefined,数组长度不变。
delete objectName.property;
delete objectName[index];
  • typeof 返回一个表示类型的字符串
// 返回string和boolean,字符串和布尔值,包括String()和Boolean()
typeof true; // returns "boolean"
typeof "Hello world"; // returns "string"
typeof String(1) // returns 'string'
// 返回number和bigint
typeof 62; // returns "number" 
typeof 42n // returns 'bigint' 
typeof NaN // returns 'number' NaN返回数字类型
// 返回symbol,包括Symbol()
typeof Symbol('foo') // returns 'symbol'
// 返回undefined,包括不存在的变量或属性
typeof undefined // 'undefined'
typeof ttttttt // 'undefined'
// 返回function,包括es6的class、各个内置对象本身除了Math,以及Function(),new Function()
typeof class cs {} // returns 'function'
typeof parseInt; // returns "function"
typeof Date; // returns "function" 内置对象返回function类型
typeof Function; // returns "function"
typeof Option; // returns "function"
typeof String; // returns "function"
// 返回object,对象、数组、null、正则表达式,还有Math和JSON本身,还有使用new操作符的数据,除了Function以外
typeof null; // returns "object" null返回为对象类型
typeof Math; // returns "object"
typeof /d/ // returns 'object'

注意: 1、在let和const之前无法typeof,会报错 2、typeof null的解释: 在JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于null代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"。 3、typeof无法精确判断出null、数组、对象、正则的类型,若想精准判断类型,需要使用Object.prototype.toString.call 4、BigInt类型 BigInt 来自于 ES11 增加的一种最新的基础类型,可以用任意精度表示整数。 它提供了一种表示大于 2^53 - 1 整数的方法,能表示任意大的整数。 它是通过在整数末尾附加 n 或调用构造函数 BigInt() 来创建的。 IE 不支持。 无法与number进行混合运算,会报类型错误

  • void 表示一个运算没有返回值

# 关系运算符

  • in 指定属性存在于指定对象中,则返回true
var mycar = { make: "Honda", model: "Accord", year: 1998 };
"make" in mycar; // returns true
  • instanceof 如果所判别的对象确实是所指定的类型,则返回true
objectName instanceof objectType;

# 正则表达式

# 创建正则表达式

var re = /ab+c/;
var re = new RegExp("ab+c");

两种方式的不同之处就是,用构造函数创建的正则表达式会被编译,如果是动态生成的或者将被改变的就需要用构造函数来创建。

# 特殊字符

  • 断言:表示一个匹配在某些条件下发生。
  • 字符类:区分不同类型的字符,如字母和数字。
  • 组和范围:表示表达式字符的分组和范围。
  • 量词:表示匹配的字符或表达式的数量
  • Unicode属性转义:基于Unicode字符属性区分字符。例如大小写字母和数字符号标点等等。
字符 含义
\ 转义符,注意传给构造函数的特殊字符要额外加一个转义符
^ 匹配输入的开始,如/^A/ 不会匹配"anA"中的A,但会匹配"Ana"中的A
$ 匹配输入的结束,同上
* 匹配前一个表达式0次或多次,等价于{0,}
+ 匹配前一个表达式1次或多次,等价于{1,}
? 匹配前一个表达式0次或1次,等价于{0,1}。如果紧跟在任何量词(*,+,?,{})后面,将会使量词变为非贪婪(匹配尽量少的字符),缺省时则是贪婪模式。例如对“123abc”使用/\d+/将会匹配123,但是/\d+?/则只有1
. 默认匹配除换行符之外的任何单个字符,如/.n/
(x) 匹配x并记住匹配项 ,\1,\2表示第一个和第二个被捕获括号匹配的子字符串
(?:x) 匹配x但是不记住匹配项,非捕获括号,可以当成子表达式用
x(?=y) 匹配x但仅匹配紧跟y的x,先行断言
(?<=y)x 匹配x但仅匹配前置是y的x,后行断言
x(?!y) 匹配x但仅匹配不跟着y的x,正向否定查找
(<!y)x 匹配x但仅匹配前置不是y的x,反向否定查找
x y
{n} 匹配前面一个字符刚好出现了几次
{n,} 匹配前面一个字符至少出现了几次
{n,m} 匹配前面一个字符至少出现n次,至多出现m次
[xyz] 一个字符集合,匹配方括号内的任意字符,可以用-来指定范围
[^xyz] 一个反向字符集合,匹配没有在方括号内的任意字符,可以用-来指定范围
[\b] 匹配一个退格
\b 匹配一个词的边界,开头或者结尾,比如放后面就是以xx结尾,放前面就是以xx开头
\B 匹配一个非单词边界,字符串第一个或者最后一个字符为非‘字’字符
\cX 当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符
\d 匹配一个数字,等价于[0-9]
\D 匹配一个非数字字符,等价于[^0-9]
\f 匹配一个换页符
\n 匹配一个换行符
\r 匹配一个回车符
\s 匹配一个空白字符,包括空格、制表符、换页符、换行符
\S 匹配一个非空白字符
\t 匹配一个水平制表符
\v 匹配一个垂直制表符
\w 匹配一个单字字符,相当于[A-Za-z0-9]
\W 匹配一个非单字字符
\n 第n个子捕获匹配的字符串
\0 匹配null字符串

# 使用插入语

任何正则表达式的插入语都会使这部分匹配的副字符串被记忆。一旦被记忆,这个副字符串就可以被调用于其他用途。 比如/Chapter (\d+).\d*/用于匹配"Open Chapter 4.3, paragraph 6"时,'4'会被记住。 但是括号内用?:\d+则不会被记住