SZU_SH


  • 首页

  • 分类

  • 归档

  • 搜索

深入浅出react笔记

发表于 2018-06-24 | 阅读次数:

react 的生命周期

react 的生命周期,可能经过三个过程:

  • 装载 mount
  • 更新 update
  • 卸载 unmount

装载 mount

当组件第一次被装载的时候,react 会依次调用如下函数

  • constructor
  • getInitialState:一般不会用到,state 一般在constructor 中进行初始化
  • getDefaultProps
  • componentWillMount
  • render
  • componentDidMount

constructor

constructor 阶段的主要作用是:

  • 初始化 state
  • 给类的方法bind this

getDefaultProps

在es6 中我们需要这样来给props赋默认值

1
2
3
class Sceen extends React.component{
private static defaultProps = {};
}

render

在生命周期中只有render是必须实现的函数,它只是返回一个 jsx 描述的结构,最终由react来进行渲染。如果返回null 或者 undefined ,就等于告诉react不用进行渲染

componentWillMount 和 componentDidMount

一般来说componentWillMount用的比较少,componentDidMount 用的比较多一点

需要注意的是:componentDidMount 是发生在组件已经挂载到 dom 上触发的

更新 update

更新的生命周期主要有以下几个:

  • componentWillReceiveProps
  • shouldUpdateComponent
  • componentWillUpdate
  • render
  • componentDidUpdate

componentWillReceiveProps

这里需要注意的几点是:

  • 当父组件的render 被调用的时候,子组件的 componentWillReceiveProps 也会被触发,不管子组件的props是否发生了更新
  • 在组件中setState并不会触发这一生命周期

shouldUpdateComponent

这是组件中最重要的一个生命周期了,它决定了组件是否需要重新渲染。
需要注意的是,setState并不会立即修改组件的state,在这一周期的时候组件的state还是原来的。

componentWillUpdate 和 componentDidUpdate

会在render的一前一后进行触发,componentDidUpdate 和 componentDidMount一样也是在dom重新渲染之后触发的。

卸载 unmount

在销毁组件之前,会触发,componentWillUnmount,这个钩子适合用来处理一些清除性的工作。

mac前端开发环境

发表于 2018-06-14 | 阅读次数:

最近正在从 windows 转向 mac,不得不说mac做开发确实省心不少。这里记录下相关环境的搭建与配置。

git

git 可以有两种方式去安装,可以从 github上下载然后自己编译安装,由于这个过程比较麻烦,所以我还是选择了另一种方式,直接在app store中安装xCode,安装好之后就会自动的帮你安装好git了。

Homebrew

mac 下的包管理工具,很多东西可以通过他来进行安装。他的安装方式也很简单,只需复制一条简单的命令行就可以了。

1
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

item2

item是mac上一框非常好用的终端,基本上也是必备的。直接去官网下载就可以了 https://iterm2.com/。
具体的一些相关配置可以参考这偏文档 https://segmentfault.com/a/1190000010518195

谷歌浏览器插件

  • Rememberry 翻译非常好用,可以帮助你复习巩固单词,看英文文档的时候也更方便快捷
  • Tampermonkey 里面有很多有趣的脚本可以用,比如百度云盘可以免安装客户端直接下载
  • Vimium 强烈推荐这个,里面有视频教程,基本看一遍就会了,让你可以完全脱离鼠标,用键盘控制浏览器,非常好用
  • Insight.io for Github 让你能够方便快捷的看github仓库的目录结构,甚至能够像ide一样搜索残酷,强烈推荐使用
  • postman 调接口非常好用的一个插件,不过现在已经脱离谷歌浏览器成为了一个桌面程序了
  • JSON-handle 可以非常方便快捷的格式化json数据

webstorm

