每日一题 点滴进步~
2022.1.21
1.箭头函数与普通函数的区别
-
箭头函数相比于普通函数更加简洁
-
箭头函数不会改变this的指向
- call() apply()bind() 都不会改变箭头函数this的指向
-
箭头函数没有prototype 、 agruements
-
箭头函数没有原型故不能作为构造函数
-
箭头函数不能作Generator函数,不能使用yeild关键字
2.this指向哪⾥?
- 对于箭头函数来说 , this的指向取决于箭头函数外部的执行上下文
- 对于普通函数来说 ,this的指向取决于该函数运行时的执行上下文环境
- 对于有bind()、apply()、call() 的函数this的指向取决于方法指定的this
- 对于构造函数来说,this指向为新对象
3.扩展运算符的作用及使用场景
-
对象扩展运算符 用来取出参数对象中所有的可遍历属性, 拷贝到当前对象中
-
let obj = {a: 1 , b: 2}; let obj1 = {...obj} // {a: 1 , b: 2}
-
-
数组扩展运算符
-
任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组
- 字符串转化为数组
- 集合转化为数组
-
合并数组
-
2022.1.22
1. JavaScript中对象继承的方式有哪些?
-
原型式继承
-
// 原型式继承 // Object()可以理解为对传入的对象进行一个浅复制 let person = { name: 'szj', friends: ['zy', 'wjr', 'ghk'] } let me = Object(person); me.friends.push('ssss') console.log(me); console.log(person) //{ name: 'szj', friends: [ 'zy', 'wjr', 'ghk', 'ssss' ] } //{ name: 'szj', friends: [ 'zy', 'wjr', 'ghk', 'ssss' ] }
-
-
寄生式继承
-
// 寄生继承 // 像是对原型继承的另一种升级 , 采用了工厂模式的方法 增加了对象的方法 let jisheng = { name : 'sss', friends: ['ss' , 'www'] } const js = (obj) =>{ const clone = Object(obj); clone.sayHi = function (){ console.log(clone.name); } return clone } const m = js(jisheng); m.sayHi(); // sss
-
-
组合继承
-
// 组合继承 // 原型链 + 盗用构造函数 function Super(name){ this.name = name; this.friends = ['szj' , 'zy']; } Super.prototype.sayName = function (){ console.log(this.name); } function Sub(name){ // 盗用构造函数 Super.call(this , name); } // 原型链继承 Sub.prototype = new Super; const bob = new Sub('szj'); bob.sayName() console.log(bob.friends); // szj // [ 'szj', 'zy' ]
-
-
寄生式组合继承
-
// 寄生式组合继承 // 最佳实践!! 相比于组合继承 减少了构造函数调用的次数 function Superr (name){ this.name = name; this.friends = ['ss' , 'www' , 'ppp']; } Superr.prototype.say = function (){ console.log(this.name); } function Subb(name){ Superr.call(this , name) } function inheritPrototype (sub , superr) { const prototype = Object(superr.prototype); // 别忘了原型对象的指向 prototype.constructor = sub; sub.prototype = prototype; } inheritPrototype(Subb , Superr); const zy = new Subb('zy'); zy.say() console.log(zy.friends); // zy // [ 'szj', 'zy' ]
2. 实现异步加载方法的关键字有哪些?
-
defer
-
async
-
总结:
- 两者都是用来异步加载外部脚本的关键字
- defer 加载完成后 页面渲染后执行
- async 加载完成后 立即执行
- 多个 defer 按顺序依次执行 , 多个async执行顺序不定
3. 什么是JS的事件循环 , 事件循环机制是什么?
-
如图: JS是单线程的 , 在代码执行时,会将代码压入执行栈中保证函数的有序执行 , 遇到异步任务会将 任务抛给webapi进行处理 , 处理之后将回调函数推到任务队列(宏任务队列 , 微任务队列) , 当执行栈为空时 , 先执行微任务队列中的函数 , 如果需要渲染页面 , 则会渲染页面 , 最后执行宏任务队列中的函数。
Event Loop 执行顺序如下所示:
- 首先执行同步代码,这属于宏任务
- 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
- 执行所有微任务
- 当执行完所有微任务后,如有必要会渲染页面
- 然后开始下一轮 Event Loop,执行宏任务中的异步代码
宏任务 微任务
- 微任务包括: promise 的回调、node 中的 process.nextTick 、对 Dom 变化监听的 MutationObserver。
- 宏任务包括: script 脚本的执行、setTimeout ,setInterval ,setImmediate 一类的定时事件,还有如 I/O 操作、UI 渲染等。
2022.1.23
1. let、const、var区别
-
作用域
- let 、 const 为块级作用域
- var为函数作用域
-
是否可以重复声明
- let var 可以重复声明
- const 不可以重复声明
-
变量提升
- var 具有变量提升
-
暂时性死区
- let 、const 具有暂时性死区 , 未声明之后不能使用
-
给全局添加属性
- var 可以给全局添加属性 let const 不会
-
初始值设置
- var let 声明时可以不设置初始值
- const 必须设置初始值
-
指针的指向
- let 可以修改指针的指向(重新赋值) , const 不能够修改指针的指向不可以重新赋值,但是引用数据类型的属性可以改变
| 区别 | var | let | const |
|---|---|---|---|
| 是否有块级作用域 | × | ✔️ | ✔️ |
| 是否存在变量提升 | ✔️ | × | × |
| 是否添加全局属性 | ✔️ | × | × |
| 能否重复声明变量 | ✔️ | × | × |
| 是否存在暂时性死区 | × | ✔️ | ✔️ |
| 是否必须设置初始值 | × | × | ✔️ |
| 能否改变指针指向 | ✔️ | ✔️ | × |
2. 数组去重的方法有哪些?
1. 数组元素比较型
-
双层
for循环-
// 双层for循环 // 前一个跟之后所有进行比较 , 重复了删除掉 function uniq(arr){ for(let i = 0 ; i < arr.length - 1 ; i++){ for(let j = i + 1 ; j < arr.length; j++){ if(arr[i] === arr[j]){ arr.splice(i , 1); // 删除后下表移动到原位置 j--; } } } return arr; }
-
-
排序后 相邻位置进行比较
-
// 排序进行后进行相邻比较 function sortQ(arr){ // 排序后 // 没参数 如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。 arr.sort(); for(let i = 0 ; i < arr.length - 1 ; i++){ if(arr[i] === arr[i + 1]){ arr.splice(i , 1); i--; } } }
-
2.查找元素位置型
-
indexOf查找元素并返回其第一个索引值-
function uniq(arr){ const res = []; for(let i = 0 ; i < arr.length ; i++){ if(arr.indexOf(arr[i]) === i){ res.push(arr[i]) } } return res; }
-
-
findIndex返回数组中第一个满足测试函数的元素的索引-
function uniq(arr){ const res = []; for(let i = 0 ; i < arr.length ; i++){ if(arr.findIndex(item => item === arr[i]) === i ){ res.push(arr[i]); } } return res; }
-
3. 查找元素存在型
-
includes-
// 查找元素存在型 function uniq(arr){ const res = []; for(let i = 0 ; i < arr.length ; i++){ if(!res.includes(arr[i])){ res.push(arr[i]) } } return res; }
-
4. 利用数据结构类型
-
set
-
// set function uniq(arr){ return [...new Set(arr)] }
-
-
map
-
function uniq(arr){ const map = new Map(); arr.forEach(item =>{ map.set(item , true) }) // 返回键值 Object.keys(key) return[...map.keys()] }
-
5. 总结
在简单的测试用例大概 2000 万条数据下,indexOf 的方案速度相对最快
3. vue双向绑定的原理
- Mvc 模式 到 mvvm模式 的转变
- Mvc 模式 controler 层要大量的控制dom
- Mvvm 模式 是真正做到了数据与视图的分离, view 和 model 改变时 , vm层自动进行数据和视图的同步
-
vue.js 采用数据劫持结合发布者-订阅者模式的方式 , 通过Object.defineProperty()来劫持各个属性的setter、getter,在数据监听时发布消息给订阅者 , 触发响应的监听回调
-
发布 订阅者模式让双向绑定更有效率(一对多)
-
实现一个数据监听器 Observer
- 核心是 Object.defineProperty() , 将Observe的数据对象进行递归遍历 , 包括子属性的对象加上setter getter方法 , 赋值时就会调用setter方法,就监听到了数据变化
- 通知订阅者
-
实现Compile
- 解析模板的指令 , 将模板中的变量替换成数据 ,
- 初始化页面渲染 ,
- 并绑定更新函数 , 添加监听数据的订阅者 , 一但数据有变化 , 更新视图 --绑定更新函数
-
实现watcher (解析 compile 和 observe 的桥梁)
- 实例化在订阅者添加自己
- 自己有一个update()方法 --添加订阅者
- 待属性变动 , 接受通知,调用自身的update() , 并触发compile中的回调 --》更新视图
-
整合形成一个mvvm
4.70. 爬楼梯 - 力扣(LeetCode) (leetcode-cn.com)
- 经典dp
var climbStairs = function(n) {
const dp = [];
dp[0] = 1;
dp[1] = 1
for(let i = 2 ; i <= n ; i++){
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n]
};
2022.1.24
1.字面量创建对象和 new 创建对象有什么区别,new 内部都实现了什么, 手写一个 new
-
字面量创建对象 简洁 比较易读 不需要作用域解析 , 速度更快
-
new的过程
- 开辟一个新内存
- 将新对象的[[prototype]]指针指向构造函数的变量对象
- this指向新对象
- 执行构造函数内部的代码
- 如果构造函数返回一个对象返回该对象 , 否则返回建立的对象
-
手写一个new
-
function reNew (obj , ...rest){ // 原型 const newObj = Object.create(obj.prototype); // 属性 + 原型 const result = obj.call(newObj , rest); // 如果结果为一个对象 返回 不是的话返回继承原型之后的 return typeof result=== 'object'? result : newObj; }
-
2.== 和 === 的区别
- 本质区别是 比较的时候是否会进行数据类型的转换转换 。
- === 严格意义上的相等 不会进行数据类型的转换 直接比较值
- == 通常会转化为相同数据类型进行值得比较
3. 在 JS中为什么 0.2 + 0.1 > 0.3
- JS中只有一种数字类型 Number , 遵循IEEE规则 ,双精度浮点数 64位 1位符号位 11位指数位 52位尾数
- 计算机是通过二进制的方式进行存储数据 , 由于尾数有限 只能记录52位 因此加上之后转化为十进制 为0.300000004
4. 那为什么 0.2 + 0.3 == 0.5 呢
- 还是因为52位尾数 二进制加完之后 53位有数字 但是只要52 位 且没有进位
2022.1.25
1.三拦布局,有多少种?思路和代码
-
flex布局 父级元素弹性布局 左右盒子固定宽度 中间flex:1
-
.container{ display: flex; } .left{ width: 100px; background-color: antiquewhite; } .right{ width: 100px; background-color: aqua; } .center{ flex: 1; background-color: aquamarine; }
-
-
浮动
- 父级盒子BFC 清除浮动
- 将盒子的位置重新放置 左右中
- 左右分别 左右浮动 中间 margin进行
-
.container{ overflow: hidden; } .left{ float: left; height: 500px; width: 100px; background-color: antiquewhite; } .right{ float: right; height: 500px; width: 100px; background-color: aquamarine; } .center{ margin-left: 100px; margin-right: 100px; background-color: blue; height: 500px; } <body> <div class="container"> <div class="left"></div> <div class="right"></div> <div class="center"></div> </div> </body>
-
绝对定位
- 左右绝对定位
- 中间 margin
-
.container{ position: relative; } .left{ position: absolute; left: 0; width: 100px; height: 500px; background-color: aquamarine; } .right{ position: absolute; right: 0; width: 100px; height: 500px; background-color: blueviolet; } .center{ margin-right: 100px; height: 500px; margin-left: 100px; background-color: aqua; }
-
总结:
- 最优解 flex 但是兼容性不能兼容ie8以下
- 浮动和绝对定位都会导致 盒子脱离文档流 因此 最好将浮动或绝对定位的盒子 放到中间盒子的前面
2. css中定位有多少个值,每个值有什么特点
| 属性值 | 概述 |
|---|---|
| absolute | 绝对定位 , 元素会被移除文档流 , 寻找最近的非static的父元素进行偏移 |
| relative | 相对定位 , 相对于本身自己的位置移动 。 可以配合absolute进行 相对于指定元素的定位 |
| fixed | 绝对定位 , 相对于屏幕视口进行定位 |
| static | 默认值 没有定位 元素会存在于文档流中 , 会忽略 top, bottom, left, right 或者 z-index 声明 |
| inherit | 继承父元素的position |
3.对BFC的理解,如何创建BFC
-
BFC也叫块级格式化上下文 , 其本质上是指 盒子内部的元素不会影响外部元素的一个布局
-
如何创建
- float 不为none
- overflow 不为 visiblie
- position absolution
- display flex
-
作用
- 解决margin重叠的问题
- 解决 浮动元素 高度塌陷的问题
4. 算法:剑指 Offer 30. 包含min函数的栈 - 力扣(LeetCode) (leetcode-cn.com)
- 最小栈 利用两个栈
/**
* initialize your data structure here.
*/
var MinStack = function() {
this.stack = [];
this.minS = [];
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
this.stack.push(x);
if(this.minS.length){
if(this.minS[this.minS.length - 1] > x){
this.minS.push(x)
}else{
this.minS.push(this.minS[this.minS.length - 1])
}
}else{
this.minS.push(x)
}
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
this.stack.pop();
this.minS.pop();
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
const c = this.stack.pop();
this.stack.push(c);
return c
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
return this.minS[this.minS.length - 1]
};
/**
* Your MinStack object will be instantiated and called as such:
* var obj = new MinStack()
* obj.push(x)
* obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.min()
*/
2022.1.26
1. 你了解CDN吗?
-
CDN也叫内容分发网络技术 , 目的是为了提高传输内容的传输速度和稳定性,避开网络上的拥塞和不稳定的节点 , 寻找最近的网络节点获取资源
-
cdn上的内容分为静态和动态内容
- 静态:提前备份到cdn服务器
- 动态:可能会在cdn服务器实现一些接口
-
如何转发:任播 -- 服务器对外拥有一个相同的ip地址 , 请求会被距离最近的cdn服务器接受
2. Https 加密算法
https 分为三种加密加密算法
- 摘要算法 : 输入一系列子串 输入长度一定 , 常见的MD5
- 非对称加密:公钥加密 私钥解密 (公钥会传输 私钥不会传输)
- 对称加密:用同一个密钥加密 并且解密 异或的思想
拓展:
https的传输过程(4次握手)
- 客 : 发送协议的版本 可以支持的加密算法 以及一个随机数
- 服 : 确定加密算法 , 发送公钥 , 发送数字证书 以及一个随机数
- 客 : 将公钥加密后的随机数发送
- 服 : 将随机数用私钥解密
- 至此 , 将 第一随机数 第二随机数 加公钥加密后的随机数 生成 会话密钥 (对称加密)
3. JS如何进行垃圾回收的?如果回收出现循环引用会导致什么?
垃圾回收的策略
-
标记清理
- 将内存中的所有变量或者函数都进行标记 , 调用后去除标记 , 一段时间后 , 剩下还有标记的变量就会被回收
-
引用计数
- 跟踪每一个值被引用的次数 , 赋值加一 被覆盖减一 当为零的时候可以清理
-
循环引用
-
当出现两个值相互引用的现象 , 利用引用计数进行垃圾回收 , 会导致循环引用 , 永远不会释放 , 因此得手动解除引用
- 例如
-
obj1.a = obj2 obj2.a = obj1 //引用次数都为2 // 手动解除引用 obj1.a = null obj2.a = null
-
4. Vue中组件传值得方法有哪些?
-
父子组件
-
父组件传子组件
- props
-
子组件向父组件传值
- $emit()
- 子组件中定义一个方法 this.$eimt('父组件中的函数名' , 传的值的名字)
- 父组件中接受 @子组件中定义的名字 = ‘’函数名称‘ 直接以参数的形式接受
-
-
eventsBus事件总线
-
创建eventsBus.js
-
发送数据
- EventBus.$emit('addition' , { num : this.num++})
-
接受数据
- EventBus.$on('addition' , pramas =>{ console.log(paramas.num)})
-
-
ref/$refs
- ref属性在子组件上 ,他的引用就指向子组件的实例 , 便可以访问子组件内部的方法
-
依赖注入(project / inject)
-
这种方式就是Vue中的依赖注入,该方法用于父子组件之间的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方法来进行传值。就不用一层一层的传递了。
project / inject是Vue提供的两个钩子,和data、methods是同级的。并且project的书写形式和data一样。project钩子用来发送数据或方法inject钩子用来接收数据或方法
在父组件中:
provide() { return { num: this.num }; }在子组件中:
inject: ['num']还可以这样写,这样写就可以访问父组件中的所有属性:
provide() { return { app: this }; } data() { return { num: 1 }; } inject: ['app'] console.log(this.app.num)注意: 依赖注入所提供的属性是非响应式的。
-
5.算法 5. 最长回文子串 - 力扣(LeetCode) (leetcode-cn.com)
- 动态规划
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function longestPalindrome(s){
let n = s.length;
let res = '';
let dp = Array.from(new Array(n),() => new Array(n).fill(false));//初始化二维数组dp[n][n]
for(let i = n-1; i >= 0; i--){//循环字符串
for(let j = i; j < n; j++){
//dp[i][j]表示子串i~j是否是回文子串
//回文子串必须满足s[i],s[j]相等。并且向外扩展一个字符也相等,即dp[i+1][j-1]也是回文子串
//j - i < 3表示子串之间剩余的也必然是回文串(ij的差值为0表示ij指向同个下标,
//1表示ij为相邻下标,2表示ij为相隔一个的下标)
dp[i][j] = s[i] == s[j] && (j - i < 3 || dp[i+1][j-1]);
if(dp[i][j] && j - i + 1 > res.length){//当前回文子串比之前的大,更新最大长度
res = s.substring(i,j+1);
}
}
}
return res;
};
2022.1.27
- 如何判断两个链表是否相交?
- 对vue的响应式原理有了解么,可以简单的说一下么?
- cookie是为了解决什么问题,session, localStorage, sessionStorage,这三者的区别是啥呢?
- 给你一棵树,树上的每条边权值都是1,求树上两个节点的距离,使得路径最大
1. 如何判断两个链表是否相交?
-
思路:
- 先计算长度 并进行对齐
- 遍历寻找节点并返回
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
// 创建一个计算长度的函数
const countLen = (head) =>{
let count = 0;
while(head){
head = head.next;
count++;
}
return count;
}
var getIntersectionNode = function(headA, headB) {
let lenA = countLen(headA);
let lenB = countLen(headB);
let p1 = headA;
let p2 = headB;
if(lenA > lenB){
[lenA , lenB] = [lenB , lenA];
[p1 , p2] = [p2 , p1];
}
let i = lenB - lenA;
while(i--){
p2 = p2.next;
}
while(p1 && p2){
if(p1 === p2){
return p1
}
p1 = p1.next;
p2 = p2.next;
}
return null
};
2.对vue的响应式原理有了解么,可以简单的说一下么?
整体思路是数据劫持+观察者模式
对象内部通过 defineReactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存放他所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新(派发更新)。
相关代码如下
class Observer {
// 观测值
constructor(value) {
this.walk(value);
}
walk(data) {
// 对象上的所有属性依次进行观测
let keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let value = data[key];
defineReactive(data, key, value);
}
}
}
// Object.defineProperty数据劫持核心 兼容性在ie9以及以上
function defineReactive(data, key, value) {
observe(value); // 递归关键
// --如果value还是一个对象会继续走一遍odefineReactive 层层遍历一直到value不是对象才停止
// 思考?如果Vue数据嵌套层级过深 >>性能会受影响
Object.defineProperty(data, key, {
get() {
console.log("获取值");
//需要做依赖收集过程 这里代码没写出来
return value;
},
set(newValue) {
if (newValue === value) return;
console.log("设置值");
//需要做派发更新过程 这里代码没写出来
value = newValue;
},
});
}
export function observe(value) {
// 如果传过来的是对象或者数组 进行属性劫持
if (
Object.prototype.toString.call(value) === "[object Object]" ||
Array.isArray(value)
) {
return new Observer(value);
}
}
复制代码
响应式数据原理详解 传送门
3.cookie是为了解决什么问题,session, localStorage, sessionStorage,这三者的区别是啥呢?
- cookie (服务器设置 , 客户端储存 , 同源请求携带) 常用来识别用户 , 与session一起跟踪用户的状态。 最多储存4k
- session 保存在服务端 , 用来跟踪用户的状态 , 与cookie一起使用
- sessionStorage : HTML5 提供的一种浏览器本地存储的方法 , 类似于session , 代表了一次会话所保存的数据 , 页面关闭后失效
- loaclStorage:HTML5 提供的一种浏览器本地存储的方法 , 保存在本地 , 不删除就会永久的储存。
4.给你一棵树,树上的每条边权值都是1,求树上两个节点的距离,使得路径最大
543. 二叉树的直径 - 力扣(LeetCode) (leetcode-cn.com)
- 思路 : 递归 (深度遍历)
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
// 深度优先遍历
var diameterOfBinaryTree = function(root) {
let res = 1;
const deep = (n) =>{
if(!n) return 0;
let l = deep(n.left);
let r = deep(n.right);
// 最大访问节点数
res = Math.max(res , l + r +1)
// 返回每一次的最长节点树
return Math.max(r , l) + 1;
}
deep(root);
return res - 1;
};
2022.1.18
1.力扣3 无重复字符的最长子串 2.css优先级是怎么计算的 3.typeof和instanceof的区别 4.v-if和v-show区别
1. css优先级如何计算
- css优先级是通过权重计算得到的
-
选择器 权重 内联样式 1000 id选择器 100 类选择器、属性选择器、伪类选择器 10 标签选择器、伪元素选择器 1 - 另外 !inportant 优先级最高!!
2. typeof和instanceof的区别
-
相同点:两者都是操作符 用来判断类型
-
不同点
- typeof: string number symbol bigInt boolean function object , 可以判断七种类型 只能判断对象 , 无法判读哪种对象
- instanceof : 可以判断 是哪种object 但是不能判断 原始数据类型
3. v-if和v-show区别
- 原理:v-if 是利用动态的向DOM树内添加或者删除DOM , v-show 是通过设置DOM元素的display属性控制显隐
- 编译过程:v-if 切换有一个局部编译/卸载的过程 , 切换过程中合适的销毁和重建内部的事件监听和子组件 , v-show只是进行一个css样式的切换
- 编译条件:v-if 是惰性的 , 当初是条件为假 , 不会进行一个编译 , 只有到条件为真的时候才开始真正的编译 , v-show 无论条件是否为真都会进行一个编译
- 性能消耗:v-if 涉及到编译卸载的过程 比较高的切换消耗, v-show 有比较高的初始渲染消耗
- 使用场景:频繁切换用v-show ,条件不大可能改变用v-if
4.3. 无重复字符的最长子串 - 力扣(LeetCode) (leetcode-cn.com)
-
思路:
- map + 快慢指针
- 慢指针 每次遇到重复的元素 就向重复元素之后移动
-
var lengthOfLongestSubstring = function(s) { // 思路:快慢指针 if(!s) return 0; const arr = [...s]; const map = new Map(); let l = 0; let res = 0; for(let r = 0 ; r < arr.length ; r++){ const c = arr[r]; if(map.has(c) && l <= map.get(c) ){ l = map.get(c) + 1; } res = Math.max(res , r -l + 1 ); map.set(c , r); } return res };
2022.1.29
- null和undefined的区别
- 判断this指向的几种方法
- vue中key的作用,为什么不建议用index作为key
- promise.all实现
1. null 和 undefined的区别
- undefined 意为未定义 , 常常是变量声明并没有赋值
- null 空对象 , 常用来赋值给一个可能返回对象的变量
2. 判断this指向的几种方法?
-
箭头函数类别
-
this指向为箭头函数外部的执行上下文
-
非箭头函数
- this指向该函数运行时的函数的执行上下文
-
构造函数
- this指向新对象
-
call、apply、bind this指向指定this
-
3. vue中key 的作用,为什么不建议用index作为key
-
作用
-
标识一个独立的元素
- 在 v-if中 , 由于vue会尽可能高效的渲染元素 , 会优先复用相同类型的元素而不是重头渲染 , 因此为了防止复用相同的元素(input用户输入不会被清除掉),使用key的元素就不会复用
-
更高效的更新DOM
- v-for中利用key来跟踪元素 , 如果发生了元素的顺序改变 , 没有必要移动dom 来匹配顺序 ,而是利用key值直接复用此处的元素。
-
总结: 更准确 , 更快速
-
-
为什么不建议?
- index 仅仅是标记了数组的一个索引值 , 当数组中的元素顺序发生改变后 , 索引值并不发生改变 , 并不能提供便捷。
4. promise.all
const promiseAll = (_promises) =>{
return new Promise ((resolve , rejected) =>{
const promises = [..._promises];
const agr = agruements;
const result = [];
for(let i = 0 ; i < promises.length ; i++){
Promise.resolve(promises[i]).then((res) =>{
result.push(res)
if (i === promises.length - 1){
resolve(result)
}
} , (err) =>{
rejected(err)
})
}
})
}
2022.1.30
1.水平垂直居中的方法 2.ES6有哪些新特性? 3.宏任务和微任务都有哪些?有什么区别? 4.力扣:1.两数之和
1.水平垂直居中的方法
水平居中
-
flex 布局
-
display:flex ;justify-content : center
-
-
块级元素
- 设置宽度
margin : 0 auto
- 设置宽度
-
行内元素
text-align : center
-
绝对定位
-
position:absolute; left: 50%; transform : translateX(-50%) // 或者 margin-left : - width/2 ;
-
垂直居中
-
flex布局
-
display:flex; justify-content : center; alsign-item : center
-
-
绝对定位
-
position:absolute; left: 50%; right: 50% transform : translate(-50% , -50%) -
position: absolute; left: 50%; top: 50%; margin-left :- width/2; margin-bottom: -top/2; -
position:absolute; left:0; right:0; top:0; bottom:0; margin : auto;
-
-
行内元素
-
line-height:height; text-align:center;
-
2.ES6有哪些新特性?
-
解决原有语法上的不足
letconst块级作用域
-
对原有语法进行增强
-
解构
- 数组解构
- 对象解构
-
参数
- 默认参数
- 剩余参数
-
模板字面量
-
-
全新的数据结构和数据类型
- symbol
- bigInt
- map
- set
-
全新的方法、函数、对象
- promise对象
- proxy 代理对象
Object.assign()Object.is()- 箭头函数
3.宏任务和微任务都有哪些?有什么区别?
1. 宏任务
- I/O
- setTimeout
- setInterval
- setImmediate
2. 微任务
- Promise
3. 区别
-
执行顺序
- 当执行栈为空时 , 先执行微任务 , 后执行宏任务
-
进程的切换为宏任务 , 线程的切换为微任务。
4.两数之和
var twoSum = function(nums, target) {
const map = new Map();
const res = [];
nums.forEach((item , index) =>{
if(map.has(target - item)){
res.push(index , map.get(target - item))
}
map.set(item , index)
} )
return res
};