# 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
3valueOf()
查看对象的原始类型的值。
# 函数
# 函数的声明 (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']; // 一维数组
var a = [[1, 2], [3, 4]]; // 二维数组
a[0][1] // 2
a[1][1] // 4
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
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
负数值运算符
# 比较运算符
- 先看两个运算子是否都是字符串,如果是的,就按照字典顺序比较(实际上是比较 Unicode 码点);
- 否则,先将两个运算子都转成数值,再比较数值的大小。
>
大于运算符<
小于运算符<=
小于或等于运算符>=
大于或等于运算符==
相等运算符- 实例:
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()
,定时执行无限次。setTimeout
和setInterval()
,都返回一个整数值,表示计数器编号。将该整数传入clearTimeout和clearInterval函数,就可以取消对应的定时器。debounce
(防抖动)
# DOM
# 事件
# 浏览器模型
# 讨论区
由于评论过多会影响页面最下方的导航,故将评论区做默认折叠处理。