webstorm 是一款非常好用的前端ide,虽然本身的功能已经十分强大了,但是还是有非常多的强大的插件可以用。这里简单列举几个我常用的插件:

  • .ignore 支持 .gitignore 的语法规则,并提供自动将文件加入 .gitignore 的功能
  • Key PromoterX Key Promoter的升级版,使用鼠标点击的时候会提醒你键盘的快捷键是什么,帮助你更好的使用键盘进行工作
  • ideaVim 可以让你在 webstorm 中使用vim
  • AceJump 帮助你快速跳转代码,和谷歌浏览器中的vimuim功能类似 ,非常好用的一个插件,强力推荐,默认快捷键是 ctrl+; 三个键,由于mac上按+号不是很方便个人建议改成command;
  • Material Theme UI 一个很好看的主题
  • Rainbow Brackets 更好看的括号颜色
  • activate-power-mode 装逼神器,和atom上的敲代码酷炫效果类似,一个比较鸡肋的功能
  • CodeGlance 可以在右边看到代码的整体缩略图,也强力推荐使用
  • eslint 如果项目中需要用到eslint的话,比较建议装上

以上是比较通用的一些插件,还有vue,react,angular的一些插件,就看个人需求具体的去安装了。

dash

一款非常好用的api文档查看工具,不过是收费的。

以上是我觉得开发当中比较好用的一些东西,仅供参考,如果有更好的工具欢迎分享~

浏览器如何验证证书的

发表于 2018-05-03 | 分类于 HTTPS | 阅读次数:

基本概念

CA

首先CA是Certificate Authority的缩写,也叫“证书授权中心”。
它是负责管理和签发证书的第三方机构,就好比例子里面的中介——C 公司。
一般来说,CA必须是所有行业和所有公众都信任的、认可的。因此它必须具有足够的权威性。就好比A、B两公司都必须信任C公司,才会找 C 公司作为公章的中介。

CA 证书

顾名思义,就是CA颁发的证书。

浏览器中默认有得到认证的根证书,使用https的网站需要让浏览器信任自己的证书就需要去申请这些机构的证书

浏览如何验证证书的真伪呢?

首先我们需要了解一下CA是如何给我们发证书的。

1.向CA申请证书
2.CA认证了你的信息之后同意给你颁布证书,生成证书信息,生成证书的指纹用于后面验证证书的真伪
3.使用私钥对指纹进行加密生成数字签名,常用的算法有RSA公钥体制
4.将证书颁发网站,生成的证书会指向给他颁发证书的CA

了解完CA证书的生成之后我们就可以看一下浏览器如何验证证书的了。

1.浏览器拿到证书之后会找到证书所对应的CA
2.浏览器取出CA中的公钥,使用公钥对证书的签名进行解密
3.将解密的结果与证书指纹做对比,如果对比一致则说明真书是真的
4.浏览器提取出证书中的公钥使用

vue生命周期

发表于 2018-03-26 | 分类于 vue | 阅读次数:

在 vue 的官方文档中,我们可以看到 vue 的整个生命。

01

vue 主要给我们提供了如下八个钩子:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestory、destoryed

首先我们先粗略的了解一下,vue 初始化的时候会做哪些事情。

  • 挂载生命周期钩子
  • 解析 data 属性,将 data 属性转化为 Observer
  • 解析模板,编译模板
  • 挂载节点

各生命周期的含义

beforeCreate

在 beforeCreate 的时候,vue 只是将各生命周期注册的方法挂载到对应的钩子上,此时还未对 data 中的元素做初始化

created

这个阶段主要完成了将data转化为Observer,此时还未对模板进行编译

beforeMount

这个阶段主要做了两个事

  1. 检查vue配置,即new Vue{}里面的el项是否存在,有就继续检查template项。没有则等到手动绑定调用vm.$mount()
  2. 检查配置中的template项,如果没有template进行填充被绑定区域,则被绑定区域的el对象的outerHTML(即整个#app DOM对象,包括
    和
    标签)都作为被填充对象替换掉填充区域

此时模板还未进行编译。

mounted

这个阶段完成了对模板的编译,并完成了元素的挂载。

