前端面试思维导图-JavaScript
2021-01-28 17:10:06 0 举报
AI智能生成
前端面试思维导图-JavaScript语言基础知识点和面试考点以及相关解释和注意点
作者其他创作
大纲/内容
基础知识
基本概念
<script>元素
属性
type
text/javascript
src
引用外部脚本必须指明来源文件;引用外部脚本的标签之间的代码无效
language
已废弃
defer
延迟脚本,表示脚本可以延迟到文档完全被解析和显示之后再执行
charset
字符集
async
异步脚本,表示立即下载脚本,不妨碍页面中其他操作
位置
<head>标签中
<body>元素中页面内容的后面
语法
JS区分大小写
标识符(变量/函数/参数等)
组成
首个字符必须是字母、下划线或$
其他字符包括上面三种和数字
建议
尽量不要使用ASCII或Unicode的不常见字符
尽量采用驼峰大小写格式
注释
单行注释
//
多行注释
/* ... */
严格模式
启用严格模式
顶部添加代码"use strict",也可在函数体内部上方添加
子主题 2
关键字+保留字
关键字
break、else、new、var、case、finally、return、void、catch、for、switch、while、continue、function、this、with、default、if、throw、delete、in、try、do、instranceof、typeof、debugger*
保留字
abstract、enum、int、short、boolean、export、interface、static、byte、extends、long、super、char、final、native、synchronized、class、float、package、throws、const、goto、private 、transient、debugger、implements、protected 、volatile、double、import、public
变量
ECMAScript变量是松散类型,可保存任意类型的数据,严格模式下不能定义名为eval或arguments的变量
数据类型
typeof操作符
”undefined“
null,空对象指针
未赋值的变量
未声明的变量
”boolean“
”string“
”number“
”object“
null
new Object()
[1,2,3]
”function“
instanceof
定义
检测是何种对象,判断一个引用是否属于某构造函数,判断一个实例是否属于它的父类
原理
构造函数原型是否等于实例的__proto__属性,即Object.prototype === obj.__proto__
返回值
Object
Array
RegExp
Date
基本类型(按值访问)
Undefined
未赋值的变量
赋值为undefined
Null
null === undefind为true
当意在保存对象但还没真正对象时赋值为null
Boolean
true
非空字符串
非零数字
任何非null对象
false
空字符串
0
null
undefined
Number
整形
十进制
八进制
第一位必须是0,在严格模式下无效
十六进制
前两位是0x
浮点数
构成必须有小数点,小数点之后必须有数字
极大极小数值采用科学技术发3.125e7
浮点数值的最高精度是17位小数,0.1+0.2!0.3,因为运算时需要转换成二进制,且精度只支持到53位,所以运算后小数部分会被截断,再转换成十进制时会有误差
数值范围
5e-324 到 1.7976931348623157e+308
正无穷Infinity
负无穷-Infinity
判断是否是有穷,使用isFinite()函数
NaN
NaN !== NaN
isNaN()判断一个值是否是数值,但是像"10"和true是可以被转换成数值的
数值转换
方法
Number()/parseInt()/parseFloat()
转换结果
Boolean
true=>1, false=>0
Null
0
undefined
NaN
字符串
“011”
11
“1.1”
1.1
“0xf“
相同大小十进制数值
”“
0
其他
NaN
String
由零个或多个16位Unicode字符组成的字符序列
字符字面量
\n
换行
\t
制表
\b
退格
\r
回车
\f
进纸
\\
斜杠
单引号,可在字符串中使用
\"
双引号
\xnn
十六进制
\unnnn
十六进制表示unicode字符
转换字符串
几乎任何值都有的转换方法.toString()
操作符
一元操作符
递增和递减
递增
++
递减
--
递增递减规则
应用于字符串时,先转换为数字值;若不包含有效数字字符,则设置为NaN
应用于布尔值时,先转换为0和1
应用于对象时,先调用valueOf()方法
一元加减
作为数值转换,加为正,减为负
位操作符
按照内存中的二进制数表达进行运算
位运算
按位非
返回数值的反码
~
按位与
按位进行与操作
&
按位或
按位进行或操作
|
按位异或
按位进行异或操作,只有两位不相同才返回1,相同都返回0
^
左移
按位将数值除符号位的所有位向左移动制定位数,右边以0填充空位,不影响符号位
<<
右移
有符号的右移
按位将数值除符号位的所有位向右移动制定位数,左边以符号位填充空位
>>
无符号的右移
按位将数值所有位向右移动制定位数
>>>
数学运算操作符
加性
加法
+
特殊情况
操作数有NaN,则结果为NaN
Infinity+(Infinity或-Infinity)=Infinity
-Infinity+(-Inifinity)=-Infinity
0+0或-0=0
-0+(-0)=-0
减法
-
特殊情况
操作数有NaN,则结果为NaN
Infinity-Infinity=NaN
-Inifinity-(-Infinity)=NaN
Infinity-(-Inifinity)=Infinity
-Inifinity-Infinity=-Infinity
+0-(+0)=+0
-0-(+0)=-0
-0-(-0)=+0
乘性
乘法
*
特殊情况
操作数有NaN,则结果为NaN
Infinity*0=NaN
Infinity*非零,则按符号返回Infinity和-Infinity
Infinity*Infinity=Infinity
除法
/
特殊情况
操作数有NaN,则结果为NaN
Infinity/Infinity=NaN
0/0=NaN
非零/0=Infinity或-Infinity
Infinity/非零=Infinity或-Infinity
求模
%
逻辑运算操作符
布尔
逻辑非
!
逻辑与
&&
短路操作,第一个操作数能决定结果则不再求值第二个操作数
逻辑或
||
关系
小于
<
大于
>
小于等于
<=
大于等于
>=
相等
==
!=
===
!==
条件
? :
赋值
=
衍生
*=
/=
%=
+=
-=
<<=
>>=
>>>=
逗号
var num1=1, num2=2, num3=3
var num = (1, 2, 3, 0), num === 0
语句
条件语句
if-else
do-while
switch
循环语句
while
for
for-in
用来枚举对象的属性
break
立即退出循环,与label同用
continue
跳过当前循环的一次
with
将一段代码的作用域绑定到一个特定的对象中,其中的属性和方法可以直接访问,严格模式下禁止使用
with() {}
label
start: var a = 0;
用于break和continue语句引用
作用域与执行环境
执行环境
执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为,每个执行环境都有一个与之关联的变量对象保存所有的变量和函数
代码进入一个执行环境时,会创建变量对象的一个作用域链,保证对执行环境有权访问的所有变量和函数的有序访问
全局执行环境
window对象
是在Web浏览器中的全局环境
函数执行环境
作用域
作用域链
内部环境可通过作用域链访问所有的外部环境,反之不然
延长作用域链
try-catch语句的catch块会创建一个新的变量对象
with语句,将制定的对象添加到作用域链中
作用域链中的顺序
变量声明
使用var声明变量会自动添加到最接近的执行环境中
没有使用var声明的变量会添加到全局执行环境
查询标识符
向上主机查询与给定名字匹配的标识符,局部环境=>全局环境
模仿块级作用域
JS中没有块级作用域,只有全局作用域和函数中的作用域,所以采用立即执行函数来模仿块级作用域
(function() {
// ...
})()
私有变量
在函数内部的变量只能在函数内被访问,在函数中的方法也可以访问这些变量(闭包)
特权方法
有权访问私有变量和私有函数的公有方法
function Person(name) {
this.getName = function() {
return name;
}
this.setName = function() {
name = value;
}
}
静态私有变量
在立即执行函数中设置变量,该变量可以作为静态私有变量
(function() {
var name = "";
Person = function() {
name = value;
}
Person.prototype.getName = function() {
return name;
}
Person.prototype.setName = function(value) {
name = value;
}
})();
this
在单纯的函数调用中
this指向全局对象
在匿名函数中
一般都返回全局对象
作为对象的方法调用
this指向调用这个方法的对象
作为构造函数调用
通过函数生成一个新对象,this指向这个对象
apply、call和bind调用
this指的是这些方法中传入的第一个参数
编译与运行
编译
找到var和function关键字,做出对应的提升
执行
按照代码顺序的逻辑,正常进行执行
引用类型
Object
一组数据和功能的集合
创建对象实例
构造法
var o = new Object();
new
创建一个空对象
设置原型链(实例的内部将包含一个指针(内部属性),指向构造函数的原型对象)
让Func中的this指向obj,并执行Func的函数体
判断Func的返回值类型:如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象
对象字面量
var person = {
name: "nicholas"
}
Object实例属性和方法
constructor,即Object()
hasOwnProperty(propertyName)
isPrototypeOf(object)
propertyIsEnumerable(propertyName)
toLocaleString()
toString()
valueOf(),和toString()方法返回值相同
Array
创建数组实例
构造法
var colors = new Array(长度/逗号分隔的item);
数组字面量
尽量不要出现多余的逗号
检测数组
value instanceof Array
Array.isArray(value)
属性方法
转换方法
.toString()
.toLocaleString()
.valueOf()
.join()
栈方法
.push()
.pop()
队列方法
.push()
.shift()
.unshift()
排序方法
.reverse()
.sort(Function)
操作方法
.splice(start, end, [item1, item2...])
.slice()
位置方法
.indexOf(),从前向后
.lastIndexOf(),从后向前
迭代方法
.every(Func)
.filter(Func)
.forEach(Func)
.map(Func)
.some(Func)
归并方法
.reduce(prev, cur, index, array)
.reduceRight(prev, cur, index, array)
TypedArray
是一种通用的固定长度缓冲区类型,用来读取缓冲区中的二进制数据
创建ArrayBuffer
var ab = new ArrayBuffer(8)
创建ArrayBuffer的引用,可指定Int32/Int16/Uint8,可指定起始位置
var v1 = new Int32Array(b);
var v2 = new Uint8Array(b, 2);
var v3 = new Int16Array(b, 2, 2);
Date
创建日期实例
var now = new Date();
日期格式化方法
toString()
toLocaleString()
valueOF()
toDateString()
返回”星期 月 日 年“
toTimeString()
返回”时 分 秒 时区“
toLocaleDateString()
toLocaleTimeString()
toUTCString()
日期/时间对象的组件方法
getTime()
返回日期毫秒数
setTime(毫秒)
getDate()
getTimezoneOffset()
返回本地时间与UTC时间相差的分钟数
年
getFullYear()
取得4位数年份
getUTCFullYear()
setFullYear()
传入4位数年份进行设置
月
getMonth()
返回月份,0开始
getUTCMonth()
setMonth()
设置月份
setUTCMonth()
日
getDate()
返回几号
getUTCDate()
setDate()
设置天数
setUTCDate()
星期
getDay()
返回周几
getUTCDay()
时
getHours()
返回小时,0开始
getUTCHours()
setHours()
设置小时
setUTCHours()
分
getMinutes()
返回分钟数
getUTCMinutes()
setMinutes()
设置分钟数
setUTCMinutes()
秒
getSeconds()
返回秒数
getUTCSeconds()
setSecondes()
设置秒数
setUTCSeconds()
getMilliseconds()
获取毫秒数
getUTCMilliseconds()
setMilliseconds()
设置毫秒数
setUTCMilliseconds()
RegExp
正则表达式创建
字面量
var exp = / pattern / flags
/g,全局模式
/i,不区分大小写
/m,多行模式
构造法
var exp = new RegExp(pattern, flags)
实例属性
.global
.ignoreCase
.lastIndex
.multiline
.source
实例方法
.exec(str)
返回包含第一个匹配项的数组,设置g后可继续查找后面的新匹配项
.test(str)
返回是否匹配bolean
局限性
不支持\A和\Z作为字符串开始和结尾
不支持向后查找
不支持并集和交集
不支持原子组
不支持条件匹配
不支持注释
不支持Unicode(单字符除外)
不支持命名捕获组,但支持编号捕获组
Function
特点
不支持重载
不能对同一个函数进行两次定义,否则只会以最后一次定义为准
函数名可作为变量,作为值来使用
函数声明
解析器会率先读取函数声明,在执行任何代码之前可用
函数表达式
需要等到解析器执行到它所在的行才会真正被解释执行 - 函数声明提升
参数
函数的参数可以在函数中通过访问arguments获得;注意arguments不是数组实例,只是类数组
传参
ECMAScript中所有的函数参数都是按值传递
传递基本类型:传入的参数会被赋值到一个局部变量,原本的变量不发生变化
传递引用类型:例如对象类型参数传入,其地址会被复制为一个局部变量,修改其属性会反应在函数外部
为什么是按值传递?
对象作为参数传入后,给这个变量重新赋值一个对象并修改其属性,但是原来的对象并不会改变。这是因为函数内部重新给参数赋值对象时,这个变量引用的就是一个局部对象,局部对象会在函数执行完毕后被立即销毁
内部属性
arguments
保存函数参数
属性
callee
指向拥有这个arguments对象的函数的指针(就是当前执行的函数本身的引用),当函数被重写时,还能使用这个属性去引用原函数
this
全局
对象
caller
function.caller可以返回当前调用这个方法的实例,不可被赋值
函数实例的属性
length
表示函数希望接受的命名参数个数
prototype
分支主题
函数实例的方法
apply()
修改函数体内this对象的值,修改其作用域
两个参数,作用域和参数数组
call()
作用同上
参数为作用域后跟着参数item1, item2...
bind()
创建一个函数实例,this值即bind函数传入的参数;仅绑定this到新的对象,不执行
递归
为了避免递归调用时原函数被修改指向null或另一个值,可以采取
使用arguments.callee来递归调用该函数
严格模式下不能使用arguments.callee,可以使用命名函数表达式来解决
var factorial = function f(num) {
if (num <= 1) {
return 1;
} else {
return num * f(num - 1);
}
}
闭包
定义
定义在函数中的函数,所有函数都是闭包
指有权访问另一个函数作用域中的变量的函数;在一个函数内部定义的函数会将外部函数的活动对象添加到它的作用域链中
作用
让外界读取某个函数内部的变量
function secret() {
var a = 0;
var b = 1;
return function () {
console.log(a, b);
}
}
让这些变量始终保持在内存中
可能会造成内存泄漏:两个变量互相引用
通过闭包返回的方法来修改函数内部的数据
创建一个私有的空间,保护私有数据
闭包的生命周期
当外层函数返回后,其执行环境的作用域链会被销毁,但是它的活动对象仍会留在内存中,这是因为其中的匿名函数还有包含这个活动对象的作用域链,只有这个匿名函数被销毁,外层函数的活动对象才会被销毁
通过闭包使得循环中的变量每次都能返回当次的值
匿名函数的执行环境是全局的,因此匿名函数中的this通常指向window
函数柯里化
是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术
作用
参数复用
提前确认
延迟运行
性能
存取arguments对象比较慢
老版本浏览器在arguments.length的实现很慢
apply和call也比较慢
创建大量嵌套作用域和闭包函数会降低空间和性能
基本包装类型
每当新建一个基本类型值,后台会创建相对应的引用类型实例
String
Boolean
Number
Global对象
全局对象
方法
isNaN()
isFinite()
parseInt()
parseFloat()
URI编码/解码方法
encodeURI()
除空格之外其他字符都不变
encodeURIComponent()
所有非字母字符进行转换
decodeURI()
decodeURIComponent()
eval()
接手一个参数,即js代码字符串
属性
特殊值
undefined
NaN
Infinity
构造函数
Object
Array
Function
Boolean
String
Number
Date
RegExp
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
window对象
Math对象
属性
.E
自然对数的底数
.LN10
10的自然对数
.LN2
2的自然对数
.LOG2E
以2位底e的对数
.LOG10E
以10为底e的对数
.PI
圆周率
.SQRT1_2
1/2的平方根
.SQRT2
2的平方根
方法
min()
max()
ceil()
round()
floor()
random()
abs()
exp()
返回Math.E的num次幂
log()
pow()
sqrt()
acos()
反余弦值
asin()
反正弦值
atan()
反正切值
atan2(y,x)
y/x的反正切值
cos()
sin()
tan()
复制
两个指针指向同一个地址,对其中一个对象进行修改,另一个也会同步改变;但两者是不等的;
深复制
在计算机中开辟了一块内存地址用于存放复制的对象
数组
for循环重新新建数组插入
concat连接空数组
slice(start, end)赋值
...操作符
对象
jquery,$.extend({}, obj)
JSON.parse(JSON.stringify(obj))
递归实现
var clone = function (obj) {
if(obj === null) return null
if(typeof obj !== 'object') return obj;
if(obj.constructor===Date) return new Date(obj);
var newObj = new obj.constructor (); //保持继承链
for (var key in obj) {
if (obj.hasOwnProperty(key)) { //不遍历其原型链上的属性
var val = obj[key];
newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除与函数名的耦合
}
}
return newObj;
};
浅复制
只是复制了引用类型的引用地址,对象改变,被拷贝出来的对象也会相应改变
面向对象
属性
属性类型
数据属性
Configurable
是否可被delete,默认为true
Enumerable
是否可被for-in循环,默认为true
Writable
能否修改属性的值,默认为true
Value
包含这个属性的值,默认为undefined
访问器属性
有get和set方法的属性
Configurable
Enumerable
get
set
数据属性和访问器属性相互转换,只要对应添加get/set和Writable/Value即可
定义/修改属性
Object.defineProperty(obj, prop, {attr, attrVal})
读取属性的特性
Object.getOwnPropertyDescriptor(obj, prop)
对象
创建对象
字面量模式
工厂模式
通过函数传入指定对象的属性值进行对象的创建,不用new
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
}
return o;
}
缺点:没有解决对象识别的问题,不知道一个对象的类型是什么;
构造函数模式
通过写一个构造函数,new出新的对象;任何函数通过new都可以成为构造函数;
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
alert(this.name);
}
}
var p1 = new Person('Peter', 29, 'taylor');
缺点:不同实例上的同名函数是不相等的
原型模式
每个函数都有一个prototype属性,该属性指向一个对象,包含了可以有特定类型的所有实例共享的属性和方法
function Person(){}
Person.prototype.name = "Peter";
Person.prototype.age = 21;
Person.prototype.job = "Taylor";
Person.prototype.sayName = function() {
alert(this.name);
}
var p1 = new Person();
Person.prototype.constructor => Person 构造函数
function Person(){}
Person.prototype = {
name: "Nicholas",
age: 29,
job: Programmer,
sayName: function() {
alert(this.name);
}
}
Person.prototype.constructor !== Person,但是用instanceof操作符还是可以判断是Person类的对象;
可以通过设置一个constructor属性指向Person
通过Object.getPrototypeOf()可以返回对象的原型
通过.hasOwnProperty(prop)可以查看是否是当前对象还是原型上的属性
缺点
省略了构造函数传参初始化的步骤
一个实例改变其中的引用类型属性,会同步到其他实例中
组合模式(构造+原型)
构造函数进行传参定义实例属性,原型模式用于定义方法和共享属性
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["shelby"];
}
Person.prototype = {
constructor: Person,
sayName: function() {
alert(this.name);
}
}
动态原型模式
在构造函数中初始化原型
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
if (typeof this.sayName != 'function') {
Person.prototype.sayName = function() {
alert(this.name);
}
}
}
寄生构造函数模式
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
}
return o;
}
var p1 = new Person('Peter', 29, 'Taylor')
稳妥构造函数模式
没有公共属性的工厂模式
function Person(name, age, job) {
var o = new Object();
o.sayName = function() {
alert(name);
}
return o;
}
继承
原型和原型链
通过SubType.prototype = new SuperType();对原型进行串联;
所有函数的默认原型都是Object的实例,所以默认的原型都会包含一个指向Object.prototype的内部指针
确定原型和实例的关系
使用instanceof操作符
实例上的isPrototypeOf()方法
问题
一个实例改变其中的引用类型属性,会同步到其他实例中
不能向超类的构造函数中传递参数
prototype和__proto__
prototype
!!!函数独有的属性
__proto__
每个对象都有的属性
new出来的对象,__proto__===constructor.prototype是成立的
Object.create()创建的对象有可能不是
继承方式
原型链继承
function Show(){
this.name="run";
}
function Run(){
this.age="20";
}
Run.prototype=new Show();
var show=new Run();
借用构造函数
function SuperType(name) {
this.name = name;
}
function SubType() {
SuperType.call(this, "Peter");
this.age = 29;
}
组合继承
伪经典继承,结合原型链和构造函数
function SuperType(name) {
this.name = name;
}
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
原型式继承
借助原型,可以基于已有的对象创建新对象
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var person = {
name: "Peter",
friends: ["Shelby"]
}
var anotherPerson = Object.create(person);
寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部增强对象,并返回该对象
function createAnother(original) {
var clone = Object.create(original);
clone.sayHi = function() {
alert("hi");
}
return clone;
}
寄生组合式继承
使用寄生式继承来继承超类型的原型,然后将结果指定给子类型的原型
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
BOM
window
全局属性与方法
窗口关系与框架
top
指向最外层框架
parent
指向当前父框架
self
指向自己
窗口的位置
screenLeft
screenTop
screenX
screenY
窗口的大小
视口的大小
document.body.clientWidth
document.body.clientHeight
窗口本身大小
outerWidth
outerHeight
页面视图去的大小(去边框)
innerWidth
innerHeight
窗口位置移动
resizeTo()
resizeBy()
打开新窗口
window.open(url, tabName, propStr)
可配置属性propStr
fullscreen
height
width
top
left
location
是否显示地址栏
menubar
是否显示菜单栏
status
是否显示状态栏
toolbar
是否显示工具栏
resizable
是否可拖动改变大小
scrollbars
是否允许滚动条
间歇与超时调用
setTimeout(function, timeout)
setInterval(function(){}, timeout)
对话框
alert()
confirm()
prompt()
使用var定义变量是全局变量,但是window对象上定义属性是有区别的
var age = 20;
delete window.age;
// return false
window.color = 'red'
delete window.color;
// return true;
窗口与框架
top
top对象始终指向最高层框架(浏览器窗口)
top.frames
如果页面中包含框架,则每个框架都有自己的window对象
parent
指当前框架的直接上层框架
location
属性
hash
host
带有端口
hostname
href
pathname
port
protocol
search
刷新页面
带有历史记录
location.assign(url)
window.location = url;
location.href = url
不带有历史记录
location.replace()
重新加载
reload()
缓存中加载
reload(true)
重新从服务器请求
navigator
screen
history
go(number)
正数前进
负数返回
forward()
前进一页
back()
后退一页
DOM
浏览器把拿到的html代码,结构化成一个浏览器能识别并且js可操作的一个模型
节点(Node)
类型
Node.ELEMENT_NODE
Node.ATTRIBUTE_NODE
Node.TEXT_NODE
Node.CDATA_SECTION_NODE
Node.ENTITY_REFERENCE_NODE
Node.ENTITY_NODE
Node.PROCESSING_INSTRUCTION_NODE
Node.COMMENT_NODE
Node.DOCUMENT_NODE
Node.DOCUMENT_TYPE_NODE
Node.DOCUMENT_FRAGMENT_NODE
Node.NOTATION_NODE
关系
.childNode
每个节点都有该属性,保存着一个NodeList对象
document
JS通过Document类型表示文档,在浏览器中,document对象时HTMLDocument实例
特征
nodeType:9,DOCUMENT_NODE
子节点
document.childNodes
document.firstChild
文档信息
document.title
document.URL
document.domain
document.referrer
查找元素
.getElement[s]By[Id, TagName, Class]
特殊属性
.anchors
.applets
.forms
.images
.links
能力监测
.implementation
DOM操作
获取节点
元素
子元素
父元素
编辑节点
移动节点
新增节点
删除节点
选择符API
querySelector()
querySelectorAll()
matchesSelector()
元素遍历
扩展
专有扩展
HTML5
DOM2和DOM3
变化
样式
遍历
范围
客户端检测
能力检测
检测要求
先检测最常用的特性
必须测试实际要用到的特性
可靠的能力监测
function isHostMethod(object, property) {
var t = typeof object[property];
return t == 'function' || (!!( t == 'object' && object[property])) || t == 'unknown';
}
怪癖检测
用户代理检测
事件
事件流
冒泡
嵌套的父子标签,在父子元素都绑定了相同类型的事件监听后,对子元素操作,父元素也会有相应的反应;从子到父冒泡;
document.querySelector().addEventListener('click', function(){})
addEventListener()必须用removeEventListener()解除
事件委托
利用事件冒泡,指定一个事件处理程序,可以管理某一类型的所有事件。主要是处理需要绑定过多事件的情况(不需要每一个元素都绑定事件)
捕获
与冒泡相反,点击父元素,会引起子元素的反应
document.querySelector().addEventListener('click', function(){}, true)
DOM事件流
事件处理程序
HTML
DOM0
DOM2
IE
跨浏览器
事件对象
DOM事件对象
IE事件对象
跨浏览器事件对象
事件类型
UI事件
焦点事件
鼠标与滚轮事件
键盘与文本事件
复合事件
变动事件
HTML5事件
设备事件
触摸与手势事件
模拟时间
DOM
IE
Canvas
错误处理与调试
浏览器报告的错误
错误处理
try-catch
抛出错误
错误处理策略
常见错误类型
区分致命错误和非致命错误
调试技术
控制台输出
记录到当前页面
抛出错误
常见IE错误
模块化
JSON
语法
解析与序列化
其他
设计模式
设计原则(SOLID)
单一职责原则SRP
一个对象或方法只做一件事 - 细粒度
开放封闭原则OCP
对扩展开放,对修改封闭
增加需求时,扩展新代码,而非修改已有代码
里氏替换原则LSP
子类能覆盖父类,父类能出现的地方子类就能出现
接口隔离原则ISP
保持接口的单一独立
依赖倒转原则DIP
面向接口编程,依赖于抽象而不依赖于具体;使用方只关注接口而不关注具体类的实现
常见设计模式
单例模式
只能被实例化一次(构造函数给实例添加属性与方法)
日志、数据库连接池、计数器
原型模式
工厂模式
一个方法可以解决多个类似的问题
有很多子类,并且经常发生变化时;创建和使用分离
发布订阅模式
Vue子组件向父组件通信
子主题 1
观察者模式
DOM操作
沙箱模式
函数放到自执行函数里面,但要用闭包暴露接口,用变量接收暴露的接口,再调用里面的值
混入模式Mixin
提供能够被一个或者一组子类简单继承功能的类
Vue中通过mergeOptions来合并配置到options上
多继承
call/apply+mixin
es6间接继承(继承链)
兼容性
客户端检测
性能问题
垃圾收集
标记清除
将离开某个执行环境的变量进行标记,垃圾收集器会销毁这些带标记的值
运行时给存储在内存中的所有变量添加标记
去掉运行环境中的变量以及环境中变量所引用的变量的标记
IE、Firefox、Opera、Chrome和Safari
v8垃圾回收机制
内存分类
新生代
存活时间较短的对象
老生代
存活时间较长/常驻内存的对象
Scavenge算法
Cheney算法
是一种采用复制的方式实现的垃圾回收算法,它将堆内存一分为二,这两个空间中只有一个处于使用中,一个处于闲置状态。处于是使用状态的空间称为From空间,处于闲置的空间称为To空间。分配对象时,先是在From空间中进行分配,当开始垃圾回收时,会检查From空间中的存活对象,并将这些存活对象复制到To空间中,而非存活对象占用的空间被释放。完成复制后,From空间和To空间的角色互换。
复制升级需要检查
是否经历过Scacenge回收
当To空间的使用应超过25%时,则这个对象直接晋升到老生代空间中
Mark-Sweep 和 Mark-Compact
引用计数
跟踪记录每个值被引用的次数,垃圾收集器运行时会释放引用次数为0的值所占内存
内存泄漏
情况
对DOM、BOM对象的引用
DOM
addEventListener
BOM
Websocket.on()
变量间循环引用
闭包导致的外层函数无法释放
事件内存与性能
移除事件处理程序
ES6
let和const
与var的区别
var
声明全局变量(在for循环中的迭代变量,跳出循环依旧可以使用)
可被修改
不初始化会输出undefined,不会报错
let
必须先声明再使用,不可在声明之前调用,即没有变量声明提升
具有块级作用域
可被修改
const
用于声明常量,必须初始化
具有块级作用域
不可修改
暂时性死区
指let和const声明变量之前,该变量都是不可用的,在语法上被称为”暂时性死区“
注意:这意味着typeof不再是一个百分之百安全的操作
变量解构赋值
引用类型的扩展
字符串
正则
数值
函数
数组
对象
箭头函数
特点
没有this
能够捕获其所在执行环境的this值作为自己的this值,是继承其父执行环境的this
不能作为构造函数,不能使用new操作符
不能绑定arguments
没有原型属性
不能简单返回对象的字面量
不能当做Generator函数,不能使用yield关键字
箭头函数不能换行
不能使用call、apply和bind改变其this值
形式(param) => {}
Symbol
表示独一无二的值
使用方法
let s = Symbol();
typeof s
// "symbol"
s.toString()
注意事项
入参相同,返回值也不同
Symbol值不能与其他类型值进行运算
可以转化为字符串
属性
description
添加一个描述
方法
.for(str)
传参为一个字符串,如果已经有这个Symbol值则返回,没有就新建一个
.keyFor(param)
传入一个Symbol值的变量,返回已登记的 Symbol 类型值的key
.match()
当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值
.hasInstance()
当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
. isConcatSpreadable()
等于一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开
使用场景
作为对象属性名
定义一组常量的值,均不相等
消除魔法字符串和魔法数字
Set
类似于数组,但是成员的值都是唯一的,没有重复的值
实例化
let s = new Set(iterator)
方法
.add(value)
返回Set
.delete(value)
返回Set
.has(value)
boolean
.clear()
.keys()
返回键名的遍历器
.values()
返回值的遍历器
.entries()
返回键值对的遍历器
.forEach()
返回回调函数遍历每个成员
属性
.size
WeakSet
结构与 Set 类似,也是不重复的值的集合
成员只能是对象
对象都是弱引用,垃圾回收机制不会管你是否在WeakSet里面,没有引用就会立刻回收
Map
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
实例化
const set = new Set([
['foo', 1],
['bar', 2]
]);
任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构(详见《Iterator》一章)都可以当作Map构造函数的参数
属性
.size
方法
.set(key, val)
.get(key)
.has(key)
.delete(key)
.clear()
.keys()
返回键名的遍历器
遍历顺序都是插入的顺序
.values()
返回值的遍历器
.entries()
返回键值对的遍历器
.forEach()
返回回调函数遍历每个成员
数据类型转换
Array
Map=>Array
[...myMap]
Array=>Map
new Map([
[true, 7],
[{foo: 3}, ['abc']]
])
Object
Map=>Object
所有key必须都是String类型
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
Object=>Map
let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));
JSON
Map=>JSON
所有key必须都是String类型
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap));
}
JSON=>Map
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')
WeakMap
与Map类似,但是只接受对象/null作为键名
对象都是弱引用,垃圾回收机制不会管你是否在WeakSet里面,没有引用就会立刻回收
Proxy
Reflect
Promise
基本用法
创建Promise实例
const promise = new Promise((resolve, reject) => { if (...) { resolve(); } else { reject(); } });
Promise实例方法
.all(iterable)
传入空的可迭代对象,返回一个已完成状态的Promise
传入非空时返回一个异步完成Promise
任意一个promise失败,则整体立即返回失败,返回错误信息是第一个失败的promise结果
.race(iterable)
返回一个新的promise,返回的新实例是跟随参数中最先改变状态的那个实例
.resolve(value)
返回一个给定值解析后的Promise对象
任意赋值的变量或值
thenable对象
{
then: function(resolve, reject) {
resolve(42);
}
}
无参数
.reject(reason)
.catch()
用于制定发生错误时的回调函数,在resolve()之后抛出的错误不会被捕获;如果不使用catch,那么promise对象抛出的错误不会传递到外层代码
状态
pending
fulfilled
rejected
状态转换
pending => fulfilled
pending => rejected
实现原理
class PromiseNew {
constructor(fn) {
this.state = 'PENDING';
this.doneList = [];
this.failList = [];
fn(this.resolve.bind(this), this.reject.bind(this));
}
// 注册成功处理函数
done(handle) {
if (typeof handle === 'function') {
this.doneList.push(handle);
} else {
throw new Error('缺少回调函数');
}
return this;
}
// 注册失败处理函数
fail(handle) {
if (typeof handle === 'function') {
this.failList.push(handle);
} else {
throw new Error('缺少回调函数');
}
return this;
}
// 同时注册成功和失败处理函数
then(success, fail) {
this.done(success || function () { }).fail(fail || function () { });
return this;
}
// 一个处理函数注册到成功和失败
always(handle) {
this.done(handle || function () { }).fail(handle || function () { });
return this;
}
// 更新state为:RESOLVED,并且执行成功处理队列
resolve() {
this.state = 'RESOLVED';
let args = Array.prototype.slice.call(arguments);
setTimeout(function () {
this.doneList.forEach((item, key, arr) => {
item.apply(null, args);
arr.shift();
});
}.bind(this), 200);
}
// 更新state为:REJECTED,并且执行失败处理队列
reject() {
this.state = 'REJECTED';
let args = Array.prototype.slice.call(arguments);
setTimeout(function () {
this.failList.forEach((item, key, arr) => {
item.apply(null, args);
arr.shift();
});
}.bind(this), 200);
}
}
手写promise.all
Promise.prototype.all = (values)=>{
return new Promise((resolve,reject)=>{
let resultArr = []
let count = 0
values.forEach((promise,index)=>{
promise.then((value)=>{
resultArr[index] = value
if(++count === values.length){
resolve(resultArr)
}
},reject)
});
});
}
Generator
Generator 函数是一个状态机,封装了多个内部状态;执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态(一种可以逐步暂停的函数)
使用方法
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
与Iterator接口
子主题 4
async
Class
基本语法
class Example {
constructor(param) {
this.param = param;
}
}
constructor
默认返回实例对象,this
类中定义方法
静态方法 static
不会被实例继承,只能通过类本身来调用
可以被子类继承
原型方法,无修饰符
实例方法,在constructor中this.func =
类中定义属性
关键词get
对于某个属性设置存值函数,默认是返回getter关键词
关键词set
对于某个属性设置,默认是返回setter关键词,可以拦截进行一定的存取行为
类的属性名可以使用表达式,但是需要用[]括起来
特点
不可重复声明
类定义不会被提升,必须要在访问前对类进行定义
方法间不能加分号
类的使用
必须通过new操作符进行实例化
可以共享原型对象
继承
如何继承
使用extends关键字
class ColorPoint extends Point {
}
子类
只能在constructor中调用super方法,否则得不到this对象。是因为子类自己的this对象必须先通过父类的构造函数完成构造,得到与父类相同的实例属性与方法,然后再进行加工
如果没有constructor方法,会默认调用一下super
可以通过Object.getPrototypeOf()方法获取子类的父类
原型
prototype
子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性
__proto__
子类的__proto__属性,表示构造函数的继承,总是指向父类
实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性
Module
Decorator
只能作用于类或类的方法上,如果一个类/类的方法都用了Decorator,类方法的Decorator由于类的Decorator执行
对koa-router中间件包装
写好添加前缀的方法,返回新的路由名称
Ajax
跨域
一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
跨域导致的问题
无法读取非同源网页的cookie、localStorage和IndexedDB
无法接触非同源网页的DOM
无法向非同源地址发送Ajax请求
解决办法
临时方案
非同源页面使用document.domain设置相同的值,即可共享cookie
使用window.postMessage()可以实现非同源页面间数据传递、iframe传递消息、跨域数据传递
较好方案
JSONP
只支持get方法
实现方法
<script src="http://test.com/data.php?callback=dosomething"></script>
<script type="text/javascript">
function dosomething(res){
console.log(res.data)
}
</script>
function jsonp(obj) {
window["callback"] = function(object) {
obj.success(JSON.parse(object));
}
var script = document.createElement("script");
script.src = obj.url + "?fn=callback";
for(key in obj.data){
script.src +="&" + key + "=" + obj.data[key];
}
document.getElementsByTagName("body")[0].appendChild(script);
}
原生ajax
function ajax ({reqType = 'GET', url, data = {}, header, success}) {
var xmlHttpReq = new XMLHttpRequest();
if (reqType === 'GET' && Object.keys(data).length > 0) {
url += '?';
for(key in data){
url +="&" + key + "=" + data[key];
}
}
xmlHttpReq.open(reqType, url);
xmlHttpReq.setRequestHeader(header);
xmlHttpReq.send(reqType === 'POST' ? JSON.stringify(data) : null);
xmlHttpReq.onreadystatechange = function() {
if(xmlHttpReq.readyState == 4){
if (xmlHttpReq.status == 200) {
success({data: xmlHttpReq.responseText, text: xmlHttpReq.responseXML});
}
}
}
}
$.ajax({
url: 'http://www.test.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
CORS
跨资源分享
实现方法
普通跨域请求
Access-Control-Allow-Origin
带cookie跨域请求
前后端都需要设置
前端
$.ajax({
url: 'http://www.test.com:8080/login',
type: 'get',
data: {},
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
});
axios.defaults.withCredentials = true
Vue.http.options.credentials = true
后端
http.createServer(function (req, res) {
res.setHeader("Access-Control-Allow-Origin", "*");
}
0 条评论
下一页