# 编程面试题整理

ok，你准备好了吗？咱们开始吧！

JS

Number
String
Boolean
Null
Undefined
Symbol（ES6新增数据类型）
bigInt

Object
Array
Date
Function
RegExp

// 0.1 和 0.2 都转化成二进制后再进行运算
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011001100110011010 =
0.0100110011001100110011001100110011001100110011001100111

// 转成十进制正好是 0.30000000000000004
1
2
3
4
5
6

// 0.2 和 0.3 都转化为二进制后再进行计算
0.001100110011001100110011001100110011001100110011001101 +
0.0100110011001100110011001100110011001100110011001101 =
0.10000000000000000000000000000000000000000000000000001 //尾数为大于52位

// 而实际取值只取52位尾数位，就变成了
0.1000000000000000000000000000000000000000000000000000 //0.5
1
2
3
4
5
6
7

typeof

instanceof

constructor

Object.prototype.toString.call()

boolean 、 number 、 undefined 、 array 、 function 、 object 、 date 、 math 数据类型。

// -----------------------------------------typeof
typeof undefined // 'undefined'
typeof '10' // 'String'
typeof 10 // 'Number'
typeof false // 'Boolean'
typeof Symbol() // 'Symbol'
typeof Function // ‘function'
typeof null // ‘Object’
typeof [] // 'Object'
typeof {} // 'Object'

// -----------------------------------------instanceof
function Foo() { }
var f1 = new Foo();
var d = new Number(1)

console.log(f1 instanceof Foo);// true
console.log(d instanceof Number); //true
console.log(123 instanceof Number); //false   -->不能判断字面量的基本数据类型

// -----------------------------------------constructor
var d = new Number(1)
var e = 1
function fn() {
console.log("ming");
}
var date = new Date();
var arr = [1, 2, 3];
var reg = /[hbc]at/gi;

console.log(e.constructor);//ƒ Number() { [native code] }
console.log(e.constructor.name);//Number
console.log(fn.constructor.name) // Function
console.log(date.constructor.name)// Date
console.log(arr.constructor.name) // Array
console.log(reg.constructor.name) // RegExp

//-----------------------------------------Object.prototype.toString.call()
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(123)); // "[object Number]"
console.log(Object.prototype.toString.call("abc")); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"

function fn() {
console.log("ming");
}
var date = new Date();
var arr = [1, 2, 3];
var reg = /[hbc]at/gi;
console.log(Object.prototype.toString.call(fn));// "[object Function]"
console.log(Object.prototype.toString.call(date));// "[object Date]"
console.log(Object.prototype.toString.call(arr)); // "[object Array]"
console.log(Object.prototype.toString.call(reg));// "[object RegExp]"


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
instanceof原理⭐⭐⭐⭐⭐

instanceof原理实际上就是查找目标对象的原型链
function myInstance(L, R) {//L代表instanceof左边，R代表右边
var RP = R.prototype
var LP = L.proto
while (true) {
if(LP == null) {
return false
}
if(LP == RP) {
return true
}
LP = LP.proto
}
}
console.log(myInstance({},Object));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

000 对象
1 整型
010 双精度类型
100字符串
110布尔类型

===是严格意义上的相等，会比较两边的数据类型和值大小

==是非严格意义上的相等，

Null == Undefined ->true
String == Number ->先将String转为Number，在比较大小
Boolean == Number ->现将Boolean转为Number，在进行比较
Object == String，Number，Symbol -> Object 转化为原始类型

call和apply实现思路主要是：

bind实现思路

new出来的话返回空对象，但是实例的__proto__指向_this的prototype

Array.prototype.slice.call()
call:

Function.prototype.myCall = function (context) {
// 先判断调用myCall是不是一个函数
// 这里的this就是调用myCall的
if (typeof this !== 'function') {
throw new TypeError("Not a Function")
}

// 不传参数默认为window
context = context || window

// 保存this
context.fn = this

// 保存参数
let args = Array.from(arguments).slice(1)   //Array.from 把伪数组对象转为数组

// 调用函数
let result = context.fn(...args)

delete context.fn

return result

}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apply

Function.prototype.myApply = function (context) {
// 判断this是不是函数
if (typeof this !== “function”) {
throw new TypeError(“Not a Function”)
}

  let result

// 默认是window
context = context || window

// 保存this
context.fn = this

// 是否传参
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn

return result
}


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
bind

