进阶召唤兽进阶找谁切换原型之后怎么没法继续切换了

博客访问: 1092549
博文数量: 200
博客积分: 3308
博客等级: 中校
技术积分: 2232
注册时间:
认证徽章:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
转自:作为编辑器之神,vim一直是我编辑文本的不二选择,哪怕其坎坷的学习曲线让人头疼不已.末学总结一下经验教训,以作备忘.入门个人习惯编译选项./configure –with-features=huge –enable-cscope –enable-fontset –enable-multibyte –enable-perlinterp –enable-rubyinterp –enable-pythoninterp工作目录:pw[d] 显示当前工作目录:cd[!] {path} 工作目录切换到path移动:&h j k l 0 ^ $ e E b B w W f F t T ; , % gg G [ ]编辑:&d y p r c o在vim中还存在如x,s等编辑命令,这些命令只是&编辑命令 + 移动命令&的简答组合,如x X D C s S Y简单总结大小写操作命令的区别:作用于行首: I作用于行尾: D,C,A,R作用于整行: Y,S,V作用于逆方向: X,F,P,O,N搜索时大小写相关: \C改变大小写: gU关于编辑命令,需要说明一点:&x,d,c这些命令会把脏数据置入vim的粘贴板(所谓脏数据,也就是被命令删除或改变的那部分数据).利用vim的这个特性,我们可以轻易的实现文本剪切,如交换两个字符,交换两行文本,甚至是交换两段文本:16进制编辑,码农必备,lol:%!xxd 16进制编辑:%!xxd -r 文本编辑保存会话Session可以忠实地记录vim当前的视图,如windows和tabs,甚至是高亮.真是谁用谁知道.:mks[!] [file] 把当前视图保存到file,如file未指定,则缺省为Session.vimvim -S Session.vim 打开Session.vim,也就是Reload view,重新打开视图.可视化编辑v: charwiseV: linewiseCtrl-V: blockwise,后文介绍.gv 重选上次选中的区域,谁用谁知道区域% 作用于当前打开的整个文件‘ 作用于当前选中的区域,其中,’表示选中区域的最后一行.{num1},{num2} 作用于从第num1行到第num2行内置命令. 当前行,比如说,想要作用于从当前行开始的总共8行文本,则可以8:,$ 最后一行,:[range] substitute/from/to/[flags]&替换文本:[range] copy {num1} {num2}&复制文本:[range] Tabluarize /{char1}&对齐文本甚至可以是::[range] TOhtml&文本转为html查找:&/ ? * #:help pattern/ 向前查找keyword? 向后查找keywordn 重做最后一次/或?N 反方向重做最后一次/或?\c 查找时忽略大小写\C 查找时大小写相关\< 表示一个词的开始\> 表示一个词的结束tabs:help tabpage:tabnew 新建tab:tabclose 关闭当前tab:tabedit {file} 新建tab,并在新创建的tab打开file (等价于: tabnew后:edit {file}):tabmove {idx} 把当前tab移动到第idx tab之后gt 切换到下一tabgT 切换到上一tab{idx}gt 切换到第idx tab为了方便,我的vimrc配置如下:536&map&<A-1>&1gt537&map&<A-2>&2gt538&map&<A-3>&3gt539&map&<A-4>&4gt540&map&<A-5>&5gt541&map&<A-6>&6gt542&map&<A-7>&7gt543&map&<A-8>&8gt544&map&<A-9>&9gt尽管很dirty,好歹能工作.windows:sp {file} 横向(horizontally)切割窗口,并在新窗口打开file:vsp {file} 竖向(vertically)切割窗口,并在新窗口打开fileh 切换到左侧窗口j 切换到下方窗口k 切换到上方窗口l 切换到右侧窗口如果对所有vimer的配置做统计,下面这段配置绝对是出现频率最高的:577&map&<C-h>&<C-w>h578&map&<C-j>&<C-w>j579&map&<C-k>&<C-w>k580&map&<C-l>&<C-w>l省下的绝对不仅是一次w按键,vimer你懂的.关于窗口的扩大缩小, :help window-resizemarks:help marks我用得最多的marks操作是:‘[ 跳到上一次被改变(changed)或者复制的文本段的第一个字符'' 跳回上一次跳转的地方'^ 跳到插入模式最后一次结束的地方'. 跳到上一次文本被修改的地方缩进与对齐:help indent.txt> 向右缩进shiftwidth个字符大小< 同上,但是向左缩进= 对齐文本>,<.=这三个命令的作用域既可以是选中的一段文本,也可以是一个文本对象(后文进阶部门会解释).进阶[N]&执行N次NOTE: [N]和[N]是不一样的,如:d3w和3dw两个操作虽然看似一样,但实际上它们在vim内部的行为是有本质区别的:d3w表示一次删除3个w,而3dw表示一次删除一个w,重复3次.[start pos][end pos]&从start pos开始执行到end pos,[]表示其内部的命令不是必须的,也就是说,start pos和end pos都不是必须的.gg=G和^y$是两个极好的例子:gg=G 对齐整个文件(gg跳到第一行,=对齐,G最后一行)^y$ 从当前行行首复制至行尾(^行首,y复制,$行尾),你能看出^y$和Y的区别吗?NOTE:&start pos和end pos仅仅表示一个位置(黑话叫锚点),至于如何从光标移动到start pos或者end pos,vim并没有做出要求.于是,我们可以轻松地敲出如下命令,大大提高文本编辑的效率:df=, yf=, cf=, vf= 从当前字符开始删除(复制,改变,选中),直到遇到=之后dt”, yt”, ct”, vt” 从当前字符开始删除(复制,改变,选中),直到遇到”之前text object:help text-objectsi&作用于对象内部(i: inner)a&作用于整个对象(a: an)其中,action可以是v,d,c,y,甚至可以是>,<等而object可以是w,W,s,p,b,B,以及各种成对符号,如',",<,{,(,[等有了文本对象,写起代码来更是得心应手,如:向右缩进一段代码: >i{删除(复制,改变,选中)光标所在单词: diw, yiw, ciw, viw删除(复制,改变,选中)”"内所有文本: di”, yi”, ci”, vi”删除(复制,改变,选中)”"号内所有文本,包括引号本身: da”, ya”, ca”, va”visual block${select region}块操作可以一次编辑多行文本,对有规律的编辑需要实在是一大利器.如:宏所谓宏,就是一段录制好的操作.q${register}q&录制commands到寄存器register[N]@register&重放寄存器register中的宏N次看起来,宏和块操作的区别非常明显: 宏“可以认为”是linewise,而块操作是blockwise,也就是说,宏对应的是几行文本,块操作对应的则是选中的block.从这明显的区别中我们可以推出一个重要的结论: 宏中的锚点有相对的概念,而块操作是绝对的.比如说,行尾就是一个最简单的相对概念,每一行的行尾所在的锚点可能都不一样,但这丝毫不影响宏正确的在所有行行尾插入一段文本.而在块操作中,命令A(在行尾插入)对应的语义却变成了block的尾部,显然,”block的尾部”这一概念对block中的所有行都是相同的,也就是所谓绝对的位置.折腾配色:help syntaxvim自带了许多配色方案(在这里有各种预览),可以用colorscheme命令选择,如:&colorscheme&desertEx哪怕再性感的配色,看久了也会生烦,所幸vim自带了synIDattr函数,在vimrc中加入如下脚本:215&nmap&<C-S-P>&:call&<SID>SynStack()<CR>216&function!&SynStack()217&&&&if&!exists("*synstack")218&&&&&&&return219&&&&endif220&&&&echo&map(synstack(line(‘.’),&col(‘.’)), ‘synIDattr(v:val, "name")’)221&endfunc:so %安装后就可以通过Ctrl-Shift-P组合键方便地查看某段文本的ID了.得到文本ID之后,需要通过指定颜色来实现自定义.vim支持rgb配色(#445599之流),可是,身为毫无艺术感的二逼后台开发,我自然更偏爱skyblue这类见其名即可知其意的配色方案了:).为了让生活容易些,可以:runtime syntax/colortest.vim直接预览,谁用谁知道.vim的强大总是让人爱不释手,我们甚至可以自定义ID,比如说,我的代码中TODO横行,为了更直观的显示TODO项,于是便有了这段配置:60&highlight&RipGroup&ctermbg=yellow&cterm=none&ctermfg=black61&match&RipGroup&/TODO/btw,在终端下切记要打开256色:&set&t_Co=256再次btw,简单回答一个可以很好的区分vim新手和老鸟的问题,对Alt键的map为何在终端模式下如此虐心? 因为终端他妈的自动在Alt前面加了Esc前缀,这该让人多胸闷啊.代码折叠:help fold.txtvim支持多种折叠方法(fold methods),如indent,expr,marker,syntax等.我偏向于按syntax折叠,配置如下:716&set&foldenable&&&&&&&&&&&" enable folden717&set&foldmethod=syntax&&&&" manual : Folds are created manually.718&&&&&&&&&&&&&&&&&&&&&&&&& " indent : Lines with equal indent form a fold.719&&&&&&&&&&&&&&&&&&&&&&&&& " expr&& : ‘foldexpr’ gives the fold level of a line.720&&&&&&&&&&&&&&&&&&&&&&&&& " marker : Markers are used to specify folds.721&&&&&&&&&&&&&&&&&&&&&&&&& " syntax : Syntax highlighting items specify folds.722&&&&&&&&&&&&&&&&&&&&&&&&& " diff&& : Fold text that is not changed.728&729&"set foldclose=all730&" use space to folden731&nnoremap&<space>&@=((foldclosed(line(‘.’)) < 0) ? ‘zc’ : ‘zo’)<CR>其中,.表示当前行,zo表示展开,zc表示折叠,整行配置的意思就是通过空格键折叠代码,效果如下:vim默认在搜索和undo时会展开你辛辛苦苦设置好的折叠,这是让人非常难受的,所以我会追加这么一段配置:726&set&foldopen-=search&&&&&" dont open folds when I search into thm727&set&foldopen-=undo&&&&&&&" dont open folds when I undo stuff编码249&set&encoding=utf-8250&set&fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,gbk,euc-jp,euc-kr,latin1251&if&has("win32")252&&&&&set&fileencoding=chinese253&&&&&" fix menu gibberish254&&&&&source&$VIMRUNTIME/delmenu.vim255&&&&&source&$VIMRUNTIME/menu.vim256&&&&&" fix console gibberish257&&&&&language&messages&zh_CN.utf-8258&else259&&&&&set&termencoding=utf-8260&&&&&set&fileencoding=utf-8261&endifgui设置简单介绍一下gvim的设置,首先是字体,我的配置如下:229&set&guifont=Courier_New:h9:cANSI231&set&guifontwide=幼圆:h10:cGB2312guifont对应的应为字体,guifontwide对应所谓的宽字节字体,中文就是宽字节.我个人倾向于隐藏gvim菜单栏,工具栏,滚动条等,以最大化代码可视面积:237&if&has("gui_running")238&&&&&" set guioptions-=m&&" remove menu bar239&&&&&set&guioptions-=T&&" remove toolbar240&&&&&set&guioptions-=r&&" remove right-hand scroll bar241&&&&&set&guioptions-=l&&" remove left-hand scroll bar242&&&&&set&guioptions-=L&&" remove left-hand scroll bar even if there is a vertical split243&&&&&set&guioptions-=b&&" remove bottom scroll bar244&endif我要吐槽的是,即便设置了set guioptions-=l,当切割了横向窗口时,左侧的滚动条还是会如幽灵般出现.各种不解后查了手册才明白,原来还要set guioptions-=L,但是,右侧滚动条却没有这个坑,简直坑爹.tags:help tagstags是什么,程序员都懂.通过程序可以很方便的为C++/C项目生成tags:ctags -R –c++-kinds=+p –fields=+iaS –extra=+q .–c++-kinds=+p 生成函数原型,该选项默认关闭.同样默认关闭的选项还有l(局部变量)和x(外部变量).–fileds=+iaS 分别对应类的继承inheritabce,类成员访问权限(access)和routine签名(Signature, 如原型或参数列表等).–extra=+q 为类成员生成的tag加上其所属的类信息.这行命令敲起来太累了,不如按一下F5来的痛快:492&map&<F5>&:!ctags -R –c++-kinds=+p –fields=+iaS –extra=+q .<CR>该命令生成的文件为当前目录下的tags.作为后台开发程序员,查阅系统源码是常有的事,不妨为/usr/include目录生成tags,然后配置vimrc,以便每次启动vim时自动加载(即便有再多的autoload,即便vim启动速度再慢,也足以秒杀emacs了…这算是降维攻击不?):274&if&has("win32")275&&&&&set&tags+=E:\workspace\linux\tags&&" tags for /usr/include/276&else277&&&&&set&tags+=~/.vim/tags/include/tags&" tags for /usr/include/278&endif279&set&tags+=tags&&&&&&&&&&&&&&&&&&&&&&&&&" tags for current project需要说明的是,我偶尔需要在windows上写代码,所以我把linux下的/usr/include目录拷贝到了windows上,然后用ctags windows版生成了tags,于是在windows上写代码也舒适了许多.插件vim什么都硬,只是有一点比较短: 扩展性,vim在这一点被咖啡机emacs拉下远远不止一条街,但是对于普通青年我,却也算是差强人意了.”Do one thing and do it well”,这恐怕是不少vim拥趸自我解脱的说辞.下面是个人最喜欢的一些插件,排名不分先后::help quickfixQuickfix是vim的标准插件,它是一个典型的plumber: 只要输入符合,则vim可以正确理解和识别”错误列表”,并跳转到对应行.我们通过gcc和grep的输出来更好地理解error format:Error: Unclassifiable statement at hello-world.f90:9.4 gcc编译器的错误提示./sys/net/bpf.c:137: bpf_wakeup __P((struct bpf_d *)); grep的输出(加上-n)可以看到,它们的格式是非常类似的.虽然Quickfix插件原意是为了更方便地调试代码,可是借用error format实现文本的匹配也是非常拉轰的:505&" search word under cursor like source insight506&"
is replaced with the word under the cursor (like |star|) (:help cmdline or :help cword)507&map&<C-F>&:execute "let g:word=expand(\"<cword>\")"<Bar>execute "vimgrep /\\/g **/*.[ch] **/*.cpp"<Bar>execute "cc 1"<Bar>execute "cw"<CR>508&" next matched line509&map&<silent>&<F10>&:cnext<CR>510&" previous matched line511&map&<silent>&<F11>&:cprevious<CR>512&" open QuickFix513&" :copen514&" close QuickFix515&" :cclose简单说明一下这段配置,表示当前光标下的单词(:help cmdline or :help cword),也就是|,表示串联命令.cc 1表示跳到”错误列表”第一条,cw表示打开quickfix窗口,如果存在可识别的错误列表.cnext和cprevious表示在错误列表中切换.btw,vim在匹配时默认使用自带的vimgrep插件,如果觉得不方便,可以显示指定使用grep:&set&grepprg=grepA.vim插件可以方便地切换源文件和头文件,还是那句话,谁用谁知道啊.:A 在同一tab切换源文件/头文件:AV 竖向切割窗口,打开对应的源文件/头文件.:AS 横向切割窗口,打开对应的源文件/头文件.NERDTree插件可以清楚地展示目录树,而且支持许多快捷键.个人最喜欢的快捷键是t: 在新建的tab打开光标所对应的文件.可惜的是,NERDTree原版插件对所新建的tab的命名看起来没什么具体的含义,于是我用上了,配置如下:378&map&<F6>&<plug>NERDTreeTabsToggle<CR>379&380&let&g:nerdtree_tabs_open_on_gui_startup=1&&&&&" Open NERDTree on gvim/macvim startup381&let&g:nerdtree_tabs_open_on_console_startup=1&" Open NERDTree on console vim startup382&let&g:nerdtree_tabs_open_on_new_tab=1&&&&&&&&&" Open NERDTree on new tab creation383&let&g:nerdtree_tabs_meaningful_tab_names=1&&&&" Unfocus NERDTree when leaving a tab for descriptive tab names384&let&g:nerdtree_tabs_autoclose=1&&&&&&&&&&&&&&&" Close current tab if there is only one window in it and it’s NERDTree385&let&g:nerdtree_tabs_synchronize_view=1&&&&&&&&" Synchronize view of all NERDTree windows (scroll and cursor position)386&387&" When switching into a tab, make sure that focus is on the file window, not in the NERDTree window.388&let&g:nerdtree_tabs_focus_on_files=1OmniCppComplete借助于tags实现智能补全,Ctrl-X Ctrl-O弹出待选择tags菜单,Ctrl-N切换至下一选项,Ctrl-P切换至上一选项.个人配置如下:318&" :help omnicppcomplete319&set&completeopt=longest,menu&&&&&&" I really HATE the preview window!!!320&let&OmniCpp_NameSpaceSearch=1&&&&&" 0: namespaces disabled321&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" 1: search namespaces in the current buffer [default]322&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" 2: search namespaces in the current buffer and in included files323&let&OmniCpp_GlobalScopeSearch=1&&&" 0: disabled 1:enabled324&let&OmniCpp_ShowAccess=1&&&&&&&&&&" 1: show access325&let&OmniCpp_ShowPrototypeInAbbr=1&" 1: display prototype in abbreviation326&let&OmniCpp_MayCompleteArrow=1&&&&" autocomplete after ->327&let&OmniCpp_MayCompleteDot=1&&&&&&" autocomplete after .328&let&OmniCpp_MayCompleteScope=1&&&&" autocomplete after ::在智能补全时,OmniCppComplete会在当前工作窗口上方横向切割出一个preview窗口,preview窗口包含当前待选项的各种说明.杯具的是,当通过Ctrl-N或者Ctrl-P切换待选tags时,该preview窗口将会随着待选说明的变化而增大缩小,如果切换速度较快,则preview窗口看起来就像抖动一般.这也让人很难受,我们可以如下配置,关闭preview特性.319&set&completeopt=longest,menu&&&&&&" I really HATE the preview window!!!另外,不要被插件名字欺骗了,OmniCppCompelete同样支持其他语言,如python,xml等.配置如下:331&autocmd&FileType&python&set&omnifunc=pythoncomplete#Complete332&autocmd&FileType&javascript&set&omnifunc=javascriptcomplete#CompleteJS333&autocmd&FileType&html&set&omnifunc=htmlcomplete#CompleteTags334&autocmd&FileType&css&set&omnifunc=csscomplete#CompleteCSS335&autocmd&FileType&xml&set&omnifunc=xmlcomplete#CompleteTags336&autocmd&FileType&php&set&omnifunc=phpcomplete#CompletePHP337&autocmd&FileType&c&set&omnifunc=ccomplete#Complete关于autocmd,找manual: help autocmdvim在插入模式下支持13种补全方式(:help ins-completion),普通青年记不住,于是有了Supertab插件,配置如下:312&let&g:SuperTabRetainCOmpletionType=2&&&&" 2: remember last autocomplete type, unless I use ESC to exit insert mode313&let&g:SuperTabDefaultCompletionType=""该插件展示当前文件对应的tags列表.配置如下:299&if&has("win32")300&&&&&let&Tlist_Ctags_Cmd=‘ctags’&&&&&&&&&&&&&" set ctags path301&else302&&&&&let&Tlist_Ctags_Cmd=‘~/ctags-5.8/ctags’&" set ctags path303&endif304&let&Tlist_Show_One_File=1&&&&&&&&&&&&&&&" only show current file’s taglist305&let&Tlist_Exit_OnlyWindow=1&&&&&&&&&&&&&" if taglist is of the last windows, exit vim306&let&Tlist_Use_Right_Window=1&&&&&&&&&&&&" show taglist at right307&let&Tlist_File_Fold_Auto_Close=1&&&&&&&&" hide taglist if it’s not for current file这是一款高亮插件.m高亮当前光标所对应的单词,再次m清除高亮.n清除所有高亮.mark.vim默认只有下面这6种高亮颜色.如果觉得太少,可以自由地在mark.vim中添加.&68&" default colors/groups&69&" you may define your own colors in you vimrc file, in the form as below:&70&hi&MarkWord1&&ctermbg=Cyan&&&&&ctermfg=Black&&guibg=#8CCBEA&&&&guifg=Black&71&hi&MarkWord2&&ctermbg=Green&&&&ctermfg=Black&&guibg=#A4E57E&&&&guifg=Black&72&hi&MarkWord3&&ctermbg=Yellow&&&ctermfg=Black&&guibg=#FFDB72&&&&guifg=Black&73&hi&MarkWord4&&ctermbg=Red&&&&&&ctermfg=Black&&guibg=#FF7272&&&&guifg=Black&74&hi&MarkWord5&&ctermbg=Magenta&&ctermfg=Black&&guibg=#FFB3FF&&&&guifg=Black&75&hi&MarkWord6&&ctermbg=Blue&&&&&ctermfg=Black&&guibg=#9999FF&&&&guifg=Black最后推荐两大暗爽已久的神器,一是,在firefox上高度仿真了vim.一是,其惊艳的键位布局彻底释放了我被压抑多时的小拇指(码农你懂的),而奢侈的电容键盘更让人概叹.当然,如果拿hhkb来码中文,那就是另一回事了…
阅读(10528) | 评论(0) | 转发(2) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
标签:至少1个,最多5个
总括: 包含这三个月来碰到的一些觉得比较好的面试题,三个月没怎么写博客着实有些手痒,哈哈哈。7000余字,不成敬意2333
原文地址:
知乎专栏&&简书专题:&&
博主博客地址:
烈火试真金,逆境试强者
React和Vue对比
数据驱动视图,提供响应式的视图组件
都有Virtual DOM,组件化开发,通过props参数进行父子组件数据的传递,都实现webComponents规范
数据流动单向
都支持服务端渲染
都有支持native的方案,React的React native,Vue的weex
社区:React社区还是要比vue大很多;
开发模式:React在view层侵入性还是要比Vue大很多的,React严格上只针对MVC的view层,Vue则是MVVM模式的一种实现;
数据绑定:Vue有实现了双向数据绑定,React数据流动是单向的
数据渲染:对于大规模数据渲染,React要比Vue更快,渲染机制启动时候要做的工作比较多;
数据更新方面:Vue 由于采用依赖追踪,默认就是优化状态:你动了多少数据,就触发多少更新,不多也不少。React在复杂的应用里有两个选择:
(1). 手动添加 shouldComponentUpdate 来避免不需要的 vdom re-render。
(2).Components 尽可能都用 pureRenderMixin,然后采用 redux 结构 + Immutable.js;
开发风格的偏好:React 推荐的做法是 JSX + inline style,也就是把 HTML 和 CSS 全都写进 JavaScript 了,即"all in js";Vue进阶之后推荐的是使用 webpack + vue-loader 的单文件组件格式,即html,css,js写在同一个文件;
使用场景:React配合Redux架构适合超大规模多人协作的复杂项目;Vue则适合小快灵的项目。对于需要对 DOM 进行很多自定义操作的项目,Vue 的灵活性优于 React;
Vue要比React更好上手,具体可能体现在很多人不熟悉React的JSX语法和函数式编程的思想,以及想要发挥出React的最大威力需要学习它一系列生态的缘故;
Vue着重提高开发效率,让前端程序员更快速方便的开发应用。React着重于变革开发思想,提升前端程序员编程的深度与创造力,让前端工程师成为真正的程序员而不是UI的构建者;
gulp和webpack区别
gulp是一种工具,我们可以用它来优化前端的工作流程,比如自动刷新页面、combo、压缩css、js、编译less等等。具体体现为:在gulp的配置文件中书写一个个的task,webpack则是一种打包工具,或者说是一种模块化解决方案,实际上很大一部分人刚开始使用webpack的方式就是通过gulp-webpack这个插件,写好task来使用webpack对前端的一些文件进行打包;
gulp的处理任务需要自己去写,webpack则有现成的解决方案,只需要在webpack.config.js配置好即可;
防止重复发送Ajax请求
用户点击之后按钮
abort掉上一个请求。
事件捕获阶段(capturing phase)。事件从document一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
事件处理阶段(target phase)。事件到达目标元素, 触发目标元素的监听函数。
事件冒泡阶段(bubbling phase)。事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
浏览器缓存机制
Expires策略
Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。
Cache-Control策略
Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓读取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。
以上是设置缓存时间的两种方法。那么当缓存时间过了咋整呢?有人肯定说了,那就再次发起请求啊,这是对的。问题是如果服务器资源并没有更新呢?比如说我有一个jQuery.js文件已经缓存了,当它的缓存时间到了之后服务器的jQuery.js文件也没有更新,那实际上我们直接使用本地缓存的文件就可以啊!没必要浪费带宽和时间去重新请求一个新的文件啊!这时候我们就需要再进一步看一下HTTP协议里这几个参数的作用了。
Last-Modified/If-Modified-Since
首先Last-Modified/If-Modified-Since要配合Cache-Control使用。
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间(这个参数是和Cache-Control一起过来的)。
If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since ,则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
ETag/If-None-Match
Etag/If-None-Match也要配合Cache-Control使用。
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器觉得)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match(Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
ETag和Last-Modified
HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
Ajax的状态值与HTTP状态码
Ajax的状态值
0: (未初始化)还没有调用send()方法。
1: (载入)已经调用send()方法,正在派发请求。
2: (载入完成)send()已经执行完成,已经接收到全部的响应内容。
3: (交互)正在解析响应内容。
4: (完成)响应内容已经解析完成,用户可以调用。
HTTP状态码
200 & OK: 请求成功;
204 & No Content: 请求处理成功,但没有资源可以返回;
206 & Partial Content: 对资源某一部分进行请求(比如对于只加载了一般的图片剩余部分的请求);
301 & Move Permanently: 永久性重定向;
302 & Found: 临时性重定向;
See Other: 请求资源存在另一个URI,应使用get方法请求;
304 & Not Modified: 服务器判断本地缓存未更新,可以直接使用本地的缓存;
307 & Temporary Redirect: 临时重定向;
400 & Bad Request: 请求报文存在语法错误;
401 & Unauthorized: 请求需要通过HTTP认证;
403 & Forbidden: 请求资源被服务器拒绝,访问权限的问题;
404 & Not Found: 服务器上没有请求的资源;
500 & Internal Server Error: 服务器执行请求时出现错误;
502 & Bad Gateway: 错误的网关;
503 & Service Unavailable: 服务器超载或正在维护,无法处理请求;
504 & Gateway timeout: 网关超时;
React-router原理
老浏览器的history: 主要通过hash来实现,对应createHashHistory
高版本浏览器: 通过html5里面的history,对应createBrowserHistory
node环境下: 主要存储在memeory里面,对应createMemoryHistory
内部createHistory实现:
// 内部的抽象实现
function createHistory(options={}) {
listenBefore, // 内部的hook机制,可以在location发生变化前执行某些行为,AOP的实现
listen, // location发生改变时触发回调
transitionTo, // 执行location的改变
push, // 改变location
goForward,
createKey, // 创建location的key,用于唯一标示该location,是随机生成的
createPath,
createHref,
createLocation, // 创建location
createLocation方法:
function createLocation() {
pathname, // url的基本路径
search, // 查询字段
hash, // url中的hash值
state, // url对应的state字段
action, // 分为push、replace、pop三种
key // 生成方法为: Math.random().toString(36).substr(2, length)
三种方法各自执行URL前进的方式:
createBrowserHistory: pushState、replaceState
createHashHistory: location.hash=*** location.replace()
createMemoryHistory: 在内存中进行历史记录的存储
伪代码实现:
// createBrowserHistory(HTML5)中的前进实现
function finishTransition(location) {
const historyState = { key };
if (location.action === 'PUSH') ) {
window.history.pushState(historyState, null, path);
window.history.replaceState(historyState, null, path)
// createHashHistory的内部实现
function finishTransition(location) {
if (location.action === 'PUSH') ) {
window.location.hash =
window.location.replace(
window.location.pathname + window.location.search + '#' + path
// createMemoryHistory的内部实现
entries = [];
function finishTransition(location) {
switch (location.action) {
case 'PUSH':
entries.push(location);
case 'REPLACE':
entries[current] =
React-router的基本原理
URL对应Location对象,而UI是由react的 components来决定的,这样就转变成location与components之间的同步问题。
什么是原型链
每一个对象都会在内部链接到另一个对象(该对象的原型对象),该对象有一个原型prototype,当访问对象的属性或是方法的时候,不仅仅会在原对象上查找,还会顺着原型链在原型对象的原型链上查找,直到查到null(所有原型链的顶层)为止。原型是JavaScript实现继承的基础,new关键字做的主要的事情就是将实例对象的__proto__属性指向原型对象的prototype。
什么是闭包
闭包是javascript支持的一种方式,它是一个能够引用其内部作用域变量(在本作用域第一次声明的变量)的表达式,这个表达式可以赋值给某个变量,可以作为参数传递给函数,也可以作为一个函数返回值返回。
闭包是函数开始执行的时候被分配的一个,在函数执行结束返回后仍不会被释放(就好像一个栈帧被分配在堆里而不是栈里!)
闭包的应用:
比如写柯里化函数的时候利用闭包,保存参数在内存中;
var currying = function(fun) {
//格式化arguments
var args = Array.prototype.slice.call(arguments, 1);
return function() {
//收集所有的参数在同一个数组中,进行计算
var _args = args.concat(Array.prototype.slice.call(arguments));
return fun.apply(null, _args);
模拟私有变量或是私有方法;
people = (num) =& {var num =return {
increase: () =& {
get: () =& {
man = people(4);
man.increase();
man.get();
避免引用错误
(var i = 0; i & 4; i++) {(function(_i) {
setTimeout(function() {
console.log(_i)
}, 1000)})(i)
图片懒加载与预加载
图片懒加载的原理就是暂时不设置图片的src属性,而是将图片的url隐藏起来,比如先写在data-src里面,等某些事件触发的时候(比如滚动到底部,点击加载图片)再将图片真实的url放进src属性里面,从而实现图片的延迟加载
图片预加载,是指在一些需要展示大量图片的网站,实现图片的提前加载。从而提升用户体验。常用的方式有两种,一种是隐藏在css的background的url属性里面,一种是通过javascript的Image对象设置实例对象的src属性实现图片的预加载。相关代码如下:
CSS预加载图片方式:
#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999 }
#preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999 }
#preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999 }
Javascript预加载图片的方式:
function preloadImg(url) {
var img = new Image();
if(img.complete) {
//接下来可以使用图片了
//do something here
img.onload = function() {
//接下来可以使用图片了
//do something here
跨域的方式有很多种,最常用的是jsonp主要利用了script的开放策略:通过script标签引入一个js或者是一个其他后缀形式(如php,jsp等)的文件,此文件返回一个js函数的调用。缺点在于只支持get请求而且存在安全问题。
CORS跨域,关键在于服务器,如果服务器实现了CORS跨域的接口,那么就可以使用ajax(请求路径为绝对路径)进行跨域请求。CORS请求分为两种,一种是简单请求,一种是非简单请求。简单请求是指请求方法在HEAD,GET,POST三者之间并且请求头信息局限在
Accept-Language
Content-Language
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
非简单请求请求头:
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段
执行简单请求的时候,浏览器会在请求头信息增加origin字段,服务器据此来判断请求域名是否在许可范围之内,来决定是否返回Access-Control-Allow-Origin字段。响应头有以下几种:
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
(4)Access-Control-Max-Age
Access-Control-Max-Age 首部字段指明了预检请求的响应的有效时间。
(5)Access-Control-Allow-Methods
Access-Control-Allow-Methods 首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。
(6)Access-Control-Allow-Headers
Access-Control-Allow-Headers首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。
其他方法:document.domin,html5的postMessage,window.name等
函数节流和函数防抖
函数节流让指函数有规律的进行调用,应用场景:window.resize,游戏中子弹发射(1s只能发射一颗子弹)等;
函数防抖让函数在"调用''之后的一段时间后生效,应用场景:输入框(例:在用户停止输入的500ms后再处理用户数据)。
//函数节流
* @params {Function} fun 调用函数
* @params {delay} number 延迟时间
const throttle = (fun, delay, ...rest) =& {
let last =
return () =& {
const now = + new Date();
if (now - last & delay) {
fun(rest);
const throttleExample
= throttle(() =& console.log(1), 1000);
throttleExample();
throttleExample();
throttleExample();
//函数防抖
const debouce = (fun, delay, ...rest) =& {
let timer =
return () =& {
clearTimeout(timer);
timer = setTimeout(() =& {
fun(rest);
}, delay);
const debouceExample = debouce(() =& console.log(1), 1000);
debouceExample();
debouceExample();
debouceExample();
从数列中挑出一个元素,称为"基准"(pivot),
重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
时间复杂度平均情况:O(nlog n) 最快:O(n^{2})
空间复杂度:
var quickSort = function(arr) {
console.time('2.快速排序耗时');
  if (arr.length &= 1) { }
  var pivot = arr.splice(0, 1)[0];
  var left = [];
  var right = [];
  for (var i = 0; i & arr. i++){
    if (arr[i] & pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
console.timeEnd('2.快速排序耗时');
  return quickSort(left).concat([pivot], quickSort(right));
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(quickSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
AMD和CMD的区别
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
CMD 推崇依赖就近,AMD 推崇依赖前置。
AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
JavaScript内存泄露的原因以及如何去手动释放内存
易出现泄露的场景
XMLHttpRequest 泄漏发生在IE7-8,释放方法,将XMLHttpRequest实例对象设置为Null;
DOM&BOM等COM对象循环绑定 泄漏发生在IE6-8,释放方法,切断循环引用,将对对象的应用设置为Null;
定时器(严格上说不能算是泄露,是被闭包持有了,是正常的表现),对于闭包中无用的变量可以使用delete操作符进行释放;
JavaScript垃圾回收机制
此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
限制:无法处理循环引用。在下面的例子中,两个对象被创建,并互相引用,形成了一个循环。它们被调用之后不会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。
当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾回收器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
柯里化函数
所谓的柯里化函数简单的说就是将本来接受多个参数的函数变为只接受一个参数的函数。柯里化函数的模板和实例如下:
var currying = function(fun) {
//格式化arguments
var args = Array.prototype.slice.call(arguments, 1);
return function() {
//收集所有的参数在同一个数组中,进行计算
var _args = args.concat(Array.prototype.slice.call(arguments));
return fun.apply(null, _args);
var add = currying(function() {
var args = Array.prototype.slice.call(arguments);
return args.reduce(function(a, b) {
return a +
add(1, 2, 4)
* 经典面试题
* 函数参数不定回调函数数目不定
* 编写函数实现:
* add(1,2,3,4,5)==15
* add(1,2)(3,4)(5)==15
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数
var _args = [].slice.call(arguments);
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
var adder = function () {
var _adder = function() {
[].push.apply(_args, [].slice.call(arguments));
// 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = function () {
return _args.reduce(function (a, b) {
return a +
return adder.apply(null, _args);
// 输出结果,可自由组合的参数
console.log(add(1, 2, 3, 4, 5));
console.log(add(1, 2, 3, 4)(5));
console.log(add(1)(2)(3)(4)(5));
Less常用特性
变量(@color = #fff)
混合(Mixin)
内置函数(颜色,字符串,类型判断,数学)
导入(@import)
ES6常用特性
变量定义(let和const,可变与不可变,const定义对象的特殊情况)
模板字符串
数组新API(例:Array.from(),entries(),values(),keys())
箭头函数(rest参数,扩展运算符,::绑定this)
Set和Map数据结构(set实例成员值唯一存储key值,map实例存储键值对(key-value))
Promise对象(前端异步解决方案进化史,generator函数,async函数)
Class语法糖(super关键字)
react中setState的原理
import React from 'react'
class App extends React.Component {
constructor() {
this.state = {
componentDidMount() {
this.setState({value: this.state.value + 1});
console.log(this.state.value);
this.setState({value: this.state.value + 1});
console.log(this.state.value);
this.setState({value: this.state.value + 1});
console.log(this.state.value);
setTimeout(() =& {
this.setState({value: this.state.value + 1});
console.log(this.state.value);
this.setState({value: this.state.value + 1});
console.log(this.state.value);
答案: 0、0、0、2、3;
当setState方法调用的时候React就会重新调用render方法来重新渲染组件;setState通过一个队列来更新state,当调用setState方法的时候会将需要更新的state放入这个状态队列中,这个队列会高效的批量更新state;
function enqueueUpdate(component) {
ensureInjected();
//判断是否处于批量更新模式
if (!batchingStrategy.isBatchingUpdates) {
//关键!下面的代码片段是这个方法的源码
batchingStrategy.batchedUpdates(enqueueUpdate, component);
//如果处于批量更新模式,则将这个组件保存在dirtyComponents
dirtyComponents.push(component);
//batchingStrategy对象
var ReactDefaultBatchingStrategy = {
//注意默认为false
isBatchingUpdates: false,
batchedUpdates: function(callback, a, b, c, d, e) {
var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingU
ReactDefaultBatchingStrategy.isBatchingUpdates =
if (alreadyBatchingUpdates) {
callback(a, b, c, d, e);
//关键!!!事务的理解
transaction.perform(callback, null, a, b, c, d, e);
源码地址:
如图:事务会将所需要执行的方法(图中的anyMethod)使用wrapper封装起来,再通过perform方法执行该方法,但在perform执行之前会先执行所有wrapper中的initialize方法,perform方法执行结束后,再执行所有的close方法;
var Transaction = require('./Transaction');
// 我们自己定义的
var MyTransaction = function() {
//do something
Object.assign(MyTransaction.prototype, Transaction.Mixin, {
//需要自定义一个getTransactionWrappers对象,获取所有需要封装的initialize方法和close方法
getTransactionWrappers: function() {
initialize: function() {
console.log('before method perform');
close: function() {
console.log('after method perform');
//实例化一个transaction
var transaction = new MyTransaction();
//需要调用的方法
var testMethod = function() {
console.log('test');
transaction.perform(testMethod);
//before method perform
//after method perform
理解题目的关键是,整个组件渲染到DOM中的过程就已经处于一次大的事务中了,因此在componentDidMount方法中调用setState的时候 ReactDefaultBatchingStrategy.isBatchingUpdates =这句代码已经执行过了,所以setState的结果并没有立即生效,而是扔进了dirtyComponent;因此执行三次setState的结果this.state.value的值依然是0,而setTimeout中的两次setState由于没有调用过batchedUpdates方法(isBatchingUpdates默认为false),所以setState方法立即生效,第二次setSState同理
XSS与CSRF介绍
XSS是一种跨站脚本攻击,是属于代码注入的一种,攻击者通过将代码注入网页中,其他用户看到会受到影响(代码内容有请求外部服务器);
CSRF是一种跨站请求伪造,冒充用户发起请求,完成一些违背用户请求的行为(删帖,改密码,发邮件,发帖等)
防御方法举例:
对一些关键字和特殊字符进行过滤(&&,?,script等),或对用户输入内容进行URL编码(encodeURIComponent);
Cookie不要存放用户名和密码,对cookie信息进行MD5等算法散列存放,必要时可以将IP和cookie绑定;
时隔三个月,终于迎来了博文的更新,有看到博友在评论留言:心里很温暖,这篇不算博文的博文就当是回归之作吧,接下来的时间会尽量保持在一周一更,实习结束有的是时间了,哈哈哈。
4 收藏&&|&&33
你可能感兴趣的文章
857 收藏,26.6k
85 收藏,3.3k
82 收藏,1.6k
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
分享到微博?
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。}

我要回帖

更多关于 召唤兽进阶流程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信