fix: 修改文章
This commit is contained in:
parent
d7bfb9d8d4
commit
b29ab2dce1
@ -9,49 +9,40 @@ group:
|
||||
|
||||
# 计算机原理
|
||||
|
||||
|
||||
## 描述一下cookies,sessionStorage 和localStorage的区别?
|
||||
|
||||
|
||||
- cookie 在浏览器和服务器之间来回传递,SS和LS不会
|
||||
- SS和LS 的储存空间更大
|
||||
- SS和LS 有更多丰富易用的接口
|
||||
- SS和LS 是有各自的储存空间
|
||||
- LS 储存是永久性的,SS 关闭浏览器就没了
|
||||
|
||||
|
||||
|
||||
## 如何实现浏览器内多个标签之间的通信
|
||||
|
||||
|
||||
- 调用LS Cookies 等本地储存方式
|
||||
|
||||
- 调用LS Cookies 等本地储存方
|
||||
|
||||
|
||||
## IE6 BUG 的解决办法
|
||||
|
||||
|
||||
- 双边距,float引起,使用display
|
||||
- 3像素问题,float引起, 使用display:inline-3px
|
||||
- 超链接 hover 点击失效, 注意顺序
|
||||
- 无法定义1px左右的宽度容器(使用overflow:hidden;zoom:0.08;line-height:1px)
|
||||
|
||||
|
||||
|
||||
## 你有哪些性能优化的方法
|
||||
|
||||
|
||||
- 减少http请求次数,css,js,html压缩,图片大小控制和压缩,网页cdn托管,data缓存,图片服务器
|
||||
- 前端模板 js + 数据,减少由于html导致的带宽浪费,减少请求次数,
|
||||
- 图片预加载,将样式表放在头部,脚本放在底部,加上时间戳
|
||||
- 用innerHTML代替dom操作,减少dom操作次数,优化js性能
|
||||
- 当需要设置的样式很多时,设置className而不是直接操作dom
|
||||
- 按需加载三方库、如果是单页应用则按需加载路由页面
|
||||
- 开启gzip模式
|
||||
- 避免在页面的主体布局中使用table,table要在其中的内容完全下载完之后才会完全显示,显示div+css布局慢。普通网站有一个普遍的思路,就是尽量向前端化,减少数据库操作,减少磁盘IO,
|
||||
- 前端化:在不影响功能和体验的情况下,能在浏览器执行的不要在服务器执行,能在缓存服务器上直接返回的不要到应用服务器,程序能直接取到的结果不要到外部取,本机能取到的不要到远程取,内存能取到的不要到磁盘取,缓存中有的不要去数据库查询
|
||||
- 前端化:在不影响功能和体验的情况下,能在浏览器执行的不要在服务器执行,能在缓存服务器上直接返回的不要到应用服务器,程序能直接取到的结果不要到外部取,本机能取到的不要到远程取,内存能取到的不要到磁盘取,缓存中有的不要去数据库查询,多用localstorage,sessionstorage、cookie
|
||||
- 减少数据库操作指:减少更新次数,缓存结果减少查询次数,将数据库执行的操作尽可能的让你的操作完成,减少磁盘IO指尽量不适用文件系统作为缓存,减少读写文件次数等。
|
||||
- 程序优化永远要优化慢的部分
|
||||
|
||||
|
||||
- 图片加载使用懒加载、列表滚动使用虚拟滚动
|
||||
|
||||
## http 状态码有哪些?分别代表啥意思?
|
||||
|
||||
@ -61,15 +52,23 @@ group:
|
||||
- 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息
|
||||
- 400-499 用于指出客户端的错误。
|
||||
|
||||
|
||||
|
||||
> 400: 语义有误 401:当前请求需要用户验证 403: 服务器已经理解请求,但是拒绝执行他 404:页面找不到
|
||||
|
||||
|
||||
|
||||
- 500-599 用于支持服务器错误。501 服务器不可用
|
||||
|
||||
## http 缓存策略
|
||||
|
||||
分为强制缓存和协商缓存。
|
||||
|
||||
强制缓存分为三种情况:1. 没找到直接发起请求;2. 找到了但是缓存结果没有失效直接使用缓存;3. 找到了但是失效了就会去使用协商缓存
|
||||
|
||||
一般强制缓存的标识字段为 Expires(http1.0,指定过期时间) 和 Cache-control(http1.1, public/private/no-cache/no-store),后者可以搭配 max-age 控制过期时间使用
|
||||
|
||||
协商缓存是强制缓存失效了,浏览器携带标识向服务端发起请求,服务器通过缓存标识决定是否使用缓存的过程。
|
||||
|
||||
协商缓存的字段为:last-modified / if-modified-since 和 Etag / if-none-match,后者优先级更高。
|
||||
|
||||
缓存的流程是请求报文向服务器发送last-modified 或者 etag字段,如果和服务端对应的字段一致,则服务端使用缓存返回304,否则失效,重新请求200
|
||||
|
||||
## 一个页面从输入 url 到页面显示完成,中间发生了什么?
|
||||
|
||||
@ -86,6 +85,7 @@ group:
|
||||
> 解析:对加载到的资源(html,js,css)进行语法解析,建议相应的内部数据结构(比如html的dom树,js的属性表,css的样式表规则等等)
|
||||
|
||||
## 浏览器的渲染原理
|
||||
|
||||