Function.prototype.myBind = function(context){
// 判断是否是一个函数
if(typeof this !== "function") {
throw new TypeError("Not a Function")
}
// 保存调用bind的函数
const _this = this
// 保存参数
const args = Array.prototype.slice.call(arguments,1)
// 返回一个函数
return function F () {
// 判断是不是new出来的
if(this instanceof F) {
// 如果是new出来的
// 返回一个空对象，且使创建出来的实例的__proto__指向_this的prototype，且完成函数柯里化
return new _this(...args,...arguments)
}else{
// 如果不是new出来的改变this指向，且完成函数柯里化
return _this.apply(context,args.concat(...arguments))
}
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

new内部：

// 手写一个new
function myNew(fn, ...args) {
// 创建一个空对象
let obj = {}
// 使空对象的隐式原型指向原函数的显式原型
obj.__proto__ = fn.prototype
// this指向obj
let result = fn.apply(obj, args)
// 返回
return result instanceof Object ? result : obj
}


1
2
3
4
5
6
7
8
9
10
11

eval执行上下文

for循环中的保留i的操作

Object的隐式原型是null

// ----------------------方法一：原型继承
// 原型继承
// 把父类的实例作为子类的原型
// 缺点：子类的实例共享了父类构造函数的引用属性   不能传参

var person = {
friends: ["a", "b", "c", "d"]
}

var p1 = Object.create(person)

p1.friends.push("aaa")//缺点：子类的实例共享了父类构造函数的引用属性

console.log(p1);
console.log(person);//缺点：子类的实例共享了父类构造函数的引用属性


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

// ----------------------方法二：组合继承
// 在子函数中运行父函数，但是要利用call把this改变一下，
// 再在子函数的prototype里面new Father() ,使Father的原型中的方法也得到继承，最后改变Son的原型中的constructor

// 缺点：调用了两次父类的构造函数，造成了不必要的消耗，父类方法可以复用
// 优点可传参，不共享父类引用属性
function Father(name) {
this.name = name
this.hobby = ["篮球", "足球", "乒乓球"]
}

Father.prototype.getName = function () {
console.log(this.name);
}

function Son(name, age) {
Father.call(this, name)
this.age = age
}

Son.prototype = new Father()
Son.prototype.constructor = Son

var s = new Son("ming", 20)

console.log(s);


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

// ----------------------方法三：寄生组合继承
function Father(name) {
this.name = name
this.hobby = ["篮球", "足球", "乒乓球"]
}

Father.prototype.getName = function () {
console.log(this.name);
}

function Son(name, age) {
Father.call(this, name)
this.age = age
}

Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son

var s2 = new Son("ming", 18)
console.log(s2);


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
extend

// ----------------------方法四：ES6的extend（寄生组合继承的语法糖）
//     子类只要继承父类，可以不写 constructor ，一旦写了，则在 constructor 中的第一句话
// 必须是 super 。

class Son3 extends Father { // Son.prototype.__proto__ = Father.prototype
constructor(y) {
super(200)  // super(200) => Father.call(this,200)
this.y = y
}
}


1
2
3
4
5
6
7
8
9
10

​ 内存泄露是指不再用的内存没有被及时释放出来，导致该段内存无法被使用就是内存泄漏

// ----------------------------------------------浅拷贝
// 只是把对象的属性和属性值拷贝到另一个对象中
var obj1 = {
a: {
a1: { a2: 1 },
a10: { a11: 123, a111: { a1111: 123123 } }
},
b: 123,
c: "123"
}
// 方式1
function shallowClone1(o) {
let obj = {}

for (let i in o) {
obj[i] = o[i]
}
return obj
}

// 方式2
var shallowObj2 = { ...obj1 }

// 方式3
var shallowObj3 = Object.assign({}, obj1)

let shallowObj = shallowClone1(obj1);

shallowObj.a.a1 = 999
shallowObj.b = true

console.log(obj1);  //第一层的没有被改变，一层以下就被改变了

// ----------------------------------------------深拷贝

// 简易版
function deepClone(o) {
let obj = {}
for (var i in o) {
// if(o.hasOwnProperty(i)){
if (typeof o[i] === "object") {
obj[i] = deepClone(o[i])
} else {
obj[i] = o[i]
}
// }
}
return obj
}

var myObj = {
a: {
a1: { a2: 1 },
a10: { a11: 123, a111: { a1111: 123123 } }
},
b: 123,
c: "123"
}

var deepObj1 = deepClone(myObj)
deepObj1.a.a1 = 999
deepObj1.b = false
console.log(myObj);

// 简易版存在的问题：参数没有做检验，传入的可能是 Array、null、regExp、Date
function deepClone2(o) {
if (Object.prototype.toString.call(o) === "[object Object]") {  //检测是否为对象
let obj = {}
for (var i in o) {
if (o.hasOwnProperty(i)) {
if (typeof o[i] === "object") {
obj[i] = deepClone(o[i])
} else {
obj[i] = o[i]
}
}
}
return obj
} else {
return o
}
}

function isObject(o) {
return Object.prototype.toString.call(o) === "[object Object]" || Object.prototype.toString.call(o) === "[object Array]"
}

// 继续升级，没有考虑到数组，以及ES6中的map、set、weakset、weakmap
function deepClone3(o) {
if (isObject(o)) {//检测是否为对象或者数组
let obj = Array.isArray(o) ? [] : {}
for (let i in o) {
if (isObject(o[i])) {
obj[i] = deepClone(o[i])
} else {
obj[i] = o[i]
}
}
return obj
} else {
return o
}
}

// 有可能碰到循环引用问题  var a = {}; a.a = a; clone(a);//会造成一个死循环
// 循环检测
// 继续升级
function deepClone4(o, hash = new map()) {
if (!isObject(o)) return o//检测是否为对象或者数组
if (hash.has(o)) return hash.get(o)
let obj = Array.isArray(o) ? [] : {}

hash.set(o, obj)
for (let i in o) {
if (isObject(o[i])) {
obj[i] = deepClone4(o[i], hash)
} else {
obj[i] = o[i]
}
}
return obj
}

// 递归易出现爆栈问题
//  将递归改为循环，就不会出现爆栈问题了
var a1 = { a: 1, b: 2, c: { c1: 3, c2: { c21: 4, c22: 5 } }, d: 'asd' };
var b1 = { b: { c: { d: 1 } } }
function cloneLoop(x) {
const root = {};
// 栈
const loopList = [  //->[]->[{parent:{a:1,b:2},key:c,data:{ c1: 3, c2: { c21: 4, c22: 5 } }}]
{
parent: root,
key: undefined,
data: x,
}
];
while (loopList.length) {
// 深度优先
const node = loopList.pop();
const parent = node.parent; //{} //{a:1,b:2}
const key = node.key; //undefined //c
const data = node.data; //{ a: 1, b: 2, c: { c1: 3, c2: { c21: 4, c22: 5 } }, d: 'asd' }  //{ c1: 3, c2: { c21: 4, c22: 5 } }}
// 初始化赋值目标，key 为 undefined 则拷贝到父元素，否则拷贝到子元素
let res = parent; //{}->{a:1,b:2,d:'asd'} //{a:1,b:2}->{}
if (typeof key !== 'undefined') {
res = parent[key] = {};
}
for (let k in data) {
if (data.hasOwnProperty(k)) {
if (typeof data[k] === 'object') {
// 下一次循环
loopList.push({
parent: res,
key: k,
data: data[k],
})
} else {
res[k] = data[k];
}
}
}
}
return root
}

function deepClone5(o) {
let result = {}
let loopList = [
{
parent: result,
key: undefined,
data: o
}
]

while (loopList.length) {
let node = loopList.pop()
let { parent, key, data } = node
let anoPar = parent
if (typeof key !== 'undefined') {
anoPar = parent[key] = {}
}

for (let i in data) {
if (typeof data[i] === 'object') {
loopList.push({
parent: anoPar,
key: i,
data: data[i]
})
} else {
anoPar[i] = data[i]
}
}
}
return result
}

let cloneA1 = deepClone5(a1)
cloneA1.c.c2.c22 = 5555555
console.log(a1);
console.log(cloneA1);

// ------------------------------------------JSON.stringify()实现深拷贝

function cloneJson(o) {
return JSON.parse(JSON.stringify(o))
}

// let obj = { a: { c: 1 }, b: {} };
// obj.b = obj;
// console.log(JSON.parse(JSON.stringify(obj))) // 报错 // Converting circular structure to JSON


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

**答：**因为JS里面有可视的Dom，如果是多线程的话，这个线程正在删除DOM节点，另一个线程正在编辑Dom节点，导致浏览器不知道该听谁的

**答：**回调函数

done为true后继续调用迭代器的next方法，返回值的value为undefined

class MyPromise2 {
constructor(executor) {
// 规定状态
this.state = “pending”
// 保存 resolve(res) 的res值
this.value = undefined
// 保存 reject(err) 的err值
this.reason = undefined
// 成功存放的数组
this.successCB = []
// 失败存放的数组
this.failCB = []

    let resolve = (value) => {
if (this.state === "pending") {
this.state = "fulfilled"
this.value = value
this.successCB.forEach(f => f())
}
}
let reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected"
this.value = value
this.failCB.forEach(f => f())
}
}

try {
// 执行
executor(resolve, reject)
} catch (error) {
// 若出错，直接调用reject
reject(error)
}
}
then(onFulfilled, onRejected) {
if (this.state === "fulfilled") {
onFulfilled(this.value)
}
if (this.state === "rejected") {
onRejected(this.value)
}
if (this.state === "pending") {
this.successCB.push(() => { onFulfilled(this.value) })
this.failCB.push(() => { onRejected(this.reason) })
}
}
}

