受控组件与非受控组件
受控组件,顾名思义就是受我们(setState)控制的组件,就是组件的状态全程响应外部数据;
<input type="text" name="username" value={this.state.value} />
//value值是react一个状态,可以通过setState改变
非受控组件,字面意思就是不受我们控制的组件,一般只是在初始的时候接收一个外部的值,储存在内部初始化组件;当用户输入新内容后,组件自身会处理更新,如果需要获取这个值,可以使用ref;
<input type="text" name="username" defaultValue="请输入内容" ref={this.inputRef} />
//我们无法控制value,只能通过ref获取
props和state的区别
- props是只读的,state是多变的、可写的;
- props是外部输入的数据,react是自上而下通过props传输数据的单向数据流;而state是组件内部数据,被组件自己管理,一般在constructor中初始化;
props和state的相同点
- 都是Javascript对象;
- 都用于保存信息;
- 都能触发渲染更新;
0.1+0.2等于0.3?怎么相等?
不相等,因为浮点数的加法运算会失去精度,实际上小数点后面有17位,0.1+0.2=0.30000000000000004;原因:计算机内部计算之前会转换成二进制,JavaScript中整数和小数都是Number类型来保存,遵循IEEE 754标准,使用64位固定长度来保存(双精度浮点数)。
方法一:使用 toFixed 保留至指定位数的小数,再比较;
(0.1+0.2).toFixed(2) == 0.3 //true
方法二:Number.EPSILON 代表JavaScript能够表示的最小精度,如果差值小于这个值就说明等式成立;
Number.EPSILON > Math.abs(0.1+0.2-0.3) //true
编程题
题目(20分钟):使用 JavaScript 实现以下转换对象转换功能,将一个层叠的对象展平:
{ a: 1, b: { c: 2, d: { e: 3, f: 4 }}, g: [5, 6, { h: 7 }] }
转换为
{
“a”: 1, “b.c”: 2,
“b.d.e”: 3, “b.d.f”: 4,
“g.0”: 5, “g.1”: 6, “g.2.h”: 7
}
function flat(obj) {
let newObj = {}
function format(o, pre) {
for (let [key,value] of Object.entries(o)) {
if (typeof value === 'object') {
if (!pre) {
format(value, key);
} else {
format(value, pre + '.' + key);
}
} else {
if (!pre) {
newObj[key] = value;
} else {
newObj[pre + '.' + key] = value; //.拼接生成新的属性名
}
}
}
}
format(obj, null)
return newObj
}
git常用命令
- 克隆仓库 git clone +ssh url
- 创建并切换到该分支 git checkout -b + 分支名
- 创建分支 git branch + 分支名
- 切换到分支 git checkout + 分支名
- 查看所有分支 git branch -a
- 暂存 git stash
- 弹出最后一次缓存 git stash pop
- 提交该分支下所有修改 git add .
- 提交并备注 git commit -m “备注”
- 合并某分支到当前分支 git merge + 分支名
- 从远程仓库拉代码 git pull origin 远程分支名
- 推送代码到远程仓库 git push origin 远程分支名
- 修改旧的分支名 git branch -m 旧名 新名
- 提交本地分支到远程 git push --set-upstream origin 分支名
数组常用方法
- 遍历 find/map/for/some/every/filter
- 判断 isArray/includes
- 平铺 flat/flatMap
- 索引indIndex/indexOf
- 增删改 concat/slice/splice/push/pop/shift/unshift/delete
- 排序 sort/reverse
- 转换 toString
- 最值 Math.min([…arr])/Math.max([…arr])
手写深拷贝
const handleClone = (obj) => {
let newObj = null;
if (typeof (value) != 'object') return obj;
newObj = Array.isArray(obj) ? [] : {};
for (let [key, value] of Object.entries(obj)) {
if (typeof (value) != 'object') {
newObj[key] = value;
} else {
newObj[key] = handleClone(value)
}
}
return newObj
}
手写promise/promise.all
promise解决了多个异步请求嵌套地狱;(改用promise的链式调用)
参考手写Promise
//手写promise.all 接收一个数组
Promise.all = (values)=>{
if (!Array.isArray(values)) {
const type = typeof values;
return new TypeError(`TypeError:${type} ${values} is not iterable`);
}
return new Promise((resolve, reject) => {
let resulAll = [];
let orderIndex = 0;
const handleResult = (value, index) => {
resulAll[index] = value;
if (++orderIndex === values.length) {
resolve(resulAll);
}
};
for (let i = 0; i < values.length; i++) {
if (values[i] && typeof values[i].then === "function") {
//如果是promise
values[i].then((res) => {
handleResult(res, i);
}, reject); //任何一个promise失败就直接失败了
} else {
handleResult(values[i], i);
}
}
});
};
useEffect(() => {
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("1");
}, 1000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("4");
}, 2000);
});
Promise.all([p1, p2, 444]).then((res) => console.log('resolve',res),e=>console.log(e));
}, []);
如何中断promise调用链 / 如何中断promise
- 中断调用链,使用promise.finally();
- 中断promise,在promise里面调用reject(‘中断’);