|
||||
|
||||
1)浏览器会解析三个东西:
|
||||
@ -102,8 +102,8 @@ group:
|
||||
|
||||
3)最后通过调用操作系统Native GUI的API绘制。
|
||||
|
||||
|
||||
## 并发(concurrency)和并行(parallelism)区别
|
||||
|
||||
异步和这小节的知识点其实并不是一个概念,但是这两个名词确实是很多人都常会混淆的知识点。其实混淆的原因可能只是两个名词在中文上的相似,在英文上来说完全是不同的单词。
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@ group:
|
||||
|
||||
- flex布局
|
||||
|
||||
> 设置justify-content:center;
|
||||
> 设置justify-content:center;items-align: center;
|
||||
|
||||
### 2· 垂直居中
|
||||
|
||||
|
@ -9,6 +9,29 @@ group:
|
||||
|
||||
# 面试技巧
|
||||
|
||||
## 自我介绍技巧
|
||||
|
||||
1. 个人的基本情况介绍,简历上有的就大概跳过
|
||||
2. 个人擅长什么,技术上的和非技术上的,技术上聊专长,非技术聊个人
|
||||
3. 做过的项目,挑一些核心的说
|
||||
4. 自己的一些想法和思考,兴趣和观点,让面试官感觉你是个爱折腾的人
|
||||
|
||||
举个例子:
|
||||
|
||||
--------------------------------
|
||||
面试官好,我叫dev,18年毕业于东华理工大学软件工程,从大四开始就一直从事前端开发的工作
|
||||
|
||||
我比较擅长的是 react 全家桶,平时开发的话,打包工具的话对 webpack 比较熟悉,自己有从0-1大型项目的经验和能力,包括前端项目的自动构建脚本编写,项目服务器发布,基本的node接口服务开发。服务器Nginx 的配置,负载均衡,域名服务器的配置,和使用 pm2 的去做项目的守护进程管理全链路开发。
|
||||
|
||||
在上家公司是人工智能创意中心,视频编辑器的项目负责人,主要职责是负责从0-1视频编辑器的开发和后期维护,还有及时响应客户需求。在此期间还基于 yapi 搭建了一套接口自动化管理系统,目的是为了高效对接后端接口质量(自动化测试)和解放手动编写接口的工作(通过后端swagger文档自动生成包含ts注释的接口),其它还负责公司的UI组件库的部分开发
|
||||
|
||||
除了开发相关的工作,还有一定的作为Owner的项目管理经验:比如需求评审,UI\UX交互评审,负责小组项目排期,成员之间的协作开发,监督成员之间的codeReview,敏捷开发推动项目进度等。
|
||||
|
||||
另外我有自己的博客,主要是用来记录在工作中的一些心得,和碰到的问题和解决方案。同时去记录一些学到的新的知识,早期也发过一些文章再segmentfault和掘金上。
|
||||
在 github 上我还成立了一个自己的组织叫nicecode,主要是用来沉淀一些这些年工作中整合的一些能提升工作效率的方案,比如说:脚手架、git提交校验工具、敏感字过滤库,常见函数方法、还有开发过一款基于 vscode 的代码片段插件。前前后后写了10几个npm包了,做这件事的原因是,我感觉开源还挺有成就感也挺有趣的
|
||||
|
||||
--------------------------------
|
||||
|
||||
## 如何粗略判断公司是否靠谱
|
||||
|
||||
然后我们还得了解一家公司的情况,这里我推荐使用「天眼查」去查询一家公司的信息。在这里我们可以查询到一家公司的几个重要指标
|
||||
@ -23,6 +46,40 @@ group:
|
||||
|
||||
很推荐大家在准备面试的过程中,挖掘出自己擅长的技术内容,然后在面试的过程中,寻找机会引导面试官提问你擅长的技术点。
|
||||
|
||||
### 常见问题答复
|
||||
|
||||
1. 你什么时候入职?
|
||||
|
||||
在职的时候说:需要交接一下手续,大概1-2礼拜。
|
||||
离职的时候说:确定录用的话,大概一周左右时间可以入职。
|
||||
|
||||
2. 为啥工作换的这么频繁?
|
||||
|
||||
坦诚说,前几次的换工作让自己觉得在岗位持续发展和成长的重要性,所以现在希望找个好的平台固定下来,然后目前这个工作给我综合看来是比较合适的,所以非常希望能得到这个机会。
|
||||
|
||||
3. 为什么选择我们公司?
|
||||
|
||||
在对方讲完公司的优势之后,结合自身优点于成长诉求,表明与公司的契合度,营造平等的社交沟通
|
||||
|
||||
4. 为什么你觉得可以胜任这份工作?
|
||||
|
||||
从三个角度去展开:
|
||||
* 工作经历、项目背景与当前岗位的匹配度
|
||||
* 个人能力模型的匹配度
|
||||
* 突出过往的工作中取得的成绩,竞争力优势
|
||||
|
||||
5. 你的期望薪资是多少?
|
||||
|
||||
最近我手里也有几个机会在看,大概就是在实际薪资的价位。但是我肯定会综合考量工作的价值,不会单纯地只看薪资。或者,您先报个价可以吗?
|
||||
|
||||
6. 接受加班吗?
|
||||
|
||||
赶项目、冲进度的时候,加班肯定在所难免。对于这些必要的加班,我一定会尽力配合。但是按照以往的经验来看,我会优先选择提高工作效率,而不是拉长工作时间。这样既能保证项目进度,也能让自己维持一个比较好的精神状态,迎接后续更大的挑战。
|
||||
|
||||
7. 为啥没干多久就离职了?
|
||||
|
||||
两个方面,一个方面是和当初说好的不一样,公司目前使用vue,但是会用 react 重启新项目,我认为做一件事专精很重要。另一方面,加班比较多,项目上线冲进度加班是正常且合理的,但是经常周末需要加班,晚上10-11点走,CTO 倒排压缩开发时长不是很合理,生活和工作太不平衡,我不是很能接受
|
||||
|
||||
## 谈钱
|
||||
|
||||
具体的工资(也就是合同上签订的工资),不要杂七杂八什么绩效加起来的那种
|
||||
@ -31,3 +88,7 @@ group:
|
||||
是否是 996,我个人很不推荐 996 的公司
|
||||
加薪升职的情况
|
||||
其他各种福利,比如餐补、房补、交通补、节假日福利、另外的保险等等
|
||||
|
||||
## 话术技巧参考
|
||||
|
||||
<https://juejin.cn/post/7173316141161381924>
|
||||
|
@ -19,9 +19,17 @@ group:
|
||||
|
||||
### typeof 返回哪些数据类型
|
||||
|
||||
- obj num fun bool undefined
|
||||
- object number function boolean undefined
|
||||
|
||||
> typeof null 返回的是object,这个是个历史遗留问题
|
||||
> typeof null 返回的是 object,这个是个历史遗留问题
|
||||
|
||||
### typeof 和 instanceof 的区别?
|
||||
|
||||
1. typeof 返回的是数据类型,instanceof 返回的是布尔值
|
||||
2. instanceof 可以判断复杂引用数据类型,但是不能判断基本数据类型
|
||||
3. typeof 能判断基本数据类型,在引用类型中只能判断 function
|
||||
|
||||
> 通用检测数据类型,可以采用Object.prototype.toString.call(),调用该方法,统一返回格式“[object Xxx]” 的字符串
|
||||
|
||||
### 3种强制类型转换两种隐式类型转换
|
||||
|
||||
@ -45,6 +53,7 @@ get: 1. 参数在链接上。2、url链接长度有限制,所以大小有限
|
||||
|
||||
### call 和 apply 的区别
|
||||
|
||||
call可以允许多个参数入参,而apply只允许一个参数
|
||||
|
||||
- object.call(this, obj1,obj2,obj3)
|
||||
- object.apply(this, argument)
|
||||
@ -57,7 +66,6 @@ get: 1. 参数在链接上。2、url链接长度有限制,所以大小有限
|
||||
|
||||
### 添加 删除 替换 插入到某个节点的方法
|
||||
|
||||
|
||||
- obj.appendChild()
|
||||
- obj.innersetBefore()
|
||||
- obj.replaceChild()
|
||||
@ -73,18 +81,20 @@ get: 1. 参数在链接上。2、url链接长度有限制,所以大小有限
|
||||
|
||||
|
||||
```javascript
|
||||
function A(name) {
|
||||
this.name = name;
|
||||
this.sayHello = function(){alert(this.name+ "say hello!")}
|
||||
function A(name) {
|
||||
this.name = name;
|
||||
this.sayHello = function() {
|
||||
alert(this.name+ "say hello!")
|
||||
}
|
||||
}
|
||||
|
||||
function B(name, id) {
|
||||
this.temp = A
|
||||
this.temp(name)
|
||||
delete this.temp
|
||||
this.id = id
|
||||
this.checkId = function(ID) {alert(this.id == ID)}
|
||||
}
|
||||
function B(name, id) {
|
||||
this.temp = A
|
||||
this.temp(name)
|
||||
delete this.temp
|
||||
this.id = id
|
||||
this.checkId = function(ID) {alert(this.id == ID)}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -92,125 +102,45 @@ get: 1. 参数在链接上。2、url链接长度有限制,所以大小有限
|
||||
|
||||
|
||||
```javascript
|
||||
function stopBubble(e) {
|
||||
if (e && e.stopPropagation) {
|
||||
e.stopPropgation ()
|
||||
} else {
|
||||
window.event.cancelBubble = true
|
||||
}
|
||||
return false
|
||||
}
|
||||
function stopBubble(e) {
|
||||
if (e && e.stopPropagation) {
|
||||
e.stopPropgation ()
|
||||
} else {
|
||||
window.event.cancelBubble = true
|
||||
}
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 谈谈this对象的理解
|
||||
### 谈谈 this 对象的理解
|
||||
|
||||
- this只在调用的时候发生指向确认,它指向什么取决于在什么地方调用。this 指向的就是调用函数的那个对象。
|
||||
- this 一般情况下: 是指全局对象global, 如果作为方法调用,就指向这个对象
|
||||
- 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是 window
|
||||
- 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象
|
||||
- 对于 new 的方式来说,this 被永远绑定在了 c 上面,不会被任何方式改变 this
|
||||
- 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象(箭头函数则指向window)
|
||||
- 对于 new 的方式来说,this 被永远绑定在构造函数上面,不会被任何方式改变 this
|
||||
|
||||
```js
|
||||
console.log(this)
|
||||
class Test {
|
||||
constructor() {
|
||||
console.log(this)
|
||||
}
|
||||
}
|
||||
export default () => {
|
||||
let demo = new Test()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 简单讲下 node 的使用场景
|
||||
|
||||
|
||||
- 高并发,聊天,实时消息推送
|
||||
|
||||
|
||||
|
||||
### node 的优点和缺点提出自己的看法
|
||||
|
||||
|
||||
- 优点: node是基于时间驱动和无阻塞的,所以非常适合处理并发请求,因此构建在node上的代理服务器相比其他技术实现的服务器表现要好的多,与node代理服务器交互的客户端代码也是用js写的,用的相同的语言,这感觉前后端非常亲切和美妙
|
||||
- 缺点: node是一个相对比较新的开源项目,所以不太稳定,它总是在变,而且缺少足够多的第三方库的支持
|
||||
|
||||
|
||||
### `location.replace()`与`location.assign()`区别
|
||||
|
||||
```html
|
||||
location.replace() 的 url 不会出现在 history 中
|
||||
```
|
||||
|
||||
|
||||
### AMD CMD CommonJS
|
||||
### DOM 操作
|
||||
|
||||
|
||||
#### Common.js
|
||||
```html
|
||||
主要是服务端,前期的nodejs采用了这种规范。module.exports或exports负责对外暴漏数据,require来引入
|
||||
|
||||
<!--a.js-->
|
||||
module.exports = {
|
||||
name: '四大名将'
|
||||
}
|
||||
<!--也可以用exports导出-->
|
||||
<!--export.name = '四大名将'-->
|
||||
|
||||
<!--b.js-->
|
||||
const res = require('./a.js')
|
||||
console.log(res.name) // 四大名将
|
||||
```
|
||||
|
||||
|
||||
#### AMD: 加载完成后执行
|
||||
```html
|
||||
客户端加载时需要等待,可能存在假死情况,鉴于浏览器的特殊情况,AMD规范出来了,
|
||||
它采用异步方式加载模块定义的所有依赖,在依赖加载完成后再执行回调函数。
|
||||
|
||||
<!-- 定义模块 -->
|
||||
<!-- AMD中require的模块会先加载完成 依赖前置 提前执行 -->
|
||||
define('module', ['dep1', 'dep2'], function(dep1, dep2){
|
||||
function foo(){
|
||||
dep1.doSomething();
|
||||
dep2.doSomething();
|
||||
}
|
||||
return {
|
||||
foo : foo
|
||||
};
|
||||
})
|
||||
|
||||
<!-- 数组中声明需要加载的模块,可以是模块名、js文件路径 -->
|
||||
<!-- 两个参数:加载的模块,加载成功后的回调函数 -->
|
||||
require(['module'], function(module){
|
||||
module.foo()
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### CMD:require 到依赖才执行
|
||||
```html
|
||||
CMD规范在2011年由seaJS提出,CMD规范和AMD规范类似,主要区别是CMD规范是就近加载依赖,
|
||||
延迟执行,只有到require时依赖才执行。
|
||||
|
||||
<!-- a.js -->
|
||||
define(function(require, exports, module) {
|
||||
function foo(){
|
||||
<!-- require的模块此时才会执行 依赖就近 延迟执行 而AMD中依赖是前置的 一开始就全都执行完毕了 -->
|
||||
var dep1 = require('dep1')
|
||||
dep1.doSomething();
|
||||
}
|
||||
<!--暴漏给外部调用-->
|
||||
exports.foo = foo
|
||||
|
||||
/** return或者exports都行
|
||||
return {
|
||||
foo : foo
|
||||
};
|
||||
**/
|
||||
});
|
||||
<!-- b.js -->
|
||||
seajs.use("./a", function(a){
|
||||
a.foo()
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### DOM 操作
|
||||
```html
|
||||
// 创建节点
|
||||
createDocumentFragment()
|
||||
@ -232,8 +162,8 @@ querySelector()
|
||||
querySelectorAll()
|
||||
```
|
||||
|
||||
|
||||
### JS设置css样式的几种方式
|
||||
|
||||
```html
|
||||
/* 1.直接设置style属性 */
|
||||
element.style.height = '100px';
|
||||
@ -253,6 +183,7 @@ element.style.cssText += 'height: 100px !important';
|
||||
|
||||
|
||||
### 阻止默认行为
|
||||
|
||||
```html
|
||||
function stopDefault( e ) {
|
||||
// 阻止默认浏览器动作(W3C)
|
||||
@ -266,8 +197,8 @@ function stopDefault( e ) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 阻止冒泡
|
||||
|
||||
```html
|
||||
function stopBubble(e) {
|
||||
// 如果提供了事件对象,则这是一个非IE浏览器
|
||||
@ -281,8 +212,8 @@ function stopBubble(e) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Ajax交互过程
|
||||
|
||||
```html
|
||||
创建XMLHttpRequest对象,也就是创建一个异步调用对象.
|
||||
创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
|
||||
@ -291,8 +222,11 @@ function stopBubble(e) {
|
||||
获取异步调用返回的数据.
|
||||
使用JavaScript和DOM实现局部刷新.
|
||||
```
|
||||
|
||||
### 考察知识点最广的JS面试题
|
||||
|
||||
[https://www.cnblogs.com/xxcanghai/p/5189353.html](https://www.cnblogs.com/xxcanghai/p/5189353.html)
|
||||
|
||||
```html
|
||||
function Foo() {
|
||||
getName = function () { alert(1); }
|
||||
@ -314,9 +248,22 @@ new Foo().getName();
|
||||
new new Foo().getName();
|
||||
```
|
||||
|
||||
### splice和slice你能说说有啥用和区别吗
|
||||
|
||||
1. splice:是可以实现数组的增删改查、只对数组生效,会改变原数组
|
||||
2. slice:不光可以截取数组,也可以截取字符串,不会改变原数组
|
||||
|
||||
### 类数组和数组的区别
|
||||
|
||||
1. 类数组不具备数组的方法(slice、splice、filter)
|
||||
2. 类数组是一个普通对象,数组类型是 Array
|
||||
|
||||
|
||||
### JS数组深浅拷贝
|
||||
#### 浅拷贝
|
||||
|
||||
把一个对象的第一层拷贝到新的对象上去,只拷贝基本数据类型
|
||||
|
||||
```javascript
|
||||
// slice 实现
|
||||
var arr = ['old', 1, true, null, undefined];
|
||||
@ -339,8 +286,10 @@ console.log(arr) // ["old", 1, true, null, undefined]
|
||||
console.log(new_arr) // ["new", 1, true, null, undefined]
|
||||
```
|
||||
|
||||
|
||||
#### 深拷贝
|
||||
|
||||
拷贝所有类型的数据类型,不同的方法会有不同的克隆效果
|
||||
|
||||
```javascript
|
||||
// 简单版:不能拷贝 函数、undefined、symbol 、循环引用的对象
|
||||
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}];
|
||||
@ -458,15 +407,6 @@ function type (obj) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### typeof 和 instanceof 的区别?
|
||||
```javascript
|
||||
typeof 在原始类型中无法判断 null,在对象类型中只能判断 object 和function
|
||||
|
||||
instanceof 可以判断对象类型的
|
||||
```
|
||||
|
||||
|
||||
### 防抖
|
||||
```javascript
|
||||
/*
|
||||
@ -528,9 +468,9 @@ var debounce = function (func, wait, immediate) {
|
||||
|
||||
定义:函数 A 中有一个函数 B,函数 B 可以访问 A 的变量,那么函数 B 就是闭包。
|
||||
|
||||
- 闭包就是能够读取其他函数内部变量的函数
|
||||
- 闭包就是引用其他函数内部变量的函数
|
||||
|
||||
#### 循环中使用闭包解决 `var` 定义函数的问题
|
||||
1. 循环中使用闭包解决 `var` 定义函数的问题
|
||||
```javascript
|
||||
方法1
|
||||
for (var i = 1; i <= 5; i++) {
|
||||
@ -553,11 +493,56 @@ for (var i = 1; i <= 5; i++) {
|
||||
}
|
||||
|
||||
方法3:使用 let
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
setTimeout(
|
||||
function timer(j) {
|
||||
console.log(j)
|
||||
},
|
||||
i * 1000,
|
||||
i
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
2. react 自定义 hooks 也属于闭包
|
||||
|
||||
```js
|
||||
const useCount = () = {
|
||||
let count = 0
|
||||
|
||||
const getCount = () => {
|
||||
return count
|
||||
}
|
||||
|
||||
const setCount = (num: number) => {
|
||||
count = num
|
||||
}
|
||||
|
||||
return {
|
||||
getCount,
|
||||
setCount
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
3. 函数的柯里化
|
||||
|
||||
4. 回调函数
|
||||
|
||||
```js
|
||||
const fn = (cb: (name: string) => void) => {
|
||||
let name = 'nicecode'
|
||||
cb(name)
|
||||
}
|
||||
```
|
||||
|
||||
### 如何理解原型?如何理解原型链?
|
||||
|
||||
原型的本质就是一个对象,我们创建一个构造函数的时候,它自动会带上一个prototype属性,这个属性就指向原型对象。它的作用就是用来提供基于函数原型继承的共享属性
|
||||
|
||||
当读取实例的属性获取不到时,如果找不到,就会查找与对象关联的原型中的属性,还找不到就会去找原型的原型,一直到顶层,这样的一层层的关系嵌套称为**原型链**
|
||||
|
||||
1. 每一个对象都有**__proto__**这是浏览器早期为了让我们能访问 prototype。
|
||||
2. _ _proto__ 的 constructor(构造函数)里面有 prototype。
|
||||
3. _ _proto__ 下面有几个方法:hasOwnProperty 、toString、toLocalString、valueOf、isPrototypeOf
|
||||
@ -571,7 +556,6 @@ promise 的出现是为了解决回调地狱(callback hell),它的其他AP
|
||||
|
||||
1. all(处理所有promise事件回调的合集)
|
||||
|
||||
|
||||
```js
|
||||
let p1 = new Promise(function(resolve, reject) { resolve('ok1') })
|
||||
let p2 = new Promise(function(resolve, reject) { resolve('ok2') })
|
||||
@ -600,12 +584,13 @@ let res = Promise.race([p1,p2]).then(res => console.log(res)) // ok1
|
||||
### 手写一个 promise
|
||||
|
||||
```jsx
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
const PENDING = 'PENDING'; // 处理中
|
||||
const FULFILLED = 'FULFILLED'; // 已完成
|
||||
const REJECTED = 'REJECTED'; // 已拒绝
|
||||
|
||||
|
||||
class Prom {
|
||||
constructor(executor) {
|
||||
// 默认状态为 PENDING
|
||||
@ -613,7 +598,7 @@ class Prom {
|
||||
// 存放成功状态的值,默认为 undefined
|
||||
this.value = undefined;
|
||||
// 存放失败状态的值,默认为 undefined
|
||||
this.reason = undefined;
|
||||
this.error = undefined;
|
||||
|
||||
let resolve = (val) => {
|
||||
if (this.status === PENDING) {
|
||||
@ -625,13 +610,13 @@ class Prom {
|
||||
let reject = (err) => {
|
||||
if (this.status === PENDING) {
|
||||
this.status = REJECTED
|
||||
this.reason = err
|
||||
this.error = err
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// 立即执行,将 resolve 和 reject 函数传给使用者
|
||||
executor(resolve,reject)
|
||||
executor(resolve, reject)
|
||||
} catch (error) {
|
||||
// 发生异常时执行失败逻辑
|
||||
reject(error)
|
||||
@ -650,22 +635,25 @@ class Prom {
|
||||
}
|
||||
|
||||
export default() => {
|
||||
const [text, setText] = useState(PENDING)
|
||||
|
||||
useEffect(() => {
|
||||
const promise = new Prom((resolve, reject) => {
|
||||
resolve('成功');
|
||||
}).then(
|
||||
(data) => {
|
||||
console.log('success', data)
|
||||
setText(data)
|
||||
console.log('手写promise', data)
|
||||
},
|
||||
(err) => {
|
||||
setText(err)
|
||||
console.log('faild', err)
|
||||
}
|
||||
)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>Promise</div>
|
||||
<div>{text}</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -677,18 +665,24 @@ export default() => {
|
||||
|
||||
## 柯里化
|
||||
|
||||
```jsx
|
||||
特点:
|
||||
1. 组合函数:可以将函数的逻辑简单化,并且达到更细粒度的代码拆分和复用
|
||||
2. 延迟执行:可以延迟执行最后一个参数执行的时间,在期间做一些其他逻辑的执行,剩余的到后面再决定
|
||||
3. 简单化函数:将参数从多参数拆为单参数,让接口简洁,更容易使用
|
||||
|
||||
```js
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
function curry(val) {
|
||||
return function() {
|
||||
|
||||
function curry(a: number) {
|
||||
return function(b: number) {
|
||||
return function(offset: number) {
|
||||
return a + b + offset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
|
||||
curry(1)()
|
||||
curry(1)(2)(3)
|
||||
|
||||
return (
|
||||
<div>柯里化函数</div>
|
||||
@ -696,66 +690,72 @@ export default () => {
|
||||
}
|
||||
```
|
||||
|
||||
## 十大错误
|
||||
### 1. Uncaught TypeError: Cannot read property
|
||||
## event loop
|
||||
|
||||
js 执行的过程中,会创建对应的执行上下文放入栈中,我们称之为执行栈,其中执行栈中的任务又会分为宏任务和微任务。按照流程执行就是一次宏任务的进行结束之后,查看是否有微任务,执行微任务,微任务执行完毕,再一次执行宏任务,就是所谓的 event loop
|
||||
|
||||
宏任务大概有:setTimeout()、setInterval()、setImmediate()、I/O、用户交互操作,UI渲染
|
||||
|
||||
微任务则有:promise.then()、promise.catch()、new MutationObserver、process.nextTick()
|
||||
|
||||
## 堆、栈的区别
|
||||
|
||||
1. 基本数据类型一般内存小,放在栈中;引用数据类型一般内存大,放在堆中
|
||||
2. 栈的垃圾回收是执行环境结束立即释放,而堆需要所有引用结束才会释放
|
||||
3. 一般来说栈的效率要高于堆
|
||||
|
||||
## v8的垃圾回收机制
|
||||
|
||||
执行js的过程中,根据对象的存活时间进行不同的分代,然后根据不同的分代采用不同的回收算法
|
||||
|
||||
新生代的空间换时间 scavenge 算法是:1. 执行的过程中将空间分为 From 和 To 两块,2. 判断是否满足存活条件,存活的将变量复制到另一个空间,3. 不存活的直接清理。4. 将From 和 To 空间交换,如此循环往复
|
||||
|
||||
老生代的标记清除和整理,运行的时候将活跃的变量标记,并进行整理到内存的一端,移除那些不活跃的空间进行释放回收
|
||||
|
||||
## 十大错误
|
||||
|
||||
### 1. Uncaught TypeError: Cannot read property
|
||||
|
||||
发生这种情况的原因很多,但常见的一种是在渲染 UI 组件时对于状态的初始化操作不当。
|
||||
|
||||
|
||||
### 2. TypeError: ‘undefined’ is not an object
|
||||
|
||||
|
||||
这是在 Safari 中读取属性或调用未定义对象上的方法时发生的错误。这与 1 中提到的 Chrome 的错误基本相同,但 Safari 使用了不同的错误消息提示语。
|
||||
|
||||
|
||||
### 3. TypeError: null is not an object
|
||||
|
||||
|
||||
这是在 Safari 中读取属性或调用空对象上的方法时发生的错误。
|
||||
|
||||
|
||||
> 在 JavaScript 中,null 和 undefined 是不一样的,这就是为什么我们看到两个不同的错误信息。undefined 通常是一个尚未分配的变量,而 null 表示该值为空。 要验证它们不相等,请尝试使用严格的相等运算符 ===
|
||||
|
||||
|
||||
|
||||
### 4. (unknown): Script error
|
||||
|
||||
|
||||
当未捕获的 JavaScript 错误(通过window.onerror处理程序引发的错误,而不是捕获在try-catch中)被浏览器的跨域策略限制时,会产生这类的脚本错误。这是一种浏览器安全措施,旨在防止跨域传递数据,否则将不允许进行通信。
|
||||
|
||||
|
||||
### 5. TypeError: Object doesn’t support property
|
||||
|
||||
|
||||
这是您在调用未定义的方法时发生在 IE 中的错误。 您可以在 IE 开发者控制台中进行测试。
|
||||
|
||||
|
||||
### 6. TypeError: ‘undefined’ is not a function
|
||||
|
||||
|
||||
当您调用未定义的函数时,这是 Chrome 中产生的错误。
|
||||
|
||||
|
||||
### 7. Uncaught RangeError: Maximum call stack
|
||||
|
||||
|
||||
这是 Chrome 在一些情况下会发生的错误。 一个是当你调用一个不终止的递归函数。
|
||||
|
||||
|
||||
### 8. TypeError: Cannot read property ‘length’
|
||||
|
||||
|
||||
这是 Chrome 中发生的错误,因为读取未定义变量的长度属性。
|
||||
|
||||
|
||||
### 9. Uncaught TypeError: Cannot set property
|
||||
|
||||
|
||||
当我们尝试访问一个未定义的变量时,它总是返回 undefined,我们不能获取或设置任何未定义的属性。 在这种情况下,应用程序将抛出 “Uncaught TypeError: Cannot set property”。
|
||||
|
||||
|
||||
### 10. ReferenceError: event is not defined
|
||||
|
||||
|
||||
当您尝试访问未定义的变量或超出当前范围的变量时,会引发此错误。
|
||||
|
||||
## 参考文章
|
||||
|
||||
<https://github.com/CavsZhouyou/Front-End-Interview-Notebook>
|
||||
|
105
docs/interview/node.md
Normal file
105
docs/interview/node.md
Normal file
@ -0,0 +1,105 @@
|
||||
---
|
||||
nav:
|
||||
title: 面试
|
||||
path: /interview
|
||||
group:
|
||||
title: 💊 面试题库
|
||||
order: 8
|
||||
---
|
||||
|
||||
# Node
|
||||
|
||||
## ESM和CJS 的区别
|
||||
|
||||
### ESM
|
||||
|
||||
1. ESM 模块是引用(import),重新赋值会报错,不能改变指针指向,但是可以改变内部的值
|
||||
2. import 是只读引用
|
||||
3. ESM 引用是动态引用
|
||||
|
||||
### CJS
|
||||
|
||||
1. CJS 是属于浅拷贝,可以重新赋值,可以修改指针
|
||||
2. 对于基本数据类型属于复制
|
||||
3. 复杂数据类型属于浅拷贝,由于两个模块指向同一个内存空间,因此对一个模块的改变会影响另一个模块
|
||||
|
||||
### 简单讲下 node 的使用场景
|
||||
|
||||
- 高并发,聊天,实时消息推送
|
||||
|
||||
### node 的优点和缺点提出自己的看法
|
||||
|
||||
- 优点: node是基于时间驱动和无阻塞的,所以非常适合处理并发请求,因此构建在node上的代理服务器相比其他技术实现的服务器表现要好的多,与node代理服务器交互的客户端代码也是用js写的,用的相同的语言,这感觉前后端非常亲切和美妙
|
||||
- 缺点: node是一个相对比较新的开源项目,所以不太稳定,它总是在变,而且缺少足够多的第三方库的支持
|
||||
|
||||
### AMD CMD CommonJS
|
||||
|
||||
#### Common.js
|
||||
|
||||
```html
|
||||
主要是服务端,前期的nodejs采用了这种规范。module.exports或exports负责对外暴漏数据,require来引入
|
||||
|
||||
<!--a.js-->
|
||||
module.exports = {
|
||||
name: '四大名将'
|
||||
}
|
||||
<!--也可以用exports导出-->
|
||||
<!--export.name = '四大名将'-->
|
||||
|
||||
<!--b.js-->
|
||||
const res = require('./a.js')
|
||||
console.log(res.name) // 四大名将
|
||||
```
|
||||
|
||||
#### AMD: 加载完成后执行
|
||||
|
||||
```html
|
||||
客户端加载时需要等待,可能存在假死情况,鉴于浏览器的特殊情况,AMD规范出来了,
|
||||
它采用异步方式加载模块定义的所有依赖,在依赖加载完成后再执行回调函数。
|
||||
|
||||
<!-- 定义模块 -->
|
||||
<!-- AMD中require的模块会先加载完成 依赖前置 提前执行 -->
|
||||
define('module', ['dep1', 'dep2'], function(dep1, dep2){
|
||||
function foo(){
|
||||
dep1.doSomething();
|
||||
dep2.doSomething();
|
||||
}
|
||||
return {
|
||||
foo : foo
|
||||
};
|
||||
})
|
||||
|
||||
<!-- 数组中声明需要加载的模块,可以是模块名、js文件路径 -->
|
||||
<!-- 两个参数:加载的模块,加载成功后的回调函数 -->
|
||||
require(['module'], function(module){
|
||||
module.foo()
|
||||
});
|
||||
```
|
||||
|
||||
#### CMD:require 到依赖才执行
|
||||
|
||||
```html
|
||||
CMD规范在2011年由seaJS提出,CMD规范和AMD规范类似,主要区别是CMD规范是就近加载依赖,
|
||||
延迟执行,只有到require时依赖才执行。
|
||||
|
||||
<!-- a.js -->
|
||||
define(function(require, exports, module) {
|
||||
function foo(){
|
||||
<!-- require的模块此时才会执行 依赖就近 延迟执行 而AMD中依赖是前置的 一开始就全都执行完毕了 -->
|
||||
var dep1 = require('dep1')
|
||||
dep1.doSomething();
|
||||
}
|
||||
<!--暴漏给外部调用-->
|
||||
exports.foo = foo
|
||||
|
||||
/** return或者exports都行
|
||||
return {
|
||||
foo : foo
|
||||
};
|
||||
**/
|
||||
});
|
||||
<!-- b.js -->
|
||||
seajs.use("./a", function(a){
|
||||
a.foo()
|
||||
});
|
||||
```
|
@ -11,16 +11,12 @@ group:
|
||||
|
||||
## 1. 不要用 Eval
|
||||
|
||||
|
||||
eval 的作用是将用户输入的字符串转化为可执行的代码,类似欺骗的效果,这样的坏处是会受到 XSS 攻击。
|
||||
|
||||
|
||||
## 2. 使用 strict 模式
|
||||
|
||||
|
||||
严格模式下的变量 **重复声明** 等操作会抛出一些隐藏的错误。
|
||||
|
||||
|
||||
```javascript
|
||||
'use strict'
|
||||
var obj = {
|
||||
@ -30,42 +26,30 @@ var obj = {
|
||||
// 抛出错误 syntax error
|
||||
```
|
||||
|
||||
|
||||
## 3. 使用 Eslint 测试代码规范
|
||||
|
||||
|
||||
可以使我们早期捕获一些 bug,并及时修正。
|
||||
|
||||
|
||||
## 4. 全面测试
|
||||
|
||||
|
||||
测试很重要,不但单元要测试,还要全面测试,例如用 mocha 测试代码覆盖率。
|
||||
|
||||
测试很重要,不但单元要测试,还要全面测试,例如用 mocha 测试代码覆盖率。使用 jest 进行单元测试
|
||||
|
||||
## 5. Unix 下不要直接使用 sudo node app.js
|
||||
|
||||
|
||||
这样如果产生错误,会让整个系统宕机,可以使用 nginx 反向代理。
|
||||
|
||||
|
||||
## 6. 避免 shell command 注入
|
||||
|
||||
|
||||
```-t
|
||||
child_process.exec('ls', function (err, data) {
|
||||
console.log(data);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
上面的 child_process.exec 调用的是 /bin/sh ,也就是执行了一个解释器。
|
||||
|
||||
|
||||
> 为了避免这个问题,我们可以使用:child_process.execFile。
|
||||
|
||||
|
||||
|
||||
## 7. 临时文件
|
||||
|
||||
|
||||
@ -74,8 +58,6 @@ child_process.exec('ls', function (err, data) {
|
||||
|
||||
> 使用 Streams。
|
||||
|
||||
|
||||
|
||||
## 8. 加密 Web 应用
|
||||
|
||||
|
||||
@ -96,26 +78,35 @@ Im human <script>alert('I‘m hacker')<script>
|
||||
|
||||
> 处理方式:1. 对插入的数据进行验证,除去 HTML。
|
||||
|
||||
|
||||
|
||||
## 10. 看好你的 cookie
|
||||
|
||||
|
||||
默认情况下,cookie 可以通过 js 在同一个域中读取,这就有可能会被跨站点脚本攻击,而且可能被第三方库读取。为了处理这种情况,我们可以在 cookies 上使用 HTTPOnly,这个标签可以让 js 无法读取。
|
||||
|
||||
|
||||
## 11. 内容安全策略(CSP)
|
||||
|
||||
|
||||
附加的安全层,可以检测和缓解某类攻击,例如:XSS、数据注入。启用方法如下:
|
||||
|
||||
|
||||
```-t
|
||||
Content-Security-Policy: default-src 'self' *.mydomain.com
|
||||
```
|
||||
|
||||
|
||||
## 12. Cross-Site Request Forgery
|
||||
|
||||
|
||||
跨站请求伪造是一种迫使终端用户在他目前已验证授权的Web应用程序中执行其它的actions。node 社区已实现,可以使用同步令牌模式处理。
|
||||
|
||||
## react 性能提升的几个方式
|
||||
|
||||
1. 如果是18之前可以将版本提升,挂载改成 createRoot,优化后的算法会比之前的强。
|
||||
2. prerender 预加载首屏页面,提升网页的收录
|
||||
3. 给页面添加 loading,增加用户体验,可以通过 webpack 配置
|
||||
4. 通过请求头的时间限制来达到缓存的效果,协商缓存和强制缓存,节省浏览器的支出
|
||||
5. 动态引入polyfill:我们市面上90%以上的设备,其实都能支持最新的API,但是如果我们为了这10%的不支持用户从而去放弃90%的人的用户体验不值得,让它通过 UA 请求头来判断是否需要加载polyfill.
|
||||
6. 使用 splitChunkPlugin 分离公共方法和独立的页面代码,提升复用率和加载速度
|
||||
7. 使用 DllPlugin,抽离一些公共包提升打包时间,这个包只有在版本变化的时候才会去重新打包
|
||||
8. tree shaking,webpack4.0是默认打开的
|
||||
9. code splitting 按需加载页面的某个模块,提升页面加载速度
|
||||
10. 使用 placeholder 和 lazy-load 提升页面性能
|
||||
|
||||
## 参考文章
|
||||
|
||||
源码分析<https://react.iamkasong.com/#%E7%AB%A0%E8%8A%82%E8%AF%B4%E6%98%8E>
|
||||
|
@ -13,37 +13,37 @@ google 出品的一款前端MVC框架,将所有可视化模块组件化,提
|
||||
|
||||
## 为什么选择 react 框架,而不是原生js
|
||||
|
||||
1. 提升复用率,组件化的开发形式代码的复用率更高,交付更快,拓展性更强
|
||||
2. 生态成熟,目前基于react的生态圈比较完善,可以更快提升开发的效率
|
||||
3. 相比较早年的js + jq的开发形式,MVC结构能够更好的提升代码的易读性,让开发更加清晰
|
||||
1. 复用率高:组件化的开发形式代码的复用率更高,交付更快,拓展性更强
|
||||
2. 生态成熟:目前基于react的生态圈比较完善,可以更快提升开发的效率
|
||||
3. 可读性强:相比较早年的js + jq的开发形式,MVC结构能够更好的提升代码的易读性,让开发更加清晰
|
||||
|
||||
## 什么是 fiber 架构
|
||||
|
||||
react 需要经历两个阶段:
|
||||
|
||||
1. 将jsx转换成 AST 结构
|
||||
2. 新老ast结构进行比较,让后更新渲染到页面上
|
||||
2. 新老 AST 结构进行比较,让后更新渲染到页面上
|
||||
|
||||
16以前的版本是将更新渲染直接入栈出栈队列执行,diff算法本质上是一种递归,递归无法中断,这种形式可能会由于IO堵塞从而导致页面卡顿丢帧。
|
||||
而fiber架构有效的改良了这一点,使用的是一种循环机制,将整个任务渲染切片成无数个小任务,发放到每个细分的时间节点中执行,优先处理最紧急的任务,有效降低了卡顿的情况发生。
|
||||
|
||||
另外我们需要了解人眼的
|
||||
|
||||

|
||||
|
||||
## hooks 相比较传统 class 组件的区别
|
||||
## hooks组件 相比较传统 class组件 的区别
|
||||
|
||||
## 优点
|
||||
|
||||
1. 解决了 HOC 的嵌套问题,扁平式状态逻辑更加简洁
|
||||
2. 解决了类组件的 this指向问题
|
||||
2. 解决了类组件的 this 指向问题
|
||||
3. 分割在不同生命周期的代码使得代码难以维护
|
||||
4. 降低代码的复用成本,减少每个组件继承react.component,大大提升性能
|
||||
|
||||
## 缺点
|
||||
|
||||
1. 额外的学习成本
|
||||
2. 没有类组件的生命周期,也就没办法和ComponentUpdate一样获取组件上的新旧数据做比较
|
||||
|
||||
|
||||
2. 没有类组件的生命周期,也就没办法和 ComponentUpdate 一样获取组件上的新旧数据做比较(性能优化上就少了一环)
|
||||
|
||||
## memo 和 PureComponent
|
||||
|
||||
@ -65,10 +65,12 @@ const Component = React.memo(() => {
|
||||
})
|
||||
```
|
||||
|
||||
## useMeno
|
||||
## useMemo
|
||||
|
||||
将计算结果缓存下来,一般使用在比较复杂的计算函数中,降低大量计算的时候时间和性能上的消耗。
|
||||
|
||||
一般是如果一个引用数据,会在多个hook里被使用,或者是需要以 props 的形式传递给子组件,则需要包裹。
|
||||
|
||||
```jsx
|
||||
import React, { useMemo, useEffect, useState } from 'react'
|
||||
|
||||
@ -101,7 +103,9 @@ export default () => {
|
||||
|
||||
## useCallback
|
||||
|
||||
基本上和 useMemo 代码逻辑是一样的,只是useCallback 相比较 useMemo是将函数缓存下来,防止执行其他操作的时候多次渲染,消耗性能。需要搭配meno一起使用。
|
||||
基本上和 useMemo 代码逻辑是一样的,只是useCallback 相比较 useMemo是将函数缓存下来,防止执行其他操作的时候多次渲染,消耗性能。需要搭配memo一起使用。
|
||||
|
||||
使用原则也和 useMemo 保持一致
|
||||
|
||||
```jsx
|
||||
import React, { useEffect, useCallback, useState } from 'react'
|
||||
@ -159,7 +163,7 @@ export default () => {
|
||||
```js
|
||||
import React, { lazy, Suspense } from 'react'
|
||||
|
||||
const Comp = React.lazy(() => {
|
||||
const Comp = lazy(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve(import(/*webpackChunkName:"OtherComponent"*/'./OtherComponent'))
|
||||
@ -213,7 +217,8 @@ export default () => {
|
||||
|
||||
1. 将要装载,在render之前调用;
|
||||
2. 可以在服务端被调用,也可以在浏览器端被调用;
|
||||
3. componentWillMount 每一个组件render之前立即调用
|
||||
3. componentWillMount 每一个组件render之前立即调用;
|
||||
4. 目前在17中已经遗弃了这个接口,前缀为 UNSAFE_
|
||||
|
||||
### componentDidMount
|
||||
|
||||
@ -244,7 +249,7 @@ function useState(initData) {
|
||||
|
||||
redux 分为几个重要的概念:1. store(容器)、2. state(数据)、3. action(动作)、4. reducer(计算动作过程)、5. dispatch(事件分发)
|
||||
|
||||
工作过程:dispatch通过调用action执行一个事件,store自动调用reducer对state进行变更,state变更,同时view也产生变化
|
||||
工作过程:dispatch 通过调用 action 执行一个事件,store 自动调用 reducer 对 state 进行变更,state 变更,同时 view 层也产生变化
|
||||
|
||||
## 参考文档
|
||||
|
||||
|
@ -10,3 +10,35 @@ group:
|
||||
# Typescript
|
||||
|
||||
目前市面上比较流行的js的超集,目的是为了让js更加的严格,向强类型的语言看齐,同时为了后期维护上的便利。
|
||||
|
||||
## interface 和 type 的区别
|
||||
|
||||
interface 更偏向结构定义,type更偏向数据之间的关系
|
||||
|
||||
1. 两者继承的方式不同
|
||||
|
||||
```js
|
||||
interface App extends Module {
|
||||
|
||||
}
|
||||
|
||||
type App = Module & { name: string }
|
||||
```
|
||||
|
||||
2. type 可以神秘基本数据类型、联合类型、元祖类型,interface不能
|
||||
|
||||
```js
|
||||
type Name = string
|
||||
|
||||
type Pet = Dog | Cat
|
||||
|
||||
type PetList = [Dog, Cat]
|
||||
```
|
||||
|
||||
3. type 可以使用 typeof 获取类型,interface不行
|
||||
|
||||
```js
|
||||
const Name = 'nicenote'
|
||||
|
||||
type Iname = typeof Name
|
||||
```
|
||||
|
@ -54,7 +54,6 @@ yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel
|
||||
### centos 快速安装
|
||||
- yum install nginx -y
|
||||
|
||||
|
||||
## 常用命令
|
||||
|
||||
### 查看 nginx 配置文件路径和安装路径
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@ -1,10 +1,10 @@
|
||||
---
|
||||
<!-- ---
|
||||
nav:
|
||||
title: 关于我
|
||||
path: /resume
|
||||
group:
|
||||
order: 99
|
||||
gapless: true
|
||||
---
|
||||
--- -->
|
||||
|
||||
<code src="./index.tsx" inline />
|
||||
<!-- <code src="./index.tsx" inline /> -->
|
Loading…
Reference in New Issue
Block a user