Promise.all = function (promises) {
let list = []
let count = 0
function handle(i, data) {
list[i] = data
count++
if (count == promises.length) {
resolve(list)
}
}
return Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
handle(i, res)
}, err => reject(err))
}
})
}


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

async function async1() {
console.log(‘async1 start’)
await async2()
console.log(‘async1 end’)
}
async function async2() {
console.log(‘async2’)
}
async1()
console.log(‘script start’)

//执行到await时，如果返回的不是一个promise对象，await会阻塞下面代码(当前async代码块的代码)，会先执行async外的同步代码(在这之前先看看await中函数的同步代码，先把同步代码执行完)，等待同步代码执行完之后，再回到async内部继续执行
//执行到await时，如果返回的是一个promise对象，await会阻塞下面代码(当前async代码块的代码)，会先执行async外的同步代码(在这之前先看看await中函数的同步代码，先把同步代码执行完)，等待同步代码执行完之后，再回到async内部等promise状态达到fulfill的时候再继续执行下面的代码
//所以结果为
//async1 start
//async2
//script start
//async1 end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

setTimeout(function(){
console.log(‘1’)
});
new Promise(function(resolve){
console.log(‘2’);
resolve();
}).then(function(){
console.log(‘3’)
});
console.log(‘4’);
new Promise(function(resolve){
console.log(‘5’);
resolve();
}).then(function(){
console.log(‘6’)
});
setTimeout(function(){
console.log(‘7’)
});
function bar(){
console.log(‘8’)
foo()
}
function foo(){
console.log(‘9’)
}
console.log(‘10’)
bar()
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

