Skip to content

Commit 841cd40

Browse files
committed
add js原生系统知识
1 parent dbbaeef commit 841cd40

File tree

10 files changed

+291
-22
lines changed

10 files changed

+291
-22
lines changed

interview/javascript原生知识/1.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ console.log(myInstanceof(myDate, String))
8888

8989
/**
9090
* 9: Object.is和===的区别?
91-
* Object.is对+0,-0及NaN对处理,
92-
* 一般在需要考虑元编程方案对时候用,
91+
* Object.is对+0,-0及NaN的处理,
92+
* 一般在需要考虑元编程方案的时候用,
9393
*/
9494
console.log((+0) === (-0)) // true
9595
console.log(NaN === NaN) // false
@@ -129,7 +129,7 @@ const obj = {
129129
return '6'
130130
}
131131
}
132-
console.log('number+:', obj+1, 'String+:', obj+'6');
132+
console.log('number+:', obj+1, 'String+:', obj+'6'); // 5 46
133133

134134
/**
135135
* 14: 如何让if(a == 1 && a == 2)条件成立?
@@ -150,9 +150,9 @@ console.log(a == 1 && a == 2)
150150
* 红宝书对闭包的定义:有权访问另外一个函数作用域中的变量的函数
151151
* MDN对闭包的定义: 能访问自由变量的函数(自由变量: 指在函数中使用的,既不是arguments也不是函数局部变量的变量,* 也就是另外一个函数作用域中的变量)
152152
* 2: 闭包产生的原因:
153-
* 作用域链,ES5中存在两种作用域:全局作用域和函数作用域,当访问一个变量的时候,会从底层开始,直到找到全局作用域或window未知,如果没找到就抛出异常
153+
* 作用域链,ES5中存在两种作用域:全局作用域和函数作用域,当访问一个变量的时候,会从底层开始,直到找到全局作用域或window为止,如果没找到就抛出异常
154154
* 3: 闭包产生的本质:
155-
* 当前环境中存在指向父级作用域的应用
155+
* 当前环境中存在指向父级作用域的引用
156156
* 4: 表现形式:
157157
* 1): 返回一个函数
158158
* 2): 函数作为参数传递: 定时器,事件监听等
@@ -167,8 +167,8 @@ for(var i = 1; i <= 5; i ++){
167167
/**
168168
* 16: 谈谈你对原型链的理解?
169169
* 一:原型对象和构造函数的关系
170-
* js中,每当定义一个函数数据类型(普通函数,类)等时候,都会自带一个prototype属性,这个属性指向函数都原型对象
171-
* 当函数通过new调用时,这个函数就成了构造函数,返回一个全新当实例对象,这个实例对象有一个proto属性,指向构造函数当原型对象
170+
* js中,每当定义一个函数数据类型(普通函数,类)等时候,都会自带一个prototype属性,这个属性指向函数的原型对象
171+
* 当函数通过new调用时,这个函数就成了构造函数,返回一个全新的实例对象,这个实例对象有一个proto属性,指向构造函数的原型对象
172172
* 二:原型链
173173
* js对象通过prototype指向父类对象,直到指向Object为止,这样就形成了一个原型指向的链条,就叫原型链
174174
* 1):对象通过hasOwnProperty()来检查对象自身是否含有该属性

interview/javascript原生知识/2.js

+147-9
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
* @Author: Tiny
33
* @Date: 2020-01-03 17:10:03
44
* @Last Modified by: [email protected]
5-
* @Last Modified time: 2020-01-07 23:30:48
5+
* @Last Modified time: 2020-01-17 17:36:10
66
*/
77