beforeUpdate

数据改变时,会进入这个钩子

updated

组件更新之后,会进入这个钩子

beforeDestory

组件销毁前调用

destoryed

组件销毁后调用

父子组件的加载顺序

vue 在编译模板的时候,最先读进去的是根元素,然后一层一层的递归进子模板。

编译完成之后,在从子组件开始一层一层向外挂载。

总的来说就是,从创建到编译,是从父到子,从编译到挂载,是由子到父。

$nextTick

在 vue 中,数据更新的时候并不会立刻去更新视图,而是会先将数据放入队列中异步的去更新视图。通过 $nextTick 我们就可以在视图更新之后再去调用方法了。

js 数组元素与数组长度

发表于 2018-03-23 | 分类于 JS | 阅读次数:

创建数组

在 js 中我们可以用如下的方法创建数组

1
2
3
4
5
var arr1 = [1,2]

var arr2 = new Array(3) // [empty*3]

var arr3 = new Array(1,2) // [1,2]

第一种是我们常用的一种创建数组的方法

第二种则会生成一个length为3的数组对象,我们访问 arr2[0] 返回的是 undefined

这里我们需要注意一点的是,arr2 不会初始化 arr2[0],arr2[1],arr[2],这句话是什么意思呢,看看下面这个例子你就明白了。

1
2
3
4
5
6
7
8
9
10

var arr = new Array(3)

var arr2 = [undefined,undefined,undefined]

console.log(0 in arr); // false
console.log(0 in arr2); // true

// 和 new Arry(3) 效果是一样的,注意这里是四个逗号
var arr3 = [,,,,]

修改数组

通常我们在修改数组的时候都是这样子修改

1
2
3
4
5

var arr = [];
arr[0] = 1;
arr.push(2);
console.log(arr);[1,2]

我们还可以这样操作

1
2
3
4
5

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

console.log(arr);//  [1, 2, 3, empty × 7, 10]

这里会导致和new Array(10)的结果有点类似

1
2

console.log(3 in arr); // false

arr[10] = 10 虽然会让数组的长度增加,但实际上却未真正的增加了数组的元素。

数组的方法

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

var arr = [1,3]

// 输出 0,1
for (let key in arr.keys()){
console.log(key);
}

var arr = new Array(3)

// 啥都没输出
for (let key in arr.keys()){
console.log(key);
}
1
2
3
4
5

var arr = [1,2,3,undefined,,]
console.log(arr.filter(function(value){
return true
}));// [1,2,3,undefined]

弹性布局

发表于 2018-03-21 | 分类于 CSS | 阅读次数:

布局的方案有很多,目前最常见的要数 Flex 布局了

Flex 布局

写弹性布局的基本步骤如下

指定 flex 容器

首先我们要指定一个元素为 flex 容器

1
2
3
4
5

.box {
display:flex;
display:-webkit-flex;/* Safari */
}

设置 flex 布局之后,子元素的 float、clear、vertical-align 都将失效

设置容器的属性

主要有如下六个属性

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

flex-direction

1
2
3
4
row(默认值):水平方向排列,从左边开始排列。
row-reverse:水平方向排列,从右开始排列。
column:垂直方向排列,从上往下排。
column-reverse:垂直方向排列,从上往下排。

flex-wrap

1
2
3
nowrap(默认值):不换行
wrap:换行,第一行在最上面
wrap-reverse:换行,第一行在最下面

flex-flow

就是前flex-direction 和 flex-wrap的简写

1
flex-flow:flex-direction flex-wrap;

justify-content

定义水平对齐方式对齐方式

1
2
3
4
5
6

flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,子元素之间的间隔都相等。
space-around:每个子元素两侧的间隔相等。所以,子元素之间的间隔比子元素与边框的间隔大一倍。

align-items