new Promise属于主线程任务直接执行打印2
Promis下的then方法属于微任务，把then分到微任务 Event Queue中
console.log(‘4’)属于主线程任务，直接执行打印4

console.log(‘10’)属于主线程任务直接执行

setTimeout(() => {
console.log('1');
new Promise(function (resolve, reject) {
console.log('2');
setTimeout(() => {
console.log('3');
}, 0);
resolve();
}).then(function () {
console.log('4')
})
}, 0);
console.log('5'); //5 7 10 8 1 2 4 6 3
setTimeout(() => {
console.log('6');
}, 0);
new Promise(function (resolve, reject) {
console.log('7');
// reject();
resolve();
}).then(function () {
console.log('8')
}).catch(function () {
console.log('9')
})
console.log('10');


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

var
var声明的变量可进行变量提升，let和const不会
var可以重复声明
var在非函数作用域中定义是挂在到window上的
let
let声明的变量只在局部起作用
let防止变量污染

const

Proxy对象，里面传两个对象，第一个对象是目标对象target，第二个对象是专门放get和set的handler对象。Proxy和上面两个的区别在于Proxy专门对对象的属性进行get和set

Vue的双向绑定 vue2用的是Object.defineProperty，vue3用的是proxy

exports.xxx=‘xxx’
module.export = {}
exports是module.exports的引用，两个指向的是用一个地址，而require能看到的只有module.exports

commonjs

AMD

CMD

seajs 规范

commonjs模块输出的是值的拷贝，而ES6输出的值是值的引用
commonjs是在运行时加载，是一个对象，ES6是在编译时加载，是一个代码块
commonjs的this指向当前模块，ES6的this指向undefined

JSONP⭐⭐⭐⭐⭐

JSONP只能get请求

function addScriptTag(src) {
var script = document.createElement("script")
script.setAttribute('type','text/javascript')
script.src = src
document.appendChild(script)
}

// 回调函数
function endFn(res) {
console.log(res.message);
}

// 前后端商量好，后端如果传数据的话，返回endFn({message:'hello'})


1
2
3
4
5
6
7
8
9
10
11
12
13
14
document.domain⭐

