JavaScript
JavaScript区分大小写。
【标识符】
- 第一个字符,可以是任意字母,
$
和_
。- 第二个字符及后面的字符,除了字母、
$
和_
,还可以用数字0-9
。
【注释】
// 单行注释
/* 多行注释 */
<!-- 单行注释 -->
也可以,但是只有-->
在行首时才会被识别成注释,否则会被识别成运算。
x = 1; <!-- x = 2;
--> x = 3;
// 只有x=1会执行,其他会被注释掉。
// 为什么x=3也会被注释掉?
function countdown(n) {
while (n --> 0) console.log(n);
// n --> 0会被当做n-- > 0执行。
}
countdown(3)
// 2
// 1
// 0
【字面量】
不可改变的值。
- 比如1、2、3。
【变量】
用来保存字面量,变量的值可以任意改变。
声明变量
- var a;
- 全局作用域、函数作用域。
【标签label】
label: 语句;
标签,相当于定位符,用于跳转到程序的任意位置。
标签可以是任意的标识符,但不能是保留字,语句部分可以是任意语句。
标签通常与break
语句和continue
语句配合使用,跳出特定的循环。
// 跳出双重循环。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) break top;
console.log('i=' + i + ', j=' + j);
}
}
// 跳出代码块。
foo: {
console.log(1);
break foo;
console.log('本行不会输出');
}
// 进入下一层外层循环。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) continue top;
console.log('i=' + i + ', j=' + j);
}
}
【数据类型】
以下Number、String、Boolean、Undefined、Null(前五种)为基本数据类型,而Object为引用数据类型。
- 基本数据类型
基本数据类型指的是字面量的类型。
变量和基本数据类型值存储在栈内存中。- 引用数据类型
变量和指向对象存储地址的指针存储在栈内存中,对象值存储在堆内存中。
(1)Number
整数或小数。
在JavaScript内部,数字都是以标准 IEEE 754的64位浮点数形式存储。
- 能够表示的数值范围为2^1024到2^(-1023)。
- 精确度范围-2^53到2^53(大约16位十进制数)。
- 正向溢出返回Infinity,负向溢出返回0。
特殊的数字
- Number.MAX_VALUE:能表示的最大值。
- number.MIN_VALUE:最小正值。
- Infinity:正无穷,-Inifinity:负无穷。
- NaN:Not A Number。
由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3
// false
0.3 / 0.1
// 2.9999999999999996
(0.3 - 0.2) === (0.2 - 0.1)
// false
+0
和-0
在大多数场合下是相等的。但当+0
或-0
当作分母,返回的值是不相等的。下面的代码之所以出现这样结果,是因为除以正零得到+Infinity
,除以负零得到-Infinity
,这两者是不相等的。
(1 / +0) === (1 / -0) // false
parseInt
将字符串转为整数。
返回值只有两种可能,要么是一个十进制整数,要么是NaN。
// 如果字符串头部有空格,自动去除空格。
parseInt(' 81') // 81
// 如果参数不是字符串,则会先转为字符串再转换。先转换成十进制,再转换成字符串,再按进制解析。
parseInt(1.23) // 1
// 等同于
parseInt('1.23') // 1
// 字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
// 如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。
parseInt('abc') // NaN
// 如果字符串以0x或0X开头,parseInt会将其按照十六进制解析。
parseInt('0x10') // 16
//如果字符串以0开头,将其按照10进制解析。
parseInt('011') // 11
// 对于那些会自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。
parseInt(0.0000008) // 8
// 等同于
parseInt('8e-7') // 8
// parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。
// 如果超出范围,则返回NaN。如果第二个参数是`0`、`undefined`和`null`,则直接忽略。
// 如果字符串包含对于指定进制无意义的字符,则从最高位开始,只返回可以转换的数值。如果最高位无法转换,则直接返回NaN。
parseInt('1546', 2) // 1
parseInt('546', 2) // NaN
parseFloat
将字符串转为浮点数。
// 如果字符串符合科学计数法,则会进行相应的转换。
parseFloat('314e-2') // 3.14
parseFloat('0.0314E+2') // 3.14
// 如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分。
parseFloat('3.14more non-digit characters') // 3.14
// parseFloat方法会自动过滤字符串前导的空格。
parseFloat('\t\v\r12.34\n ') // 12.34
// 如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN。
parseFloat([]) // NaN
parseFloat('FF2') // NaN
parseFloat('') // NaN
isNaN
判断一个值是否为NaN。
// isNaN只对数值有效,如果传入其他值,会先被Number函数转成数值,再进行判断。
isNaN('Hello') // true
// 空或非空对象返回true
// 空对象转换为数值为NaN
isNaN({}) // true
// 空数组返回false
// 空数组转换为数值为0
???
isNaN([]) // false
// 只有一个数值成员的数组返回false
isNaN([123]) // false
isNaN(['123']) // false
// 含有非数值成员的数组返回true
isNaN(['xzy']) // true
判断NaN更可靠的方法是,利用NaN为唯一不等于自身的值的特点。
function myIsNaN(value){
return value !== value;
}
isFinite
除了Infinity、-Infinity、NaN和undefined这几个值会返回false,isFinite对于其他的数值都会返回true。
(2)String
字符串的访问
- 字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。
求字符串的长度
- str.length
由于 HTML 语言的属性值使用双引号,所以很多项目约定 JavaScript 语言的字符串只使用单引号。
如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠,也可以使用连接运算符(+
)。
(3)Boolean
除了下面六个值被转为false,其他值都视为true。
- undefined
- null
- false
- 0
- NaN
- ""或’’(空字符串)
空数组[]和空对象{}对应的布尔值都是true。
NaN不等于任何值,包括它本身。
(4)Undefined
- 表示定义未赋值。
- 转为数值时为NaN。
(5)Null
- 表示定义并赋值了,但值为null。
- 转为数值时为0。
- 初始赋值为null,表明将要赋值为对象。最后赋值为null,成为垃圾对象,被垃圾回收器回收。
var a;
console.log(a);//undefined
var b = null;
console.log(b);//null
(6)object
对象的分类
- 内建对象
由ES标准中定义的对象,在任何的ES的实现中都可以用。
比如:Math、String、Number、Boolean、Function、Object…- 宿主对象
由JS的运行环境(浏览器)提供的对象。
比如:BOM、DOM- 自定义对象
由开发人员创建的对象。
狭义的对象object
对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。
键名key
- 又称为属性property。属性可以动态创建,不必在对象声明时就指定。
- 键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。
- 如果是数值,会被自动转为字符串。
- 如果不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。
创建对象
var obj = new Object();读取属性
(1)点运算符。
key为数字不能用点运算符。
obj.p
(2)方括号运算符。
如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。
key为数字可以不加引号,因为会自动转成字符串。
obj.[‘p’]删除属性
delete obj.p;
删除一个不存在的属性,delete不报错,而且返回true。只有一种情况,delete命令会返回false,那就是该属性存在,且不得删除。
delete命令只能删除对象本身的属性,无法删除继承的属性。查看是否存在该属性
‘p’ in obj;
in运算符不能识别哪些属性是对象自身的,哪些属性是继承的(从原型继承过来的)。此时可以使用对象的hasOwnProperty方法判断一下,是否为对象自身的属性。obj.hasOwnProperty(‘toString’);查看所有属性
Object.keys(obj);遍历属性
for(var i in obj){
console.log(i);
console.log(obj[i]);
}
for…in遍历的是对象所有可遍历的属性,会跳过不可遍历的属性(比如toString)。它不仅遍历对象自身的属性,还遍历继承的属性。
如果要只遍历对象自身的属性,可以
for(var i in obj){
if(obj.hasOwnProperty(i))
…
}操作同一个对象的多个属性
不建议使用
with (document.links[0]){
console.log(href);
console.log(title);
console.log(style);
}
// 等同于
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);
如果with区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。
var obj = {};
with (obj) {
p1 = 4;
p2 = 5;
}
obj.p1 // undefined
p1 // 4
函数
- 函数也可以作为对象的属性,称为对象的方法。
- console.log()调用console对象的log方法。
数组
数据类型和变量类型
数据类型
- 基本类型
- 对象类型
变量类型
- 基本类型:保存的是基本类型的数据
- 引用类型:保存的是地址值
//var a = x, a内存中保存的是什么?
//x是基本数据类型,则保存的是这个数据
//x是对象,则保存的是对象的地址值。
//x是变量,则保存的是x内存中的内容。(即x中为基本数据类型,则保存的是这个数据;x中为对象,则保存的是对象的地址值)
var x = 'abc';
a = x;//a中保存的是'abc'这个数据
var x = {};
a = x;//a中保存的是对象的地址值。
【强制类型转换】
强制类型转换主要指将其他数据类型转换成String、Number、Boolean。
(1)转换为String
- toString()
对于null和undefined没有toString()方法,如果调用toString()方法会报错。
console.log(a.toString());- String()
对于Number和Boolean实际上就是调用toString()方法。
对于null和undefined不会调用toString()方法,而是直接转换成“null”和“undefined”。
console.log(String(a));- 算数运算符+
console.log(a + “”);
(2)转换为Number
- Number()
a = Number(a);
①字符串->数字
如果字符串中有非数字的内容,则转换为NaN。
如果字符串是空串或者全是空格,则转换为0。
②布尔->数字
true 1。
false 0。
③null->数字=0
④undefined->数字=NaN- parseInt()
a = parseInt(a);- parseFloat()
a = parseFloat(a);- 算数运算符-*/
-0、*1、/1- 一元运算符+
+a;
(3)转换为Boolean
- Boolean()
a = Boolean(a);
①数字->布尔
0和NaN为false,其他都为true。
②字符串->布尔
空串为false,其他都为true。
③null->布尔=false
④undefined->布尔=false
【判断数据类型】
(1)typeof
以字符串的形式返回一个值的数据类型。
- 可以判断undefiend/number/string/boolean/function。
- 不能判断null(返回object)、array(返回object)。
- NaN的类型是number。
- null的类型是object。因为1995年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑
null
,只把它当作object
的一种特殊值。后来null
独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null
返回object
就没法改变了。
typeof NaN//'number'
var a = null;
typeof a//'object'
var obj = {
b1: ['a','b', console.log],
b2: function(){
console.log('b2');
return fuction(){
return 'test';
}
}
};
typeof obj.b1//'object'
typeof obj.b2//'function'
(2)instanceof
A instanceof B
检查一个对象是否是一个类的实例(检测构造函数B的prototype
属性是否出现在某个实例对象A的原型链上)。
- 所有对象都是Object的后代。
- 可以判断array。
(3)Object.prototype.toString
【运算符】
算数运算符±*/
- 当对非Number类型的值进行运算时,会将这些值转换为Number再进行运算。
- 任何值和NaN运算,都等于NaN。
- +
字符串拼接:任何值和字符串做加法运算,都会先转换为字符串再拼串。一元运算符±
自增运算符++、–
逻辑运算符!、&&、||
赋值运算符=、+=、-= 、*=、/=
关系运算符>、<、>=、<=
- 当对非Number类型的值进行比较时,会将这些值转换为Number再进行比较。
- 两字符串比较,按字典序比较。
相等运算符==、!=、===、!==
- ==
比较数值。
如果两个值类型不同,会自动进行类型转换为相同的类型再进行比较。
underfined和null都被自动转为false,相等运算符==
认为二者是相等的。
NaN不和任何值相等,包括它本身。
当比较两个基本数据类型的值时,就是比较值;当比较两个引用数据类型时,是比较对象的内存地址,如果两个对象一模一样但是地址不同,也会返回false。- !=
类似==。- ===
全等。
比较类型和数值。
如果两个值类型不同,不会自动进行类型转换,直接返回false。- !==
不全等。
类似===。条件运算符/三元运算符 条件a?语句b:语句c
- 如果条件a的结果是非布尔值,会先转换成布尔值。
运算符的优先级
【函数】
用typeof检查一个函数对象时,会返回function。
(1)函数声明
函数声明
function print(s){
console.log(s);
}
// 不用加分号函数表达式
var print = function(s){
console.log(s);
};
// 加分号
相当于将一个匿名函数(函数表达式)赋值给变量。以字符串形式传递给构造函数
var add = new Function(
‘x’,
‘y’,
‘return x + y’
);
// 等同于
function add(x, y) {
return x + y;
}
add();//调用
①固定最后一个参数为函数体。
②封装到函数中的代码不会立即执行,在函数调用时才执行。立即执行函数
(function(a, b){
console.log(a+b);
})(123, 456)
(2)函数的属性和方法
f.name;
- 获取函数的名字。
f.length
- 返回函数预期传入的参数个数。
f.toString()
- 返回一个字符串,内容是函数的源码。
f.call()、f.apply()
- 调用函数。
- 在调用call()和apply()时可以将一个对象指定为第一个参数,此时这个对象成为函数执行时的this。
- call()可以将实参在对象之后一次传递。f.call(obj, 1, 2);
- apply()可以将实参封装到一个数组中统一传递。f.apply(obj, [1,2]);
(3)作用域
全局作用域
- 在页面打开时创建,在页面关闭后销毁。
函数作用域
- 在函数定义时创建,在函数执行完毕后销毁。
块级作用域
- ES6才有。
作用域的作用
- 隔离变量,不同作用域下同名变量不会有冲突。
(4)执行上下文
全局执行上下文
- 在执行全局代码前将window确定为全局执行上下文对象。
- 对全局数据进行预处理。
var定义的全局变量=>undefined,添加为window的属性。
function声明的全局函数=>赋值,添加为window的方法。
this=>赋值(window)- 开始执行全局代码。
函数执行上下文
- 在调用函数、准备执行函数体之前,创建对应的函数执行上下文对象。
- 对局部数据进行预处理。
形参=>赋值(实参)=>添加为执行上下文的属性。
arguments=>赋值(实参列表)=>添加为执行上下文的属性。
var定义的局部变量=>undefined=>添加为执行上下文的属性。
function声明的函数=>赋值=>添加为执行上下文的方法。
this=>赋值(调用函数的对象)- 开始执行函数体代码。
执行上下文栈
- 在全局代码执行前,JS引擎会创建一个栈来存储管理所有的执行上下文对象。
- 在全局执行上下文对象确定后,将其添加到栈中。
- 在函数执行上下文对象创建后,将其添加到栈中。
- 在当前函数执行完后,将栈顶的对象移出。
- 在所有的代码执行完后,栈中只剩下window。
(5)作用域和执行上下文的区别
区别
①
- 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了,而不是在函数调用时确定。
- 全局执行上下文环境是在全局作用域确定之后,JS代码马上执行之前创建。
- 函数执行上下文环境是在调用函数时,函数体代码马上执行之前创建。
②
- 作用域是静态的,只要函数定义好了就一直存在且不会再发生变化。
- 上下文环境是动态的,调用函数时创建,函数调用结束时上下文环境会被释放。
联系
- 上下文环境(对象)是从属于所在的作用域。
- 全局上下文环境=>全局作用域
- 函数上下文环境=>对应的函数作用域。
(6)变量提升、函数提升
变量提升
- 使用var声明的变量,在所有代码执行之前就可以被访问到。
- 值为undefiend。
函数提升
- 通过function声明的函数,在所有代码执行之前就可以直接调用。
- 值为函数定义(对象)。
执行顺序:先变量提升再函数提升。
优先级:函数提升>变量提升。
//通过function声明
function f(){}
//通过变量声明
var f = function(){}
//先变量提升再函数提升 => fun = undefined => fun = function(){}(函数是直接赋值)
console.log(fun) //function fun(){}
var fun = 'f'
function fun(){}
//执行上面后,因为函数在函数提升时已经赋值过了会直接跳过;就执行fun = 'f'。
console.log(fun) //'f'
(7)参数
可以省略参数。
- 没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。
- 解析器在调用函数每次都会向函数内部传递2个隐含的参数。
this
- this指向的是一个对象,这个对象是函数执行的上下文对象。
- 根据函数的调用方式不同,this会指向不同的对象。
①以函数的形式调用时,this就是window对象。
fun();
②以方法的形式调用时,this就是调用方法的对象。
obj.fun();
③以构造函数的形式调用时,this就是新创建的对象。
④使用call()和apply()时,this就是指定的对象。
arguments
- arguments对象包含了函数运行时的所有参数。arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
- 通过arguments对象的length属性,可以判断函数调用时到底带几个参数。
- 正常模式下,
arguments
对象可以在运行时修改。
严格模式下,修改arguments对象不会影响到实际的函数参数。arguments
对象带有一个callee
属性,返回当前正在执行的函数对象。
arguments.callee();
虽然arguments是一个类数组对象,但它是一个对象。数组专有的方法(比如slice和forEach),不能在arguments对象上直接使用。
以下为常用的将arguments对象转换成数组的方法:
// slice
var args = Array.prototype.slice.call(arguments);
var args = [];
for(var i = 0; i < arguments.length; i++){
args.push(arguments[i]);
}
(8)构造函数(类)
首字母大写。
使用同一个构造函数创建的对象,称为一类对象。
通过一个构造函数创建的对象,称为是该类的实例。
构造函数和普通函数的区别
- 调用方式的不同:普通函数是直接调用,而构造函数使用new关键字来调用。
构造函数的执行流程
- ①创建一个对象。
②将新建的对象作为函数中的this。
③逐行执行函数中的代码。
④将新建的对象作为返回值返回。
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
//执行n次创建n次
//浪费内存空间。
this.sayHello = function(){
alert(this.name);
};
//执行n次创建1次
//把函数声明在全局作用域,污染全局作用域的命名空间,且不安全。
this.sayHello = fun;
}
function fun(){
alert(this.name);
}
//建议使用原型
Person.prototype.sayHello = function(){
alert(this.name);
};
var per = new Person('孙悟空', 18, '男');
per.sayHello();
(9)原型
每个函数(不论是普通函数还是构造函数)都有一个prototype属性(显式原型/显式属性),是在定义函数时自动添加的,prototype属性指向原型对象(空Object实例对象,但Object的prototype不是空Object实例对象)。
每个实例对象都有一个__proto__属性(隐式原型/隐式属性),是创建对象时自动添加的,__proto__属性指向原型对象。
程序员能直接操纵显式原型,但不能直接操纵隐式原型(ES6前)
原型对象
- 构造函数的原型对象中有一个constructor属性,它指向构造函数(constructor和prototype是成对的)。
- 可以将对象中共有的内容,统一设置到原型对象中。
- 原型对象也是对象,也有原型。
原型链(隐式原型链,JS高级P17)
当访问对象的属性或方法时
- 先在对象自身中寻找,找到返回;
- 如果没有,再沿着__proto__这条链向上找,找到返回;
- 如果最终没找到,返回undefined。
https://juejin.cn/post/7007416743215759373#heading-11
(10)回调函数
定义
- 你定义的
- 你没有调用
- 但最终它执行了
常见的回调函数
- dom事件回调函数
- 定时器回调函数
- ajax请求回调函数
- 生命周期回调函数
(11)闭包
定义
- 引用了另一个函数作用域中变量的函数。
产生的条件
- 函数嵌套。
- 内部函数引用了外部函数的数据(变量/函数)。
作用
- 读取外部函数内部的变量。
- 让这些变量始终保持在内存中。
外层函数执行后,其执行上下文会被清除。但是由于闭包用到了外层函数的活动对象,导致外层函数的活动对象不能从内存释放。只要闭包没有被垃圾回收机制清除,就一直保持着对外层函数的活动对象的引用,外层函数的活动对象就一直保存在内存中。(至于是全部保存还是只保存被引用的,取决于JS引擎使用的GC机制。https://www.iteye.com/blog/justjavac-1465169)应用
- 实现JS模块。
优点
- 希望一个变量长期存储在内存中。
- 避免全局变量污染。
- 私有成员的存在。
缺点
- 常驻内存,增加内存使用量。
- 使用不当会造成内存泄露。
http://cavszhouyou.top/JavaScript%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E4%B9%8B%E9%97%AD%E5%8C%85.html
(12)IIFE
立即执行函数表达式Immediately-Invoked Function Expression
作用
- 隐藏实现。
- 不会污染外部(全局)命名空间。
- 编写JS模块。
function(){
...
}();
【数组】
用typeof检查一个数组对象时,会返回object。
(1)数组的基本操作
创建数组
- var arr = new Array(10);
- var arr = [];
- 数组元素可以是任意数据类型。
读取数组
- 如果不存在返回undefined。
获取数组长度
- arr.length;
- length是属性,不用加()。
- 对于连续的数组,会获取到数组的长度(元素的个数)。
对于非连续的数组,会获取到数组的最大索引+1。- 也可以利用length修改数组长度。
向数组的最后一个位置添加元素
- arr[length]=22;
(2)数组的方法
push()
- 向数组的末尾添加一个或多个元素,并返回新的数组长度。
- arr.push(11);
pop()
- 删除数组的最后一个元素,并返回被删除的元素。
unshift()
- 向数组开头添加一个或多个元素,并返回新的数组长度。
shift()
- 删除数组的第一个元素,并返回被删除的元素。
forEach()
- 遍历数组。
- 只支持ie8以上。
- 参数为一个回调函数,该回调函数传递三个参数:当前正在遍历的元素,当前正在遍历的元素的索引,正在遍历的数组。
- arr.forEach(function(value, index, a){
…
});slice()
- 截取数组[start, end)元素并返回截取元素。
- 不会改变原数组。
- 第二个参数可以不写,则默认从start截取到最后一个元素。
- 参数可以传递负值,表示倒数第n个。
- arr.slice(0, 1);
splice()
- 删除数组指定元素并返回被删除元素。
- 会改变原数组。
- 第一个参数:表示开始位置的索引。
- 第二个参数:表示删除的数量。
- 第三个及以后的参数:传递一些新元素,并插入到开始位置前。
concat()
- 连接两个或多个数组并返回新的数组。
- 不会改变原数组。
join()
- 将数组转化为字符串并返回。
- 不会改变原数组。
- 参数为连接符,不写默认逗号。
reverse()
- 反转数组。
- 会改变原数组。
sort()
- 按unicode编码字典序给数组排序。
- 会改变原数组。
- 可以传入一个回调函数,来指定排序规则。浏览器会根据回调函数的返回值来决定元素的顺序。
(1)比较函数将小的数排在前面(默认升序)。比较函数返回正, 代表a大于b, 就会将b排在前面;如果返回为负数代表a小于b,会将a排在前面;所以如果我们给结果加一个负号, 就会颠倒它们变成降序。
(2)比较函数应该具有两个参数 a 和 b,其返回值如下:
若 a 小于 b即a-b<0,则元素位置不变。
若 a 等于 b即a-b=0,则认为两个元素相等也不交换位置。
若 a 大于 b即a-b>0,则元素会交换位置。
arr.sort(function(a, b){
return a-b;
});
【正则表达式】
用于定义一些字符串的规则。计算机可以根据正则表达式,检查一个字符串是否符合规则。
用typeof检查正则对象,会返回object。
正则表达式对象
- var 变量 = new RegExp(“正则表达式”, “匹配模式”);
var reg = new RegExp(“a”,“i”);
创建正则表达式的对象。- var 变量 = /正则表达式/匹配模式
var reg = /a/i;- test()
reg.test(str);
检查字符串是否符合正则表达式的规则。如果符合则返回true,否则返回false。
匹配模式
默认匹配到第一个就结束。
- i:忽略大小写。
- g:全局匹配模式。
语法
- |或[]表示或
是否有a或b:reg = /a|b/; reg = /[ab]/;
是否含有abc或adc或aec:reg = /a[bde]c/;
任意小写字母:reg = /[a-z]/;
任意大写字母:reg = /[A-Z]/;
任意字母:reg = /[A-z]/;
任意数字:reg = /[0-9]/;- [^]表示除了
含有除了a、b以外的:reg = /[^ab]/;- {n}表示内容出现n次
是否含ababab:reg = /(ab){3}/;- {a, b}表示内容出现[a,b]次
- {a, }表示内容出现a次及a次以上
- +表示内容出现至少1次
- *表示内容出现0次或多次
- ?表示内容出现0次或1次
- ^表示以内容开头
- $表示以内容结尾
只能是’a’:reg = /^a$/;- .表示任意字符
是否含有.:reg = /\./;- \w表示任意字母、数字、_
- \W表示除了字母、数字、_
- \d表示任意数字
- \D表示除了数字
- \s表示空格
- \S表示除了空格
- \b表示单词边界
是否含有独立单词child:reg = /\bchild\b/;- \B表示除了单词边界
去除开头或结尾的空格:reg = /^\s*|\s*$/g;
【标准库】
Object对象
//Object对象本身的方法(直接定义在Object对象的方法)
//Object.keys():返回对象自身的可枚举的所有属性名。
var obj = {
p1: 123,
p2: 234
};
Object.keys(obj) // ["p1", "p2"]
//Object.getOwnPropertyNames():返回对象自身的可枚举+不可枚举的所有属性名。
var a = ['hello', 'world'];
Object.keys(a) // ["0", "1"]
Obejct.getOwnPropertyNames(a) // ["0", "1", "length"]
//Object.getOwnPropertyDescriptor():获取某个属性的描述对象。
//Object.defineProperty():通过描述对象,定义某个属性。
//Object.defineProperties():通过描述对象,定义多个属性。
//Object.preventExtensions():防止对象扩展。
//Object.isExtensible():判断对象是否可扩展。
//Object.seal():禁止对象配置。
//Object.isSealed():判断一个对象是否可配置。
//Object.freeze():冻结一个对象。
//Object.isFrozen():判断一个对象是否被冻结。
//Object.create():该方法可以指定原型对象和属性,返回一个新的对象。
//Object.getPrototypeOf():获取对象的`Prototype`对象。
//Object的实例方法(定义在Object.prototype上的方法)
//Object.prototype.valueOf():返回当前对象对应的值。
var obj = new Object();
obj.valueOf() === obj // true
//Object.prototype.toString():返回当前对象对应的字符串形式。
//数组、字符串、函数、Date 对象都分别部署了自定义的`toString`方法,覆盖了`Object.prototype.toString`方法。
//实例对象可能会自定义toString方法,会覆盖掉Object.prototype.toString。直接使用Object.prototype.toString方法。
var o1 = new Object();
o1.toString() // "[object Object]"
Object.prototype.toString.call(value)
//Object.prototype.toLocaleString():返回当前对象对应的本地字符串形式。
//Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。
var obj = {
p: 123
};
obj.hasOwnProperty('p') // true
obj.hasOwnProperty('toString') // false
//Object.prototype.isPrototypeOf():判断当前对象是否为另一个对象的原型。
//Object.prototype.propertyIsEnumerable():判断某个属性是否可枚举。
属性描述对象
JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。
//元属性
//value:表示属性值。默认undefined。
//writable:表示value是否可修改。默认true。
//enumerable:表示是否可遍历。默认false。
//configurable:表示属性的可配置性。默认ture。
//get:表示该属性的取值函数(getter)。默认undefined。
//set:表示该属性的存值函数(setter)。默认undefined。
//定义了get或者set,就不能将writable设为true,或者定义value属性。
//Object.getOwnPropertyDescriptor():获取属性描述对象。
//只能用于对象本身的属性,不能用于继承的属性。
var obj = { p: 'a'};
Object.getOwnPropertyDescriptor(obj, 'p')
// Object {
// value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }
//Object.getOwnPropertyNames():返回参数对象自身的全部属性的属性名(包括可遍历、不可遍历)
var obj = Object.defineProperties({},{
p1: {value: 1, enumerable: true},
p2: {value: 2, enumerable: false}
});
Object.getOwnPropertyNames(obj)
// ["p1", "p2"]
//Object.defineProperty(),Object.defineProperties():允许通过属性描述对象,定义或修改一个属性,然后返回修改后的对象。
/*
Object.defineProperty(object, propertyName, attributesObject)
object:属性所在的对象
propertyName:属性名
attributesObject:属性描述对象
*/
/*
Object.defineProperties(object, {propertyName: attributesObject, ... })
*/
//Object.preventExtensions():使得一个对象无法再添加新的属性。
var obj = new Object();
Object.defineProperty(obj, 'p', {
value: 'hello'
});
// TypeError: Cannot define property:p, object is not extensible.
obj.p = 1;
obj.p // undefined
//Object.isExtensible():检查一个对象是否使用了Object.preventExtensions方法。
//Object.seal():使得一个对象既无法添加新属性,也无法删除旧属性(可以修改)。
//Object.isSealed():检查一个对象是否使用了Object.seal方法。
//Object.freeze():使得一个对象无法添加新属性、无法删除旧属性、也无法改变属性的值。
//Object.isFrozen():检查一个对象是否使用了Object.freeze方法。
//局限性:以上只能冻结对象本身,仍可以通过原型对象进行修改。
//Object.prototype.propertyIsEnumerable():判断某个自身属性是否可以遍历。
Array对象
//Array.isArray():表示参数是否为数组。
var arr = [1, 2, 3];
Array.isArray(arr) // true
//valueOf():返回数组本身。
arr.valueOf() //[1, 2, 3]
//toString():返回数组的字符串形式。
arr.toString() //"1,2,3"
//push():用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
arr.push(1) //4
//pop():用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组。
[].pop() //undefined
//shift():用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。
//unshift():用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
//join():以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。
//应用:通过call方法也可以用于字符串或类似数组的对象。
Array.prototype.join.call('hello', '-')// "h-e-l-l-o"
var obj = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.join.call(obj, '-')// 'a-b'
//concat():用于多个数组的合并。将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变。
['hello'].concat(['world'])// ["hello", "world"]
//reverse():颠倒排列数组元素,返回改变后的数组。注意,该方法将改变原数组。
//slice(start, end):返回数组[start, end)位置的元素。
//如果省略第二个参数,则一直返回到原数组的最后一个成员。
//参数是负数,则表示倒数计算的位置。
//如果start>arr.length或者start<end,返回空数组。
arr.slice(0) // [1, 2, 3, 4]
arr.slice(1, 3) // [2, 3, 4]
//应用:将类似数组的对象转为真正的数组。
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2})// ['a', 'b']
//splice():用于删除原数组的一部分成员,并可以在删除的位置添加新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。
arr.splice(start, count, addElement1, addElement2, ...);
//sort():按照字典序对数组成员进行排序。排序后,原数组将被改变。
//map():将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。
var nums = [1, 2, 3];
nums.map(function(n){
return n+1;
})//[2, 3, 4]
nums //[1, 2, 3]
//map()方法的回调函数有三个参数,elem为当前成员的值,index为当前成员的位置,arr为原数组。
nums.map(function(elem, index, arr){
return elem * index;
})//[0, 2, 6]
//map()方法还可以接受第二个参数,来绑定回调函数内部的this变量。
[1, 2].map(function(e){
return this[e];
}, nums)//[2, 3]
//forEach():和map()类似。但不会返回执行结果。
//filter():过滤数组成员并组成新数组返回。
nums.filter(function(n){
return (n > 1);
}) //[2, 3]
//filter()方法的参数函数可以接受三个参数:当前成员,当前位置和整个数组。
//filter()方法还可以接受第二个参数,来绑定回调函数内部的this变量。
//some():判断数组成员是否符合某种条件。一个数组成员满足条件即返回true。
nums.some(function(n){
return (n > 1);
})//true
//some()方法的参数函数接受三个参数:当前成员、当前位置和整个数组。
//some()方法还可以接受第二个参数,来绑定回调函数内部的this变量。
//every():类似some()。但是当所有数组成员都满足条件才返回true。
//reduce():依次处理数组的每个成员,并返回结果。从左往右。
nums.reduce(function(a, b){
return a + b;
})
//第一轮:a为数组的第一个成员1,b为数组的第二个成员2。
//第二轮:a为上轮的返回值3, b为数组的第三个成员3。
//结果为6。
//reduce()方法的参数函数可以接受四个参数;累积变量(必要),当前变量(必要),当前位置,原数组。
//reduce()方法还可以接受第二个参数,为累积变量指定初值。若指定了初值,遍历则是从第一个成员开始遍历,还可以防止空数组报错。
nums.reduce(function(a, b){
return a + b;
}, 0)//6
//reduceRight():类似reduce(),从右往左。
//indexOf():返回给定元素在数组中第一次出现的位置,如果没有出现则返回-1。
//还可以接受第二个参数,表示搜索的开始位置。
nums.indexOf(1, 1) // -1
//lastIndexOf():返回给定元素在数组种最后一次出现的位置,如果没有出现则返回-1。
//注意:以上不能用来搜索NaN的位置,因为方法内部是使用===进行比较,而NaN不等于其本身。
//以上方法可以链式使用。
var users = [
{name: 'tom', email: 'tom@example.com'},
{name: 'peter', email: 'peter@example.com'}
];
users
.map(function (user) {
return user.email;
})
.filter(function (email) {
return /^t/.test(email);
})
.forEach(function (email) {
console.log(email);
});
// "tom@example.com"
包装对象
JS为我们提供了三个包装类,可以将基本数据类型转化为对象。
- 当我们对一些基本数据类型的值调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后调用对象的属性和方法,调用完以后再将其转换为基本数据类型。
String()
- var str = new String(‘aaa’);
- charAt()
返回字符串指定位置的字符。- charCodeAt()
返回字符串指定位置的字符的Unicode编码。- String.fromCharCode()
根据字符编码获取字符。- concat()
连接两个或多个字符串。- indexOf()
检索字符串中是否有指定内容,有则返回其第一次出现的索引,无则返回-1。
第二个参数:开始查找的位置,没有则默认从0开始。- lastIndexOf()
检索字符串中是否有指定内容,有则返回其最后一次出现的索引,无则返回-1。(从后往前找)
第二个参数:开始查找的位置,没有则默认从0开始。- slice()
截取字符串中[start, end)字符。
不会改变原字符串。
同数组。- substring()
截取字符串中[start, end)字符。
参数传递负值,则视为0。
自动调整参数位置(如果第二个参数小于第一个参数,自动交换位置)。- substr()
截取字符串。
第一个参数:开始位置的索引。
第二个参数:截取长度。- split()
按照参数(可以是正则表达式)将字符串拆分成数组。- search()
搜索字符串中是否有指定内容,有则返回其第一次出现的索引,无则返回-1。
可以用正则表达式作为参数。- match()
根据正则表达式,从一个字符串中将符合条件的内容以数组形式返回。- replace()
将字符串中指定内容替换为新的内容。
第一个参数:被替换的内容(可以正则表达式)。
第二个参数:新的内容。- toUpperCase()
将字符串转换成大写并返回。- toLowerCase()
Number()
Boolean()
Date对象
var d = new Date();
- 封装当前代码执行时间。
var d = new Date(“12/03/2016 11:10:30”);- 封装指定时间。
- 传入字符串“月/日/年 时:分:秒”。
d.getDate()
- 返回几号(前面不带0)。
d.getDay()
- 返回周几(0-6)。
d.getMonth()
- 返回月份(0-11)。
d.getFullYear()
- 返回年份。
d.getHours()
- 返回小时(0-23)。
d.getMinutes()
- 返回分钟(0-59)。
d.getSeconds()
- 返回秒(0-59)。
d.getMilliseconds()
- 返回毫秒(0-999)。
d.getTime()
- 返回时间戳(从格林威治标准时间1970年1月1日0时0分0秒,到当前日期所花费的毫秒数)。
- 时间戳/1000 秒
时间戳/1000/60 分
…Date.now();
- 获取当前的时间戳。
Math对象
Math.PI
- 返回圆周率。
Math.abs()
- 返回一个值的绝对值。
Math.ceil()
- 向上取整。
Math.floor()
- 向下取整。
Math.around()
- 四舍五入。
Math.random()
- 生成0-1的随机数。
- 生成0-x的随机数Math.round(Math.random()*x)。
- 生成1-10的随机数Math.round(Math.random()*9+1)。
- 生成x-y的随机数Math.round(Math.random()*(y-x)+x)。
Math.max()
- 返回一组数中的最大值。
Math.min()
- 返回一组数中的最小值。
Math.sqrt()
- 返回平方根。
Math.pow(x, y)
- 返回x的y次幂。
【DOM】
Document Object Model文档对象模型
通过document对象获取节点
- ducument.getElementById(’’)
var bj = document.getElementById(‘bj’);- document.getElementsByTagName(’’)
var inputs = document.getElementsByTagName(“input”);- document.getElementsByTagName(’*’)
获取所有元素。- document.getElementsByName(’’)
- document.getElementsByClassName(’’)
ie9以上。- document.querySelector()
根据css选择器查询元素节点。
只会返回第一个。
ie8也可以。- document.querySelectorAll()
根据css选择器查询元素节点。
以数组形式返回全部。
ie8也可以。- document.body
获取body标签。- document.documentElement
获取html标签。- document.createElement()
根据标签名创建一个元素节点对象并返回。- document.createTextNode()
根据文本内容创建文本节点对象并返回。通过节点获取节点
- getElementsByTagName("")
- childNodes
会获取包括文本节点在内的所有结点,标签间空白也会被当成文本节点(ie8及以下不会)。- children
会获取包括文本节点在内的所有结点。
标签间空白不会被当做文本节点。- firstChild
标签间空白也会被当成文本节点。- firstElementChild
标签间空白不会被当做文本节点。
ie8及以下不支持。- lastChild
标签间空白也会被当成文本节点。- parentNode
- previousSibling
- previousElementSibling
标签间空白不会被当做文本节点。
ie8及以下不支持。- nextSibling
- innerHTML
获取元素内部的HTML代码。
有标签。
自结束标签没用。
console.log(bj.innerHTML);
bj.innerHTML += ‘<li>广东</li>’;- innerText
获取元素内部的文本内容。
没有标签。- 元素.属性名
class属性不能用,可以用className读取class属性。
console.log(inputs[i].value);- 父节点.appendChild(子节点)
向一个父节点中添加一个新的子节点。- 父节点.insertBefore(新节点, 旧节点)
在指定的子节点前插入新的子节点。- 父节点.replaceChild(新节点, 旧节点)
使用指定的子节点替换已有的子节点。- 父节点.removeChild(子节点)
删除一个子节点。通过节点修改样式
(设置和读取的是内联样式)
- 元素.style.样式名 = 样式值
修改元素的样式值。
box.style.width = ‘600px’;
样式名需要改成小驼峰。
box.style.backgroundColor = ‘orange’;- 元素.currentStyle.样式名
读取元素当前正在显示的样式,没有则是默认值(maybe auto。只有ie能用。
其他浏览器可以使用getComputedStyle()返回css元素对象,没有则获取到真实的值。不支持ie8及以下。
第一个参数:要获取样式的元素;第二个参数:可以传递一个伪元素,一般传null。
console.log(getComputedStyle(box, null));
完美版本:
if(window.getComputedStyle){
return getComputedStyle(obj, null)[name];
}else{
return obj.currentStyle[name];
}- 元素.cilentWidth
- 元素.clientHeight
获取元素的可见高度(返回的是数字,内容区和内边距),只读。- 元素.offsetWidth
- 元素.offsetHeight
获取整个元素的高度(内容区、内边距和边框)。- 元素.offsetParent
获取当前元素的定位父元素(最近的开启了定位的祖先元素)。- 元素.offsetLeft
当前元素相对于其定位父元素的水平偏移量。- 元素.offsetTop
当前元素相对于其定位父元素的垂直偏移量。- 元素.scrollWidth
- 元素.scrollHeight
元素整个滚动区域的高度。- 元素.scrollLeft
- 元素.scrollTop
垂直滚动条滚动的距离。
scrollHeight - scrollTop == cilentHeight成立说明滚动条滚动到底了。
节点Node
构成HTML文档最基本的单位。
- 文档节点:整个HTML文档。
nodeName: #document
nodeTyep: 9
nodeValue: null- 元素节点:HTML文档中的标签。
nodeName: 标签名
nodeType: 1
nodeValue: null- 属性节点:元素的属性。
nodeName: 属性名
nodeType: 2
nodeValue: 属性值- 文本节点:HTML标签中的文本内容。
nodeName: #text
nodeType: 3
nodeValue: 文本内容
for循环在页面加载后立即执行,onlick事件在响应后才执行(此时for循环早已执行完毕)。
【事件】
文档或浏览器窗口中发生的一些特定的交互瞬间。
(1)事件对象event
- 当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数。在事件对象中封装了当前事件相关的一切信息。
- 在ie8中,浏览器不会传递事件对象,是将事件对象作为window对象的属性保存的。
event = event || window.event;
event.target
- 触发事件的对象。
event.wheelDelta
- 鼠标滚轮滚动的方向。
event.keyCode
- 获取按键ASCII编码。
event.altKey
- 判断alt是否被按下。
- if(event.keyCode == 89 && event.altKey){}
event.ctrlKey
event.shiftKey
event.key
- 获取按键。
- clientX
获取鼠标在当前可见窗口的水平坐标。
ie8及以下不可用。- cilentY
获取鼠标在当前可见窗口的垂直坐标。- pageX
获取鼠标在当前页面的水平坐标。
ie8及以下不可用。- pageY
获取鼠标在当前页面的垂直坐标。
绑定事件
①btn.onclick = function(){};
使用该方法只能为一个元素的相同事件同时绑定一个函数,如果绑定了多个,则后边的会覆盖掉前边的。
②btn.addEventListener(‘click’, function(){});
第一个参数:事件的字符串,不要on;第二个参数:回调函数;第三个参数:是否在捕获阶段触发事件(布尔值,一般false)。
可以为一个元素的相同事件绑定多个函数,按照函数的绑定顺序执行。
ie8及以下不可用。ie8可以用attachEvent()来绑定事件,第一个参数:事件的字符串,要on;第二个参数:回调函数。可以为一个元素的相同事件绑定多个函数,后绑定的先执行。onscroll
- 元素的滚动条滚动时触发。
onwheel
- 鼠标滚轮滚动时触发。
onmousemove
- 鼠标在元素中移动时触发。
onmousedown
- 按下鼠标时触发。
onmouseup
- 鼠标松开时触发。
onkeydown
- 某个键盘按键被按下。
- 键盘事件一般绑定给可以获取焦点的对象(如input)或者document。
- 一直按着不松开则会一直触发。
onkeyup
- 某个键盘按键被松开。
onload
- 页面加载后才会触发,确保所有DOM对象都已加载。
- window.onload = function(){};
(2)事件冒泡Bubble
事件冒泡指的是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发。
- 取消冒泡
event.cancelBubble = true;
(3)事件委派
- 事件委派指的是将事件统一绑定给元素的共同的祖先元素,当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。
- 事件委派利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能。
(4)事件传播
ie8及以下没有事件传播。
捕获阶段
- 在捕获阶段时,从最外层的祖先元素向目标元素进行事件的捕获。
但是默认此时不会触发事件。如果希望在捕获阶段触发事件可以将addEventListener()函数第三个参数设为true。目标阶段
- 事件捕获到目标元素,捕获结束开始在目标元素上触发事件。
冒泡阶段
- 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件。
【BOM】
Browser Object Model浏览器对象模型
BOM对象
这些对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用。
Window
代表的是整个浏览器的窗口,同时window也是网页中的全局对象。
(1)setInterval()
定时调用。
第一个参数:回调函数;第二个参数:间隔时间(ms)。
返回值:Number类型,表示定时器的唯一标识。
(2)clearInterval()
关闭定时器。
参数:定时器的标识。
(3)setTimeout()
延时调用。
参数同setInterval()。Navigator
代表的是当前浏览器的信息,通过该对象可以来识别不同的浏览器。
(1)userAgent
字符串,描述浏览器的信息。Location
代表浏览器的地址栏信息,通过该对象可以获取地址栏信息,或者操纵浏览器跳转页面。
(1)直接打印
获取到浏览器的地址栏信息。
(2)assign()
跳转页面。
location = ‘url’;
location.assign(‘url’);
(3)reload()
刷新当前页面,默认不清空缓存。
传入参数true,强制清空缓存。
(4)replace()
替换当前页面(不会生成历史记录)。History
代表浏览器的历史记录,通过该对象可以操纵浏览器的历史记录。由于隐私问题,该对象不能获取到具体的历史记录,只能操纵浏览器向前或向后翻页,且该操作只在当次访问时有效。
(1)length
获取当次访问的链接数量。
(2)back()
回退到上一个页面。
(3)forward()
跳转到下一个页面。
(4)go(n)
跳转到指定的页面。Screen
代表用户的屏幕信息,通过该对象可以获取到与用户显示器的相关信息。
【JSON】
JavaScript Object Notation JS对象表示法。
特殊格式的字符串,能被任意语言识别并转换成任意语言中的对象。
JSON和JS对象的格式一样,不过JSON字符串中的属性名必须加双引号。
JSON中允许的值:字符串、数值、布尔值、null、对象、数组。
类型
- 对象
var obj = ‘{ “name”: “孙悟空”, “age”: 18, “gender”: “男” }’;- 数组
var arr = ‘[1, 2, 3, “hello”]’;
JSON转化为JS对象
- o = JSON.parse(obj);
JS对象转化为JSON
- o = JSON.stringify(obj);
ie7及以下没有JSON。
可以使用以下方法将JSON转化为JS对象:
①eval()
- 用来执行一段字符串形式的JS代码,并返回执行结果。
- 如果使用eval()执行的字符串中含有{},会将{}当成代码块。如果不希望将其作为代码块解析,则需要在字符串前后加一个();
- 尽量不要使用,性能慢且具有安全隐患。
- o = eval(’(’ + obj + ‘)’ );
②引用工具包
【垃圾回收Garbage Collection】
当一个对象没有任何的变量或属性对其进行引用时,将永远无法操纵该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作,只需要将不再使用的对象设置为null即可。
【内存溢出】
当程序运行所需要的内存超过了剩余的内存时,就会抛出内存溢出的错误。
【内存泄露】
占用的内存没有及时释放(占着茅坑不拉屎)。
内存泄漏积累多了容易造成内存泄露。
常见的内存泄露
- 意外的全局变量。
- 没有及时清理的计时器或回调函数。
- 闭包。
【base64】
Base64 是一种编码方法,可以将任意值转成 0~9、A~Z、a-z、+和/这64个字符组成的可打印字符。使用它的主要目的,不是为了加密,而是为了不出现特殊字符,简化程序的处理。
- btoa():将任意值转为Base64编码。
- atob():将Base64编码转为原来的值。
不适合非 ASCII 码的字符,会报错。