Open Sunny-lucking opened 4 years ago
本文首发于:https://github.com/bigo-frontend/blog/ 欢迎关注、转载。
在家或者在学校的时候,一直都是自己独立地开发项目,前后端都是自己一个人梭哈,怎么写,任凭自己主宰,在这种独自一人开发的模式中,对于团队协作模式可谓是一无所知。 后来,实习期间,经过几次版本的迭代之后,对于团队协作开发模式已经有了整体上的认知。例如一个项目的需求周期是怎样的:
发布上线
在这些过程中,前端主要发挥什么作用,也有了大致上的了解。
在实习之前,我对于工程化的概念比较模糊,更多的是局限于 组件化,模块化 等。虽然之前平时逛有一些技术博客网站的时候,会看到一些类似 《xx走进工程化xx》《xx自动化xx》,我也迫不及待地点进去了,但对于我来说,确实只是玄学,于是我会马上关闭,然后深呼吸,接着,选择《js的基本类型》《css 选择器的顺序》等文章 津津有味地读起来。
实习期间,进过几次发版之后,了解到,原来上线,是不需要手动把资源上传到服务器的。用名为jenkins 的持续集成/持续发布的工具实现起来要方便许多。
慢慢的刷新了我对工程化的认知,工程化远不止组件与模块,原来它还包括 规范化、 持续集成、自动化构建、自动化部署、自动化测试等等。
工程化是一个很大的话题,希望随着实践经验的积累,能够慢慢地掌握精髓,后面也需要找些书来看看。
除了写代码,我想我最大的一个难题就是git操作了
在实习前,我会的git命令是这样的
git pull
git add
git commit
git push
我的分支是这样的
master
在创建分支的过程中,踩了不少次坑,我终于摸出了一条正确的道路,比如 在分支的管理上,我的经历是这样的:
刚开始:一个项目对应一个文件一个分支(所有需求都在一个分支里完成)
后来:一个需求对应一个文件一个分支(导致分支间的关系不明确)
最后:同个文件夹,一个分支对应一个需求(目前来说,还没发现什么问题♪(^∇^*))
除此之外,由于有时是另一个需求还没开发完,就要开发其他需求,所以是好几个分支在同时开发的,这时难就发生了意想不到的事情,例如下面我所遇到的:
在分支上开发的过程中,添加了一些错误的文件,或者错误的修改之后,把本地的修改给add,commit,并且push上去了,但是这些修改是不需要的。怎么回退呢?
加完参数后发现gitlab不允许强行push到保护的分支上,解决方法是让项目的管理员暂时在gitlab上把你要提交的分支设置为不受保护的分支即可
除此之外也了解到有git revert这个方法
git revert
开开心心地在新的分支上开发新的功能,这时候,产品经理说 其他分支有bug或者修改需求,需要赶紧处理下,这样的话,就需要切到目标分支了,那在当前的分支上所作的修改该怎么办呢?
我想到的是commit,但其实还有更好的方法
git stash push –m”message”
git stash pop
这里需要注意的就是保存当前修改的时候,最好是添加上message,而不是简单的git stash,因为git stash 一旦多了之后,就会记不清是做了什么修改
使用git stash push –m”message”保存当前的修改
切换到需要开发的分支
使用git stash apply 应用修改
git stash apply
git log --oneline
git cherry-pick <commit hash>
git reset <commit hash>
git checkout --
在以往打印某个变量,基本都是使用console.log,但是其实还有更好的方法。
在控制台上展示数组或对象,使用console.table比console.log更加直观明了。
console.table([ {name:"Sunny",age:18,country:'China',job:'engineer'}, {name:"Luffy",age:16,country:'Japan',job:'Pirate'}, {name:"Kin",age:36,country:'Italy',job:'doctor'}, ])
当然,有时候,你可能不想输出那么多列,比如,你只想输出name和job,那么你只需要在后面加个依赖数组,表明要输出哪些字段
console.table([ {name:"Sunny",age:18,country:'China',job:'engineer'}, {name:"Luffy",age:16,country:'Japan',job:'Pirate'}, {name:"Kin",age:36,country:'Italy',job:'doctor'}, ],['name','job'])
实际上,除了console.table。还有其他的方法:
说了这么多,除了table,其实更多还是使用debugger!
使用copy方法 可以复制控制台 输出的值 到粘贴板,比手动复制要方便一些 需要注意的是,只能在谷歌浏览器上哦
在调试DOM元素的时候,我们已经聚焦到相关的DOM结构上了,但是对应的元素并没有在可视窗口上展示,那么我们可以将其快速滚动到可视窗口。
控制面板 => Elements => 右击选中的DOM节点 => Scroll into view
有时候,需要把实现好的页面交付给产品看一下,这时需要截图,但是如果网页太长,就很不方便了,难道要截很多张吗?当然,可以下载长截图的工具,可以这样,但是没必要,其实有一个长截图的命令:
控制面板 => 审查元素 => command + shift + p => capture full size screenshot
这时你就能看到一张长截图啦
当然,有时候,并不想截取那么长,只想截取某个部分,其实也是有对应的命令的
控制面板 => 审查元素 => command + shift + p => capture node screens
由于实习过程中,是在一个现在的项目上进行迭代,添加新的功能,所以可以从前辈们的代码中学习到一些比较好的代码风格,以下就列出来一些印象比较深刻的。
命名一个事件,总是有些困难,因为它很重要,我们希望可以直截了当地从方法名就看出方法的作用。比如将两个数组合并成一个新的数组,并且返回的数组不存在重复的值。
我们会怎样命名,才能体现出它的功能呢?
也许可以这样:
mergeListsIntoUniqueList(arr1,arr2){}
但是,实际上,一个方法只做一件事是最好的,这样耦合性会低一些,方法的复用性也就好一点
我们把这两个方法拆成两个方法,一个负责合并,一个负责去重
mergeList(arr1,arr2)
unique(arr)
看一下下面的代码:
多个if嵌套 if(name === "sunny" || name === "Luffy" || === "Kin"){ }
有个比较优美的写法,就是把这些值写进一个数组来,然后判断name是否在数组里即可
const nameArr = ["sunny","Luffy","Kin"] if(nameArr.includes(name)){ }
function hello(){ console.log("hi") } let enableSpeak = false if( enableSpeak){ hello() }
其实有个更加优美的写法
function hello(){ console.log("hi") } let enableSpeak = false enableSpeak && hello()
当我们在接收后端返回来的数据的时候,接受到的是一个多层嵌套的对象,而我们要拿到深层处的一个对象属性的值,为了防止报错,我们可能需要利用多层if嵌套,如下代码所示:
if(result.data){ if(result.data.obj){ if(result.list.obj.name){ if(result.list.obj.name.firstname){ } } } }
这样写起来,始终是有些麻烦的。
有个可选链操作符( ?. ),它允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效
if(result.data.obj.name.firstname){ }
有下面的代碼:
function handleEvent(event){ if(event){ //... if(event.target){ // do some thing real } } }
尽早返回使得我们的代码更加易读
function handleEvent(event){ if(!event || !event.target){ return; } }
有下面所示代码
function createObj(name,sex,age,hobby,job,address){}
当函数的参数比较多时,我们可以将同一类的参数使用对象进行合并,然后将合并后的对象作为参数传入,这样在调用该函数时能够很清楚地理解每个参数的含义,也不用去记住每个参数的位置
function createObj({name,sex,age,hobby,job,address}){}
在实习前,由于专攻vue,对于react属于零基础,由于组里的项目是react,所以就开始走上react的踩坑之路
在写react的时候,会出现一个报错,因此就会引发一些思考
在写 React 的时候,你可能会写类似这样的代码:
import React from 'react' function A(){ return <h1>前端sunny</h1> }
要是不写
import React from 'react'
就会报错,很奇怪,下面代码中明明没有使用到react的方法或属性,为什么一定要引入react呢?
后来查资料原来是 babel 会把jsx代码转化成
function A(){ return React.createElement('h1',null,"前端sunny") }
JavaScript 对this使用的限制,是有原因的。假设有如下的继承:
class Person { constructor(name) { this.name = name; } } class Geek extends Person { constructor(name) { this.sayHello; super(name); } sayHello() { alert('Good morning xdm!'); } }
如果 JavaScript 允许在调用super之前使用 this,一个月之后,我们需要修改sayHello方法,方法中使用了 name 属性:
sayHello() { alert('Good morning xdm! I am '+ this.name); }
就会出现 name 为 undefined的情况了,是不是细思极恐!
class Geek extends Person { sayHello() { alert('Good morning xdm!'); } render(){ return ( <button onClick={this.handleClick}>Click</button> ) } }
会发现 this是 undefined,第一次遇到这个问题,始终会觉得奇怪,因为在以前写vue的时候,是没啥问题的
vue代码:
<button @click="handleClick">Click</button>
或者
<button @click="this.handleClick">Click</button>
之所以react和vue事件的使用方式有所差别,原因还是内部的实现机制的不同
react将事件通过addEventListener统一注册到 document上,然后会有一个事件池存储了所有的事件,当事件触发的时候,通过dispatchEvent进行事件分发,可以简单的理解为,最终this.handleClick会做为一个回调函数调用
作为回调函数调用通常会出现this丢失的情况,就像下面的代码,最常见不过:
function delaySayHello(){ let _this = this; setTimeout(function(){ // 使用_this }) }
那有哪些方法来处理这个this呢?
写起来顺手,一气呵成。性能不太好,每次 render 都会进行 bind,而且如果有两个元素的事件处理函数式同一个,也还是要进行 bind。
class Geek extends Person { sayHello() { alert('Good morning xdm!'); } render(){ return ( <button onClick={this.sayHello.bind(this)}>Click</button> ) } }
因为构造函数只执行一次,那么只会 bind 一次,如果有多个元素都需要调用这个函数,也不需要重复 bind。
没有明显缺点,可能就是代码多了?
class Geek extends Person { constructor(props){ super(props) this.sayHello = this.sayHello.bind(this) } sayHello() { alert('Good morning xdm!'); } render(){ return ( <button onClick={this.sayHello.bind(this)}>Click</button> ) } }
顺手,好看。每次 render 都会重复创建函数,性能会差一点。
class Geek extends Person { sayHello() { alert('Good morning xdm!'); } render(){ return ( <button onClick={(e)=>this.sayHello(e)}>Click</button> ) } }
顺手,好看。处于试验阶段,如果不愿冒险,最好是在构造函数中绑定 this
class Geek extends Person { sayHello = () => { alert('Good morning xdm!'); } render(){ return ( <button onClick={}>Click</button> ) } }
为了更好地熟悉react的实现原理,看一些教学视频和资料,自己尝试着写了一个简单的react
手写简单的react核心原理 :https://juejin.cn/post/6898292945867571207
由于在项目的迭代中,新增的组件尽量是需要使用hooks来实现的,所以, 对react hook的学习也是必不可少的。
其中,学到了例如useMemo,useCallback等性能优化方法。同样,为了更好地使用,也通过看了些视频和资料,自己尝试着写了hooks中 常用的 hook的实现原理。
useMemo
useCallback
手写React Hook核心原理
学无止境,发现还有很多东西需要去学习,例如react fiber,react-saga,next.js,react 360等,在接下来的日子里,也需要努力学习啊!
欢迎大家留言讨论,祝工作顺利、生活愉快!
我是bigo前端,下期见。
有个可选链操作符( ?. ),
这是因为项目安装了@babel/plugin-proposal-optional-chaining,不是原生支持的特性.
@babel/plugin-proposal-optional-chaining
有个可选链操作符( ?. ), 这是因为项目安装了@babel/plugin-proposal-optional-chaining,不是原生支持的特性.
多谢提醒!
本文首发于:https://github.com/bigo-frontend/blog/ 欢迎关注、转载。
一、整体认知
1. 团队协作
在家或者在学校的时候,一直都是自己独立地开发项目,前后端都是自己一个人梭哈,怎么写,任凭自己主宰,在这种独自一人开发的模式中,对于团队协作模式可谓是一无所知。 后来,实习期间,经过几次版本的迭代之后,对于团队协作开发模式已经有了整体上的认知。例如一个项目的需求周期是怎样的:
发布上线
在这些过程中,前端主要发挥什么作用,也有了大致上的了解。
2. 工程化的理解
在实习之前,我对于工程化的概念比较模糊,更多的是局限于 组件化,模块化 等。虽然之前平时逛有一些技术博客网站的时候,会看到一些类似 《xx走进工程化xx》《xx自动化xx》,我也迫不及待地点进去了,但对于我来说,确实只是玄学,于是我会马上关闭,然后深呼吸,接着,选择《js的基本类型》《css 选择器的顺序》等文章 津津有味地读起来。
实习期间,进过几次发版之后,了解到,原来上线,是不需要手动把资源上传到服务器的。用名为jenkins 的持续集成/持续发布的工具实现起来要方便许多。
慢慢的刷新了我对工程化的认知,工程化远不止组件与模块,原来它还包括 规范化、 持续集成、自动化构建、自动化部署、自动化测试等等。
工程化是一个很大的话题,希望随着实践经验的积累,能够慢慢地掌握精髓,后面也需要找些书来看看。
3. Git操作
除了写代码,我想我最大的一个难题就是git操作了
在实习前,我会的git命令是这样的
git pull
git add
git commit
git push
我的分支是这样的
master
在创建分支的过程中,踩了不少次坑,我终于摸出了一条正确的道路,比如 在分支的管理上,我的经历是这样的:
刚开始:一个项目对应一个文件一个分支(所有需求都在一个分支里完成)
后来:一个需求对应一个文件一个分支(导致分支间的关系不明确)
最后:同个文件夹,一个分支对应一个需求(目前来说,还没发现什么问题♪(^∇^*))
除此之外,由于有时是另一个需求还没开发完,就要开发其他需求,所以是好几个分支在同时开发的,这时难就发生了意想不到的事情,例如下面我所遇到的:
更改已经被 push ,但是不是需要的
在分支上开发的过程中,添加了一些错误的文件,或者错误的修改之后,把本地的修改给add,commit,并且push上去了,但是这些修改是不需要的。怎么回退呢?
加完参数后发现gitlab不允许强行push到保护的分支上,解决方法是让项目的管理员暂时在gitlab上把你要提交的分支设置为不受保护的分支即可
除此之外也了解到有
git revert
这个方法正在发开当前分支,但需要切到其他分支
开开心心地在新的分支上开发新的功能,这时候,产品经理说 其他分支有bug或者修改需求,需要赶紧处理下,这样的话,就需要切到目标分支了,那在当前的分支上所作的修改该怎么办呢?
我想到的是commit,但其实还有更好的方法
git stash push –m”message”
保存当前的修改git stash pop
还原这里需要注意的就是保存当前修改的时候,最好是添加上message,而不是简单的git stash,因为git stash 一旦多了之后,就会记不清是做了什么修改
在错误的分支开发了新功能,新功能还没有在本地进行commit(提交)
使用
git stash push –m”message”
保存当前的修改切换到需要开发的分支
使用
git stash apply
应用修改在错误的分支开发了新功能,新功能已经在本地提交了,但是还没有push到远程仓库
git log --oneline
先获取本次commit的hashgit cherry-pick <commit hash>
切到目标分支后将本次commit的修改merge到目标分支git reset <commit hash>
切回错误分支,回退到之前版本git checkout --
. 清空修改二、调试技巧
1. console.table展示数据
在以往打印某个变量,基本都是使用console.log,但是其实还有更好的方法。
在控制台上展示数组或对象,使用console.table比console.log更加直观明了。
当然,有时候,你可能不想输出那么多列,比如,你只想输出name和job,那么你只需要在后面加个依赖数组,表明要输出哪些字段
实际上,除了console.table。还有其他的方法:
说了这么多,除了table,其实更多还是使用debugger!
2. copy复制数据
使用copy方法 可以复制控制台 输出的值 到粘贴板,比手动复制要方便一些 需要注意的是,只能在谷歌浏览器上哦
3. 滚动元素到视图
在调试DOM元素的时候,我们已经聚焦到相关的DOM结构上了,但是对应的元素并没有在可视窗口上展示,那么我们可以将其快速滚动到可视窗口。
控制面板 => Elements => 右击选中的DOM节点 => Scroll into view
4. 捕获快照
有时候,需要把实现好的页面交付给产品看一下,这时需要截图,但是如果网页太长,就很不方便了,难道要截很多张吗?当然,可以下载长截图的工具,可以这样,但是没必要,其实有一个长截图的命令:
控制面板 => 审查元素 => command + shift + p => capture full size screenshot
这时你就能看到一张长截图啦
5. 捕获局部快照
当然,有时候,并不想截取那么长,只想截取某个部分,其实也是有对应的命令的
控制面板 => 审查元素 => command + shift + p => capture node screens
三、代码风格
由于实习过程中,是在一个现在的项目上进行迭代,添加新的功能,所以可以从前辈们的代码中学习到一些比较好的代码风格,以下就列出来一些印象比较深刻的。
1. 注重命名
命名一个事件,总是有些困难,因为它很重要,我们希望可以直截了当地从方法名就看出方法的作用。比如将两个数组合并成一个新的数组,并且返回的数组不存在重复的值。
我们会怎样命名,才能体现出它的功能呢?
也许可以这样:
但是,实际上,一个方法只做一件事是最好的,这样耦合性会低一些,方法的复用性也就好一点
我们把这两个方法拆成两个方法,一个负责合并,一个负责去重
2. IF语句简化
看一下下面的代码:
有个比较优美的写法,就是把这些值写进一个数组来,然后判断name是否在数组里即可
3. && 代替 if
看一下下面的代码:
其实有个更加优美的写法
4. 多个if嵌套
当我们在接收后端返回来的数据的时候,接受到的是一个多层嵌套的对象,而我们要拿到深层处的一个对象属性的值,为了防止报错,我们可能需要利用多层if嵌套,如下代码所示:
这样写起来,始终是有些麻烦的。
有个可选链操作符( ?. ),它允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效
5. 尽早返回
有下面的代碼:
尽早返回使得我们的代码更加易读
6. 对象参数
有下面所示代码
当函数的参数比较多时,我们可以将同一类的参数使用对象进行合并,然后将合并后的对象作为参数传入,这样在调用该函数时能够很清楚地理解每个参数的含义,也不用去记住每个参数的位置
四、新技术
在实习前,由于专攻vue,对于react属于零基础,由于组里的项目是react,所以就开始走上react的踩坑之路
在写react的时候,会出现一个报错,因此就会引发一些思考
1. 为什么要引入React
在写 React 的时候,你可能会写类似这样的代码:
要是不写
就会报错,很奇怪,下面代码中明明没有使用到react的方法或属性,为什么一定要引入react呢?
后来查资料原来是 babel 会把jsx代码转化成
2. 为什么要引入super(),能不能不调用?
JavaScript 对this使用的限制,是有原因的。假设有如下的继承:
如果 JavaScript 允许在调用super之前使用 this,一个月之后,我们需要修改sayHello方法,方法中使用了 name 属性:
就会出现 name 为 undefined的情况了,是不是细思极恐!
3. 为什么调用方法要 bind this
会发现 this是 undefined,第一次遇到这个问题,始终会觉得奇怪,因为在以前写vue的时候,是没啥问题的
vue代码:
或者
之所以react和vue事件的使用方式有所差别,原因还是内部的实现机制的不同
react将事件通过addEventListener统一注册到 document上,然后会有一个事件池存储了所有的事件,当事件触发的时候,通过dispatchEvent进行事件分发,可以简单的理解为,最终this.handleClick会做为一个回调函数调用
作为回调函数调用通常会出现this丢失的情况,就像下面的代码,最常见不过:
那有哪些方法来处理这个this呢?
1. 直接bind this
写起来顺手,一气呵成。性能不太好,每次 render 都会进行 bind,而且如果有两个元素的事件处理函数式同一个,也还是要进行 bind。
2.constructor里手动bind
因为构造函数只执行一次,那么只会 bind 一次,如果有多个元素都需要调用这个函数,也不需要重复 bind。
没有明显缺点,可能就是代码多了?
3.使用箭头函数
顺手,好看。每次 render 都会重复创建函数,性能会差一点。
4.public class field
顺手,好看。处于试验阶段,如果不愿冒险,最好是在构造函数中绑定 this
4. 手写简单的react
为了更好地熟悉react的实现原理,看一些教学视频和资料,自己尝试着写了一个简单的react
手写简单的react核心原理 :https://juejin.cn/post/6898292945867571207
5. React Hook 的学习
由于在项目的迭代中,新增的组件尽量是需要使用hooks来实现的,所以, 对react hook的学习也是必不可少的。
其中,学到了例如
useMemo
,useCallback
等性能优化方法。同样,为了更好地使用,也通过看了些视频和资料,自己尝试着写了hooks中 常用的 hook的实现原理。手写React Hook核心原理
结尾
学无止境,发现还有很多东西需要去学习,例如react fiber,react-saga,next.js,react 360等,在接下来的日子里,也需要努力学习啊!
欢迎大家留言讨论,祝工作顺利、生活愉快!
我是bigo前端,下期见。