var w = window.open(“https://www.qq.com”)
< undefined
w.document
✖ VM3061:1 Uncaught DOMException: Blocked a frame with origin “https://id.qq.com” from accessing a cross-origin frame.
at :1:3
document.domain
< “id.qq.com”
document.domain = ‘qq.com’
< “qq.com”
w.document
< #document
1
2
3
4
5
6
7
8
9
10
11
location.hash+iframe⭐⭐

1 2 3 4 5 6 7 8 9 10 11 12 13 14 在b中监听哈希值改变，一旦改变，把a要接收的值传给c 1 2 3 4 5 6 7 8 9 在c中监听哈希值改变，一旦改变，调用a中的回调函数

1
2
3
4
5
6
7
window.name+iframe⭐⭐

a要获取b的数据，b中把数据转为json格式放到window.name中
postMessage⭐

a窗口向b窗口发送数据，先把data转为json格式，在发送。提前设置好messge监听
b窗口进行message监听，监听到了以同样的方式返回数据，
a窗口监听到message，在进行一系列操作
CORS⭐⭐⭐⭐⭐

Access-Control-Allow-Origin --必须
XMLHttpRequest只能拿到六个字段，要想拿到其他的需要在这里指定

Origin
Access-Control-Request-Method

nginx代理跨域⭐⭐⭐⭐

nginx模拟一个虚拟服务器，因为服务器与服务器之间是不存在跨域的，

HTTP头都有哪些字段⭐⭐⭐⭐

cache-control 是否使用缓存
Connection：keep-alive 与服务器的连接状态
Host 主机域

cache-control
etag 唯一标识，缓存用的
last-modified最后修改时间

2开头的表示成功

3开头的表示重定向
301永久重定向
302临时重定向
304表示可以在缓存中取数据（协商缓存）
4开头表示客户端错误
403跨域
404请求资源不存在
5开头表示服务端错误
500

TCP属于传输层

http0.9只能进行get请求
http1.1增加了长连接keep-alive，增加了host域，而且节约带宽
http2 多路复用，头部压缩，服务器推送

http无状态无连接，而且是明文传输，不安全
https传输内容加密，身份验证，保证数据完整性
https实现原理⭐⭐⭐⭐⭐

localStorage

sessionStorage

Secure：只允许在https下传输
session
session是保存在服务端的
session一般用来跟踪用户的状态
localstorage存满了怎么办？⭐⭐⭐

https://www.zhihu.com/question/28586791

get请求是冪等的，所以get请求的数据是可以缓存的

get传参，参数是在url中的

post传参，参数是在请求体中

get较不安全
post较为安全

get参数长度有限，是较小的

post传参长度不受限制

post传参发送两个请求包，一个是请求头，一个是请求体，请求头发送后服务器进行验证，要是验证通过的话就会给客户端发送一个100-continue的状态码，然后就会发送请求体

get在url上传输的时候只允许ASCII编码

https://www.jianshu.com/p/9c95db596df5

public

private

no-storage

no-cache

etag的作用

tcp面向连接，udp不需要连接
tcp需要三次握手四次挥手请求连接

tcp是可靠传输；一旦传输过程中丢包的话会进行重传
udp是不可靠传输，但会最大努力交付

UDP实时性高，比TCP工作效率高

TCP是点对点的
UDP支持一对一，一对多，多对多

tcp首部占20字节
udp首部占8字节

CDN的DNS服务器会返回给浏览器一个全局负载均衡IP

defer：不会阻塞DOM解析，等DOM解析完之后在运行，在DOMContentloaed之前
async: 不会阻塞DOM解析，等该资源下载完成之后立刻运行

1已发送，接收到ACK的
2已发送，未接收到ACK的
3未发送，但允许发送的
4未发送，但不允许发送的
2和3表示发送窗口

1.已接收
2.未接受但准备接受
3.未接受不准备接受

1.首先访问本地的 DNS ，如果没有命中，继续递归或者迭代查找，直到命中拿到对应的 IP 地址。

2.拿到对应的 IP 地址之后服务器端发送请求到目的地址。注意这里返回的不直接是 cdn 服务器的 IP 地址，而是全局负载均衡系统的 IP 地址

4.全局负载均衡系统会根据客户端的 IP地址和请求的 url 和相应的区域负载均衡系统通信

5.区域负载均衡系统拿着这两个东西获取距离客户端最近且有相应资源的cdn 缓存服务器的地址，返回给全局负载均衡系统

6.全局负载均衡系统返回确定的 cdn 缓存服务器的地址给客户端。

7.客户端请求缓存服务器上的文件

xss脚本注入

beforeUpdate
data改变后，对应的组件重新渲染之前
updated
data改变后，对应的组件重新渲染完成
beforeDestory

destoryed

Vue中的nextTick⭐⭐⭐⭐⭐

nextTick

nextTick：在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法，获取更新后的 DOM。

computed

watch

v-if 和v-show

hash模式

history模式

mvc和mvvm的区别

MVC
Model（模型）是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View（视图）是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
Controller（控制器）是应用程序中处理用户交互的部分。

diff算法⭐⭐⭐⭐⭐

diff算法是指对新旧虚拟节点进行对比，并返回一个patch对象，用来存储两个节点不同的地方，最后利用patch记录的消息局部更新DOM

Vue的Key的作用 ⭐⭐⭐⭐

key
key主要用在虚拟Dom算法中，每个虚拟节点VNode有一个唯一标识Key，通过对比新旧节点的key来判断节点是否改变，用key就可以大大提高渲染效率，这个key类似于缓存中的etag。
Vue组件之间的通信方式⭐⭐⭐⭐⭐

Vue.prototype.Event=new Vue();

Event.$emit(事件名,数据); Event.$on(事件名,data => {});


1
2
3
4
5
Vuex

state

getters

this. s t o r e . g e t t e r s . x x x 也 可 使 用 m a p G e t t e r s 先 引 用 ， 放 在 c o m p u t e 中 ， . . . m a p G e t t e r s ( [ ′ 方 法 名 ′ , ′ 方 法 名 ′ ] ) m u t a t i o n s 同 步 操 作 数 据 的 t h i s . store.getters.xxx 也可使用mapGetters 先引用，放在compute中，...mapGetters(['方法名','方法名']) mutations 同步操作数据的 this. store.commit(“方法名”,数据)

actions

this. s t o r e . d i s p a t c h ( “ 方 法 名 ” , 数 据 ) 也 可 使 用 m a p A c t i o n s ， 使 用 方 法 和 以 上 一 样 m o d u l e s 板 块 ， 里 面 可 以 放 多 个 v u e x 父 组 件 通 过 v − b i n d : / : 传 值 ， 子 组 件 通 过 t h i s . store.dispatch(“方法名”,数据) 也可使用mapActions ，使用方法和以上一样 modules 板块，里面可以放多个vuex 父组件通过v-bind:/:传值，子组件通过this. attrs获取

this.$attrs获取到的是一个对象（所有父组件传过来的集合） 祖先组件使用provide提供数据，子孙组件通过inject注入数据 p a r e n t / parent/parent/children refs—$ref

Vue-router有哪几种钩子函数⭐⭐⭐⭐⭐

beforeEach

to(Route路由对象)
from(Route路由对象)
next(function函数) 一定要调用才能进行下一步
afterEach
beforeRouterLeave
Webpack
webpack常用的几个对象及解释⭐⭐⭐⭐

entry 入口文件

output 输出文件

// 入口文件
entry:"./src/index.js",
output:{
// 输出文件名称
filename:"bundle.js",
// 输出的路径（绝对路径）
path:path.resolve(__dirname,"dist") //利用node模块的path 绝对路径
},
// 设置模式
mode:"development"


1
2
3
4
5
6
7
8
9
10
mode 设计模式

use数组解析顺序是从下到上逆序执行的

module:{
// 对某种格式的文件进行转换处理（转换规则）
rules:[
{
// 用到正则表达式
test:/.css$/, //后缀名为css格式的文件 use:[ // use数组解析顺序是从下到上逆序执行的 // 先用css-loader 再用style-loader // 将js的样式内容插入到style标签里 “style-loader”, // 将css文件转换为js “css-loader” ] } ] } // -----------------------------------------------------vue的 module.exports={ module:{ rules:[ { test: /.vue$/,
}
]
}
}
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
plugin