88
/**
99
* 原生js你知道多少?
1010
* 1: 函数的arguments为什么不是数组?如何转化成数组?
1111
* 2: forEach中return有效果吗?如何中断forEach循环?
12-
* 3: JS判断数组中是否包含某个值?
13-
* 4: JS中flat---数组扁平化?
12+
* 3: JS判断数组中是否包含某个值,有几种方法?
13+
* 4: JS中flat---数组扁平化,有多少种方法?
1414
* 5: JS数组的高阶函数: map/reduce/filter/sort/some/every/find(能不能分别实现他们?)
1515
* 6: 能不能模拟实现new的功能
1616
* 7: 能不能模拟实现bind功能
@@ -54,19 +54,25 @@
5454
* 4: JS中flat---数组扁平化?
5555
*/
5656
// 一: es6的flat方法
57-
array = arrray.flat(Infinity);
57+
let arrray = [1, [2, 3, [4,5 ]], 6]
58+
let array1 = arrray.flat(Infinity);
59+
console.log(array1) // [ 1, 2, 3, 4, 5, 6 ]
5860

5961
// 二: replace + split
60-
array = str.replace(/(\[|\])/g, '').split(',');
62+
let str2 = String([1, [2, 3, [4,5 ]], 6])
63+
let array2 = str2.replace(/(\[|\])/g, '').split(',');
64+
console.log(array2) // [ '1', '2', '3', '4', '5', '6' ]
6165

6266
// 三: replace + JSON.parse
63-
str = str.replace(/(\[|\])/g, '');
64-
str = '[' + str + ']';
65-
array = JSON.parse(str);
67+
let str3 = [1, [2, 3, [4,5 ]], 6].toString()
68+
str3 = str3.replace(/(\[|\])/g, '');
69+
str3 = '[' + str3 + ']';
70+
let array3 = JSON.parse(str3);
71+
console.log(array3) // [ 1, 2, 3, 4, 5, 6 ]
6672