1
2
3
4
5
flex-start:上对齐。
flex-end:下对齐。
center:居中对齐。
baseline: 子元素的第一行文字的基线对齐。
stretch(默认值):如果子元素未设置高度或设为auto,将占满整个容器的高度。

居中对齐实现

在面试中我们经常会被问道如何实现一个居中对齐,有了上面的知识,我们就可以很容易的实现一个居中对齐。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<style>
.box {
display: flex;
align-items:center;
justify-content: center;
height: 100%;
}
.center{
width: 200px;
height: 200px;
background-color: red;
}
</style>
<div class="box">
<div class="center"></div>
</div>

设置子元素的属性

order

排列的时候,order的值越小,排列越靠前,默认为 0

1
order:1;

flex-grow

此属性主要用于当空间未被占满的时候。

默认为0,此时空间未被占满子元素会被放大。

如果设置了值,比如说

1
2
3
4
5
6
.children1{
flex-grow:1;
}
.children2{
flex-grow:2;
}

那么 children2占据 剩余空间 比children1多一倍

flex-shrink

主要用于当空间不足的时候。

默认为1,即如果空间不足,改子元素将缩小

如果设置了此值

1
2
3
4
5
6
.children1{
flex-shrink:1;
}
.children2{
flex-shrink:0;
}

此时,如果空间不足,chilrend2 不会被缩小,children1 都会被等比例缩小

align-self

可以单独设置子元素的对齐方式,会覆盖掉父有元素的align-items,
取值同 align-items

js事件代理

发表于 2018-03-20 | 分类于 JS | 阅读次数:

前端面试中,事件代理也是我们经常会遇到的一个问题,下面我们来聊一下事件代理的原理。

原理

比如说我们想个一个列表中的每一项绑定一个点击事件,如果我们一个一个去给每一项绑定事件,则会导致多次操纵dom,效率也比较低,如果添加一个新的选项的话,还得再给这个选项绑定事件。

事件代理,其实就是将事件绑定在父元素上,然后通过父元素的点击事件来判断点击的是不是子元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
var ul = document.getElementById('test')
ul.addEventListener('click', function (event) {
var target = event.target
if (target.tagName.toUpperCase() === 'LI') {
console.log(target.innerText)
}
})

</script>

我们通过绑定父元素的点击事件,通过获取 event.target 可以知道当前点击的元素,在 IE 6-8中不支持该属性,有一个 srcElement 等价于这里 target

currentTarget

如果我们打印出 event 可以看到里面有一个 currentTarget 属性,并且这个属性为 null,那么这个属性有什么用呢。

这里我们可以这样试一下

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

<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
var ul = document.getElementById('test')
ul.addEventListener('click', function (event) {
console.log(event)
console.log(event.currentTarget)
})
</script>

可以发现event.currentTarget打印出来的是 ul这个节点。看 mdn 的文档可知道,这个属性是指向当前事件被绑定的元素上

在js中console.log(obj)打印对象的时候,是对对象的一个引用,如果对象的属性后面被改变了,打印出来的对象也是会发生改变的,所以造成了前面打印 event 的时候发现他的currentTarget为null

http 304原理

发表于 2018-03-20 | 分类于 http | 阅读次数:

http 常见的状态码有很多,200,302,303,304,403,500等,其中要数304在面试中最常被问到。初学者碰到304,可能只是知道他是用于缓存,却并不知道其中的原理。下面我们来了解一下304整个的运行机制。

缓存运行机制

首先我们先思考一个问题,浏览器如何判断一个资源是否需要缓存?

可能你已经知道了,就是用请求头来控制的。

通知缓存

在 http1.1 中我们通过请求头中的 Cache-Control 来告诉浏览器缓存机制。

作为响应头其中可选的值有:

字段 作用
public 表示任何情况下都得缓存该资源
Private=[=”field-name”] 表明返回报文中全部或部分仅开放给某些用户作缓存(服务器指定的,如代理服务器等),其他用户则不能缓存这些数据
no-cache 不直接使用缓存,要向服务器发起新鲜度校验
no-store 所有内容不会被缓存
no-transform 告知客户端缓存文件时不得对实体数据做任何改变
only-if-cached 告知代理服务器,如果客户端需要的数据,代理服务器有,代理服务器不用想原服务器发送请求
must-revalidate 资源一定是向员服务器去验证请求,若请求失败会返回504
proxy-revalidate 与must-revalidate类似
max-age=delta-seconds 告知客户端在 delta-seconds 内资源是新鲜的,不用向服务器发起请求
s-maxage=delta-seconds 和max-age一样,但仅应用于共享缓存(如代理)
cache-extension 自定义拓展值

其中常用的主要是 max-age。

1
Cache-Control: max-age=100

这个请求头的意思是告诉浏览器该资源在100秒内都是新鲜的,如果未过期,则不用向服务器发送请求,直接读取缓存,在 chrome 下我们可以看到表现为 200 from cache,若过期了,则会重新像服务器发起请求。

缓存验证

现在我们已经知道了如何通知浏览器做缓存了,但是这里还有一个问题,缓存到期了,浏览器重新请求资源,但是如果资源在这段时间并没有发生修改,又重新把资源发送了一遍,如果资源又比较大,这就造成很大的宽带和时间的浪费。

304 就是用来告诉浏览器,资源还没更新过,我就不传过去了,你直接用缓存就可以了。

接着问题又来了,如何验证资源是否被修改过呢。

http 1.1 新增了几个首部字段来解决这个问题。

Last-Modified

服务器将资源返回给浏览器的时候,会将资源的最后修改时间加在请求头上返回给浏览器。

1
Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT

浏览器接收之后,会在下一次的请求把信息附带上,到服务器去做检查,若与服务器的修改时间一直,则说明资源没有被修改过,直接返回304即可。

浏览器会通过if-modified-since将信息发送给服务器

1
if-modified-since: Sun, 18 Mar 2018 13:01:31 GMT

Last-Modified 也可能会出现一个问题,如果服务器上,一个资源被修改了,但是实质上内容根本没有发生变化,也会重新发送整个资源给浏览器。

ETag

为了解决上面这个问题,Http1.1还加入了ETag这个首部。服务器通过某种算法,给资源计算出一个唯一的表示符,并在响应头上返回给浏览器。

浏览器会在下一次请求的时候,通过If-None-Match将信息发送给服务器

1
If-None-Match: "sdfsfedc8-2132"

如果匹配上了则直接返回304即可,没匹配上则需要重新发送资源。

需要注意的是,如果这两个字段被同时使用了,需要他们两个同时验证通过才会返回304,如果其中一个没验证通过,都会重新发送资源

js 作用域与闭包

发表于 2018-03-19 | 分类于 JS | 阅读次数:

在 let 和 const 出现之前,js 是没有会计作用域的, 在我们使用 var 定义变量的时候,是有可能会导致变量提升的。

比如

1
2
3
4
5
for (var i=0;i<2;i++) {
console.log(i)
}

console.log(i);// 2

这段代码最后会输出2,这是因为var 导致了变量 i 的提升,在有了 let之后我们用let就不会有这个问题。

1
2
3
4
5
for (let i=0;i<2;i++) {
console.log(i)
}

console.log(i);// error i is not defined

作用域链

我们先看看这段代码

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

var a = 1;
function test(){
console.log(a)
var b = 2;
function inner(){
console.log(b)
}
inner();
}
test();
console.log(b)

上面这段代码会依次输出,1,2,error b is not defined,

在js中函数是有自己的作用域的,函数内部定义的变量,外部是无法直接访问到的,只有函数内部才能够直接访问。

函数内部在调用 inner() ,在访问 b 这个变量的时候,会先看自己的作用域中是否有这个变量,发现没有,然后再查找 test 的作用域,发现了这个变量,然后就输出这个变量。