const uglifyJsPlugin = reqiure(‘uglifyjs-webpack-plugin’)

module.exports={
plugin:[
new uglifyJsPlugin() //丑化
]
}
1
2
3
4
5
6
7
devServer

devServer:{
// 项目构建路径
contentBase:path.resolve(__dirname,"dist"),
// 启动gzip亚索
compress:true,
// 设置端口号
port:2020,
// 自动打开浏览器:否
open:false,
//页面实时刷新(实时监听)
inline:true
}


1
2
3
4
5
6
7
8
9
10
11
12
resolve

alias 别名

module.exports= {
resolve:{
//如果导入的时候不想写后缀名可以在resolve中定义extensions
extensions:[’.js’,’.css’,’.vue’]
//alias:别名
alias:{
//导入以vue结尾的文件时，会去寻找vue.esm.js文件
‘vue$’:“vue/dist/vue.esm.js” } } } 1 2 3 4 5 6 7 8 9 10 11 babel（ES6转ES5） 下载插件babel-loader,在module（loader）中配置 loader和plugin的区别是什么？⭐⭐⭐ loader loader是用来解析非js文件的，因为Webpack原生只能解析js文件，如果想把那些文件一并打包的话，就需要用到loader，loader使webpack具有了解析非js文件的能力 plugin 用来给webpack扩展功能的，可以加载许多插件 CSS/HTML flex布局⭐⭐⭐⭐⭐ 这个我就不例举了，看看阮一峰老师的文章叭！Flex 布局教程 grid布局⭐⭐⭐⭐ 同样是阮一峰老师的，CSS Grid 网格布局教程 常见的行内元素和块级元素都有哪些？⭐⭐⭐⭐⭐ 行内元素 inline 不能设置宽高，不能自动换行 span、input、img、textarea、label、select 块级元素block 可以设置宽高，会自动换行 p、h1/h2/h3/h4/h5、div、ul、li、table inline-block 可以设置宽高，会自动换行 请说明px,em,rem,vw,vh,rpx等单位的特性⭐⭐⭐⭐⭐ px 像素 em 当前元素的字体大小 rem 根元素字体大小 vw 100vw是总宽度 vh 100vh是总高度 rpx 750rpx是总宽度 常见的替换元素和非替换元素？⭐⭐ 替换元素 是指若标签的属性可以改变标签的显示方式就是替换元素，比如input的type属性不同会有不同的展现，img的src等 img、input、iframe 非替换元素 div、span、p first-of-type和first-child有什么区别⭐⭐⭐⭐ first-of-type 匹配的是从第一个子元素开始数，匹配到的那个的第一个元素 first-child 必须是第一个子元素 doctype标签和meta标签⭐⭐⭐⭐⭐ doctype 告诉浏览器以什么样的文档规范解析文档 标准模式和兼容模式 标准模式 ->正常，排版和js运作模式都是以最高标准运行 兼容模式->非正常 script标签中defer和async都表示了什么⭐⭐⭐⭐⭐ 众所周知script会阻塞页面的加载，如果我们要是引用外部js，假如这个外部js请求很久的话就难免出现空白页问题，好在官方为我们提供了defer和async defer 1 2 不会阻止页面解析，并行下载对应的js文件 下载完之后不会执行 等所有其他脚本加载完之后，在DOMContentLoaded事件之前执行对应d.js、e.js async 1 2 不会阻止DOM解析，并行下载对应的js文件 下载完之后立即执行 补充，DOMContentLoaded事件 是等HTML文档完全加载完和解析完之后运行的事件 在load事件之前。 不用等样式表、图像等完成加载 什么是BFC？⭐⭐⭐⭐⭐ BFC是一个独立渲染区域，它丝毫不会影响到外部元素 BFC特性 同一个BFC下margin会重叠 计算BFC高度时会算上浮动元素 BFC不会影响到外部元素 BFC内部元素是垂直排列的 BFC区域不会与float元素重叠 如何创建BFC position设为absolute或者fixed float不为none overflow设置为hidden display设置为inline-block或者inline-table或flex 如何清除浮动⭐⭐⭐⭐⭐ 额外标签clear:both Document big small 额外标签法 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 31 32 33 34 35 36 37 利用BFC overflow:hidden .fahter{ width: 400px; border: 1px solid deeppink; overflow: hidden; }  1 2 3 4 5 使用after(推荐) big small 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 什么是DOM事件流？什么是事件委托⭐⭐⭐⭐⭐ DOM事件流 分为三个阶段 捕获阶段 目标阶段 冒泡阶段 在addeventListener()的第三个参数(useCapture)设为true，就会在捕获阶段运行，默认是false冒泡 事件委托 利用冒泡原理（子向父一层层穿透），把事件绑定到父元素中，以实现事件委托 link标签和import标签的区别⭐⭐⭐⭐ link属于html，而@import属于css 页面被加载时，link会同时被加载，而@import引用的css会等到页面加载结束后加载。 link是html标签，因此没有兼容性，而@import只有IE5以上才能识别。 link方式样式的权重高于@import的。 算法 这里推荐一个排序算法的动画网站，应该是一个国外团队做的，Sorting Algorithms 冒泡算法排序⭐⭐⭐⭐⭐ // 冒泡排序 /* 1.比较相邻的两个元素，如果前一个比后一个大，则交换位置。  2.第一轮的时候最后一个元素应该是最大的一个。 3.按照步骤一的方法进行相邻两个元素的比较，这个时候由于最后一个元素已经是最大的了，所以最后一个元素不用比较。 */ function bubbleSort(arr) { for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr.length; j++) { if (arr[j] > arr[j + 1]) { var temp = arr[j] arr[j] = arr[j + 1] arr[j + 1] = temp } } } } var Arr = [3, 5, 74, 64, 64, 3, 1, 8, 3, 49, 16, 161, 9, 4] console.log(Arr, "before"); bubbleSort(Arr) console.log(Arr, "after");  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 快速排序⭐⭐⭐⭐⭐ /* 快速排序是对冒泡排序的一种改进，第一趟排序时将数据分成两部分，一部分比另一部分的所有数据都要小。 然后递归调用，在两边都实行快速排序。 */ function quickSort(arr) { if (arr.length <= 1) { return arr } var middle = Math.floor(arr.length / 2) var middleData = arr.splice(middle, 1)[0] var left = [] var right = [] for (var i = 0; i < arr.length; i++) { if (arr[i] < middleData) { left.push(arr[i]) } else { right.push(arr[i]) } } return quickSort(left).concat([middleData], quickSort(right)) } var Arr = [3, 5, 74, 64, 64, 3, 1, 8, 3, 49, 16, 161, 9, 4] console.log(Arr, "before"); var newArr = quickSort(Arr) console.log(newArr, "after");  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 插入排序⭐⭐⭐⭐ function insertSort(arr) { // 默认第一个排好序了 for (var i = 1; i < arr.length; i++) { // 如果后面的小于前面的直接把后面的插到前边正确的位置 if (arr[i] < arr[i - 1]) { var el = arr[i] arr[i] = arr[i - 1] var j = i - 1 while (j >= 0 && arr[j] > el) { arr[j+1] = arr[j] j-- } arr[j+1] = el } } } var Arr = [3, 5, 74, 64, 64, 3, 1, 8, 3, 49, 16, 161, 9, 4] console.log(Arr, "before"); insertSort(Arr) console.log(Arr, "after");  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 是否回文⭐⭐⭐⭐⭐ function isHuiWen(str) { return str == str.split("").reverse().join("") } console.log(isHuiWen("mnm"));  1 2 3 4 5 正则表达式，千分位分隔符⭐⭐⭐⭐ function thousand(num) { return (num+"").replace(/\d(?=(\d{3})+$)/g, "\$&,")
}
console.log(thousand(123456789));