6773
// 四: 普通递归
6874
let result = [];
69-
let fn = ary => {
75+
const fn = ary => {
7076
for (let i = 0; i < ary.length; i++) {
7177
const item = ary[i];
7278
if (Array.isArray(item)) {
@@ -76,7 +82,139 @@ let fn = ary => {
7682
}
7783
}
7884
}
85+
fn([1, [2, 3, [4,5 ]], 6])
86+
console.log(result)
87+
88+
/**
89+
* 6: 能不能模拟实现new的功能
90+
* 分析: new的实例对象能访问原型的属性,也能访问构造函数的属性
91+
*/
92+
93+
//new的模拟实现
94+
function Person(name, age) {
95+
this.name = name;
96+
this.age = age;
97+
98+
// this.hibit = 'Games';
99+
return null
100+
}
101+
Person.prototype.strenth = 60;
102+
Person.prototype.sayYouName = function() {
103+
console.log('I am ' + this.name);
104+
};
105+
106+
// const people = new Person('Jack', 20);
107+
const people = ObjFactory(Person, 'Jack', 20);
108+
console.log(people.name)
109+
console.log(people.age)
110+
console.log(people.strenth)
111+
people.sayYouName()
112+
113+
114+
function ObjFactory() {
115+
// 从Object.prototype上克隆一个对象
116+
const obj = new Object();
117+
118+
// 取得外部传入的构造器
119+
const Constructor = [].shift.call(arguments);
120+
121+
// 指向正确的原型,将对象的原型指向构造函数的原型
122+
obj.__proto__ = Constructor.prototype;
123+
124+
// 借用外部传入的构造器给obj设置属性
125+
const ret = Constructor.apply(obj, arguments);
126+
127+
// 确保构造器总是返回一个对象
128+
return typeof ret === 'object' ? ret || obj: obj;
129+
}
79130

131+
/**
132+
* 7: 能不能模拟实现bind功能
133+
*/
134+
var value = 2;
135+
136+
var foo = {
137+
value: 1
138+
};
139+
140+
function bar(name, age) {
141+
this.habit = 'shopping';
142+
console.log(this.value);
143+
console.log(name);
144+
console.log(age);
145+
}
146+
147+
bar.prototype.friend = 'kevin';
148+
149+
var bindFoo = bar.bind(foo, 'daisy');
150+
151+
var obj = new bindFoo('18');
152+
console.log(obj.__proto__, bindFoo.__proto__, bar.prototype)
153+
// undefined
154+
// daisy
155+
// 18
156+
console.log(obj.habit);
157+
console.log(obj.friend);
158+
// shopping
159+
// kevin
160+
161+
162+
/**
163+
* 8: 能不能实现call/apply函数
164+
*/
165+
/**
166+
* 注意两点:
167+
* a: call改变this指向,指到两foo
168+
* b: bar函数执行了
169+
*/
170+
const foo = {
171+
value: 1
172+
};
173+
function bar(name, age) {
174+
console.log(this.value, name, age);
175+
return {
176+
name,
177+
age,
178+
value: this.value
179+
};
180+
}
181+
bar.call(foo, 'jrg', '18');
182+
183+
Function.prototype.newCall = function(context) {
184+
// 首先要获取调用call的函数,用this可以获取
185+
context = context || window
186+
context.fn = this;
187+
let args = [];
188+
for (let i = 1; i < arguments.length; i++) {
189+
args.push(`arguments[${i}]`)
190+
}
191+
const result = eval(`context.fn(${args})`)
192+
// eval(`context.fn(${args})`)
193+
// context.fn()
194+
console.log(result)
195+
delete context.fn;
196+
197+
return result;
198+
}
199+
bar.newCall(foo, 'Jeck', 20);
200+
201+
Function.prototype.newApply = function(context, arr) {
202+
context = Object(context) || window;
203+
context.fn = this;
204+
205+
let result;
206+
if (!arr) {
207+
result = context.fn();
208+
} else {
209+
let args = [];
210+
for (let i = 1; i < arr.length; i++) {
211+
args.push(`arr[${i}]`)
212+
}
213+
result = eval(`context.fn(${arts})`)
214+
}
215+
delete context.fn;
216+
return result;
217+
}
80218
/**
81219
* 9: 谈谈你对js中this对理解
82220
* 一: 定义:当前执行代码的环境对象

interview/questions/questions.js

+36-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: [email protected]
33
* @Date: 2019-04-01 22:22:06
44
* @Last Modified by: [email protected]
5-
* @Last Modified time: 2020-01-12 23:27:54
5+
* @Last Modified time: 2020-01-14 21:00:59
66
*/
77

88
/**
@@ -37,6 +37,7 @@
3737
* 18: watch和computed有什么区别及应用场景
3838
* 19: 怎么实现Vue自己写的组件的按需加载
3939
* 20: vue源码和element-ui的源码,了解多少?
40+
* 21: vue自定义指令
4041
*/
4142

4243
/**
@@ -125,4 +126,37 @@ const ImportDemo3 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../co
125126
* watch和computed有什么区别及应用场景
126127
* watch应用场景:数据变化时需要做一些异步操作的时候,可以设置中间状态
127128
* computed应用场景:复杂的逻辑计算的时候(是基于它们的响应式依赖进行缓存的,只有响应式依赖发生改变时才会重新求值)
128-
*/
129+
*/
130+
131+
/**
132+
* 8: Vue导航守卫
133+
* 1): 全局: beforeEach()/beforeResolve():全局解析守卫/afterEach():全局后置钩子
134+
* 2): 路由独享: beforeEnter()
135+
* 3): 组件内守卫: beforeRouteEnter() / beforeRouteUpdate() / beforeRouteLeave()
136+
* 完整的流程:
137+
* 1导航被触发 -> 2失活组件 beforeRouteLeave() -> 3全局 beforeEach() -> 4 重用组件调用 beforeRouteUpdate() -> 5 在路由配置里调用 beforeEnter() -> 6 被激活的组件 beforeRouteEnter() -> 7 全局的解析守卫 beforeResolve() -> 8 导航被确认 -> 9 全局 afterEach() -> 10 触发dom更新
138+
*/
139+
140+
/**
141+
* vue自定义指令
142+
* 1: 全局,
143+
* 2: 局部
144+
*/
145+
// 全局自定义指令
146+
Vue.directive('focus', {
147+
bind: el => {
148+
el.focus()
149+
},
150+
inserted: el => {
151+
el.focus()
152+
},
153+
update:() => {
154+
155+
},
156+
componentUpdated: () => {
157+
158+
},
159+
unbind: () => {
160+
161+
}
162+
})

interview/questions/v-module.html

Whitespace-only changes.

interview/vue/diff.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
// diff 函数,对比两棵树
3+
function diff(oldTree, newTree) {
4+
const index = 0 // 当前节点的标志
5+
const pathes = {} // 用来记录每个节点差异的对象
6+
dfsWalk(oldTree, newTree, index, pathes)
7+
}
8+
9+
// 对两棵树进行深度优先遍历
10+
function dfsWalk(oldNode, newNode, index, pathes) {
11+
pathes[index] = [...]; // 对比oldNode和newNode的不同,记录下来
12+
diffChildren(oldNode.children, newNode.children, index, pathes)
13+
}
14+
15+
// 遍历子节点
16+
function diffChildren(oldChildren, newChildren, index, pathes) {
17+
let leftNode = null
18+
let currentNodeIndex = index;
19+
oldChildren.forEach((child, i) => {
20+
const newChild = newChildren[i]
21+
currentNodeIndex = (leftNode && leftNode.count)
22+
? currentNodeIndex + leftNode.count + 1
23+
: currentNodeIndex + 1
24+
dfsWalk(child, newChild, currentNodeIndex, pathes)
25+
leftNode = child;
26+
});
27+
}

interview/vue/element.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
// 用js对象模拟dom树,记录节点类型,属性,字节点
3+
function Element (tagName, props, children) {
4+
this.tagName = tagName;
5+
this.props = props;
6+
this.children = children;
7+
}
8+
9+
Element.prototype.render = function () {
10+
const el = document.createElement(this.tagName);
11+
const props = this.props;
12+
13+
for (const propName in props) {
14+
if (props.hasOwnProperty(propName)) {
15+
const propValue = props[propName];
16+
el.setAttribute(propName, propValue)
17+
}
18+
}
19+
20+
const children = this.children || [];
21+
22+
children.forEach(child => {
23+
const childEl = (child instanceof Element)
24+
? child.render()
25+
: document.createTextNode(child)
26+
el.appendChild(childEl)
27+
})
28+
29+
return el;
30+
}
31+
32+
module.exports = (tagName, props, children) => {
33+
return new Element(tagName, props, children);
34+
}

interview/vue/render.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const el = require('./element');
2+
3+
const ul = el('ul', { id: 'list' }, [
4+
el('li', { class: 'item' }, ['Item1']),
5+
el('li', { class: 'item' }, ['Item2']),
6+
el('li', { class: 'item' }, ['3']),
7+
])
8+
9+
const ulRoot = ul.reader()
10+
document.body.appendChild(ulRoot)

interview/vue/virtual-dom.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* virtual-dom 思想:
3+
* 一: 步骤
4+
* 1: 用js对象结构表示dom树的结构,然后用这个树构建一个真正的dom树,插到文档中
5+
* 2: 状态变更的时候,重新构建一颗新的对象树,然后用新的对象树和旧的比较,记录两个对象树的差异
6+
* 3: 把步骤2记录的差异应用到步骤1构建的真正dom树上,view更新
7+
*
8+
* 二: 本质
9+
* 本质就是在js和DOM之间做了一个缓存
10+
*/

utils/array.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: [email protected]
33
* @Date: 2019-04-03 23:02:55
44
* @Last Modified by: [email protected]
5-
* @Last Modified time: 2019-04-03 23:07:22
5+
* @Last Modified time: 2020-03-05 22:32:09
66
*/
77

88
/**

0 commit comments

Comments
 (0)