这里外部无法访问到test中的b,所以在函数执行完之后,b会被销毁掉。

闭包

我们先来看一下代码

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

function countResult(){
var count = 0;
return function () {
count ++;
console.log(cout)
}
}

var tmp = countResult();
var tmp2 = countResult();
tmp(); // 1
tmp2(); // 1
tmp(); // 2

这里虽然我们无法直接访问到 countResult 中的变量count,但是我们通过返回的函数可以间接的访问到count,tmp保持着对count的引用,所以tmp 中的count不会被销毁,我们再新生成一个tmp2,可以发现,tmp和tmp2之间的作用域是不同的,他们都有自己单独的局部作用域。

闭包的作用主要有两点:

  1. 隔离作用域
  2. 使局部变量能够常驻内存

同样闭包带来的问题也非常明显:

  1. 闭包会使得函数中的变量都被保存到内存中,导致内存消耗很大。在使用闭包的时候,退出函数之前,我们需要将一些不使用的局部变量全部删除。

js 的垃圾回收机制

引用计数法

应有计数通过计算变量的引用数来回收垃圾,如果一个值的引用数为0则将其回收

引用计数法会存在一个问题。

1
2
3
4
5
6
7
8

function test(){
var a = {};
var b= {};
a.b=b;
b.a=a;
}
test();

test 中的 a和b互相引用了对方,但是这里执行完之后本该销毁这两个变量,如果使用引用计数法的话,就不会销毁这两个变量而导致内存泄露。

标记清除法

标记清除法是通过根节点向下访问,如果能访问到的都不会被清除,在浏览器中根节点就 window, 这样就避免了循环引用导致的内存泄露问题。

[].slice.call(arguments) 转数组的原理

发表于 2018-03-16 | 分类于 JS | 阅读次数:
1
2
3
4
5
function test(){
console.log([].slice.call(arguments))
}

test(1,2,3,4) // [1,2,3,4]

我们经常可以看到一些文档或者比人的源码之中用这种方式把arguments转化为数组,但是为什么可以这样子操作呢,现在我们可以看一下Array.prototype.slice 他的实现原理是怎样的。

slice 的原理

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

Array.prototype.slice = function(begin, end) {
end = (typeof end !== 'undefined') ? end : this.length;

var i,
cloned = [],
size,
len = this.length;

var start = begin || 0;
start = (start >= 0) ? start : Math.max(0, len + start);

var upTo = (typeof end == 'number') ? Math.min(end, len) : len;
if (end < 0) {
upTo = len + end;
}

size = upTo - start;

if (size > 0) {
cloned = new Array(size);
if (this.charAt) {
for (i = 0; i < size; i++) {
cloned[i] = this.charAt(start + i);
}
} else {
for (i = 0; i < size; i++) {
cloned[i] = this[start + i];
}
}
}

return cloned;
};

我们可以到 slice 其实是在用 this 访问对象的属性,通过call将arguments绑定到this上,以此可以遍历出 arguments 的全部参数。

通过 slice 的底层原理我们也可以看出,如果我们传一个字符串进去,会把字符串转化为数组

1
[].slice.call('12345'); // [1,2,3,4,5]

ES6的新方法

ES6 给 Array 新加了一个方法,我们也可以通过他把 arguments 转化为数组。

1
2
3
4
5
6
7
8

Array.from({length:2,0:1,1,2}) // [1,2]

function test(){
console.log(Array.from(arguments))
}

test(1,2,3);// [1,2,3]

相比于 slice,from 更强大一点,from 还可以将带有遍历器属性[Symbol.iterator]的对象转化为数组

例如我们可以这样操作

1
2
3
4
5
6
7
8

var test = {}
test[Symbol.iterator] = function *(){
yield 1;
yield 2;
yield 3;
}
Array.from(test);// [1,2,3]
1234
$SH

$SH

灵活跳跃诈笑看天下 乐似仙

33 日志
8 分类
GitHub
© 2021 $SH
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4