1
2
3
4
5

var arr = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]

// 最low1
let newArr2 = []
for (let i = 0; i < arr.length; i++) {
if (!newArr2.includes(arr[i])) {
newArr2.push(arr[i])
}
}
console.log(newArr2);
// 最low2
let arr2 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
for (let i = 0; i < arr2.length; i++) {
var item = arr2[i]
for (let j = i + 1; j < arr2.length; j++) {
var compare = arr2[j];
if (compare === item) {
arr2.splice(j, 1)
j--
}
}
}
console.log(arr2);

// 基于对象去重
let arr3 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
let obj = {}
for (let i = 0; i < arr3.length; i++) {

let item = arr3[i]
if (obj[item]) {
arr3[i] = arr3[arr3.length - 1]
arr3.length--
i--
continue;
}
obj[item] = item

}
console.log(arr3);
console.log(obj);

// 利用Set
let newArr1 = new Set(arr)
console.log([...newArr1]);

let arr4 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]

newArr4 = arr4.reduce((prev, curr) => prev.includes(curr)? prev : [...prev,curr],[])
console.log(newArr4);
console.log(document);


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

// num1前一项
// num2当前项
function fb(n, num1 = 1, num2 = 1) {
if(n == 0) return 0
if (n <= 2) {
return num2
} else {
return fb(n - 1, num2, num1 + num2)
}
}


1
2
3
4
5
6
7
8
9
10

var arr = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]

// 最low1
let newArr2 = []
for (let i = 0; i < arr.length; i++) {
if (!newArr2.includes(arr[i])) {
newArr2.push(arr[i])
}
}
console.log(newArr2);
// 最low2
let arr2 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
for (let i = 0; i < arr2.length; i++) {
var item = arr2[i]
for (let j = i + 1; j < arr2.length; j++) {
var compare = arr2[j];
if (compare === item) {
arr2.splice(j, 1)
j--
}
}
}
console.log(arr2);

// 基于对象去重
let arr3 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
let obj = {}
for (let i = 0; i < arr3.length; i++) {

let item = arr3[i]
if (obj[item]) {
arr3[i] = arr3[arr3.length - 1]
arr3.length--
i--
continue;
}
obj[item] = item

}
console.log(arr3);
console.log(obj);

// 利用Set
let newArr1 = new Set(arr)
console.log([...newArr1]);

let arr4 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]

//利用reduce
newArr4 = arr4.reduce((prev, curr) => prev.includes(curr)? prev : [...prev,curr],[])
console.log(newArr4);
console.log(document);


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
git
git的常用命令⭐⭐⭐⭐⭐

commit之后撤回

git branch xx 创建分支
git checkout xx切换分支

git push
git commit -m

git常用命令与常见面试题总结

ok，今天的文章就到这里了。

10-23

02-08 16万+
05-18 2787
03-14 25万+
10-26 3069
07-19 5万+
03-04 29万+
10-26 923
02-13 6万+
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie