Zhang Xiao

Zhang Xiao

42 posts published

📍 beijing

js正则字符串

正则字符串是什么? 这个词是我自己这么叫的,就是可以用字符串来表示的正则。。。一般我们写正则,直接写在两个斜线中间:/这里是正则表达式/ 可是你要想写个动态正则,你就得借助字符串来完成了,因为字符串可以动态生成,并且当做参数去构造出正则的对象。但是这个参数直接加双引号变成:"/这里是正则表达式/" 这样就可以了吗? 如果去尝试一下,就知道咿~不对。。。为什么不对呢?先来看看escape这个东西吧。 一直对escape这个词有陌生感,因为他的英文是逃避躲开的意思,而程序中它有另一个名字叫做转义。 其实顾名思义,转义就是转换意义的意思,也算式一种避开本身意义的行为吧。那么什么是转义呢?为什么需要转义呢? 因为在特定环境中,字符串中的【某些字符或者字符组合】有某个意义,而希望它表示其他意义的时候,就需要转义了 感觉说了废话,所以上例子: "Hello "World."" 由于字符串中的两个双引号,和字符串开头和结尾的双引号引起了歧义,所以程序解释器不知道这个字符串合适结束,而你又想表示确确实实看到的这个由这些字符和四个双引号组成的字符时,就需要转义,让解释器明白我只是想表示双引号这个字符而不是它本来的字符串识别符。所以变成下面就可以了: "

一次记住js的6个正则方法

我时常感到困惑,为什么有些知识我总是觉得模糊,其实就是想的少,总结的少,大多数人也如此,有疑惑不清楚就找出来,想明白或者想不明白都记录下来自己的收获,比扭头忘记还是要好很多吧。。好我觉得js中的正则我不是很清楚,那么来看一下吧。 首先6这个具象的数字可以帮助我们整体记忆了,666哈哈 范围 js中有两个类可以让正则发挥作用 创建 var re = /ab+c/ 方式一:正则表达字面量,这种直接是常量的表示用法可以让js解析器提高性能 var re = new RegExp('ab+c') 方式二:构造函数,这种方式可以在runtime的时候动态确定正则是什么,更加灵活 常用特殊字符 来记忆一些常用特殊字符,这个是正则本身的范畴了,是不是总觉得记不住?其实我也记不住,每次都是去搜索和online验证来完成一些任务。我也困恼过,其实最后还是因为自己写的少吧,唯手熟尔。。。下面的总结不写具体内容,只列出具体特殊字符和分类,可以尝试一下说出他们的意义,我觉得比看表格更有利于记忆。。。 匹配量的:* + ? {n} {n,} {n,m}

闭包,能吃么

最近simona在面试,一面动不动就问闭包,这个包子啊,好吃么?哈哈,其实吧,很多时候程序员一直用着闭包,也知道有这么回事儿,可是有时候用语言去表达也是醉醉的。。。。所以,叙述不出来没事儿,也不代表能力,抽个空,总结一下也就完事儿了,是吧?so,让我们来吃掉这个包子~ 好的,开始认知: 是什么 闭包是指有权访问另一个函数作用域中的变量的函数(红宝书如是说) 怎么创建 在一个函数内部创建另一函数 (红宝书如是说) 有什么用 函数执行完后,让函数的内部变量不被当做垃圾收回的一种手段 (我自己如是瞎说哈哈) 好了,就这么些东西,好像不是很好吃啊,干巴巴的。。。那我们就深入一些,把包子馅给吃掉吧~ ######函数执行发生了什么? 看了一下红包书,说了很多东西,其实我们可以更感性的理解一下。说一下我的理解: 函数就是程序执行的一个提前写好的计划清单:plan 要开始做这个计划就需要在plan上写上我的计划需要的东西,例如我们要计算今天的花费: 早餐=5元 中餐=15元 晚餐=借的别人的钱

记一次webpack打包优化

开始接触vue的时候大概就是开始接触webpack的时候,用vue-cli直接脚手架工程后就开始开发了,用了一段时间后发现vendor.js越来越大,居然到了M的级别。看了一下vue-cli的默认配置,vendor是把node_modules里的依赖都打进vendor中,我觉得太大了这样,不如手动维护控制包的粒度,多分出几个包,充分利用浏览器并发请求资源的好处,而不是把所有东西都打进vendor中。 那个阶段开发任务重,没太多时间细细纠结,反正是迷迷糊糊看着webpack的配置文档和各种问题解决的帖子把上面提到的事儿做了。效果出来了,也就没再管过。这几天突然发现打包的地方还是有很多可以优化的点儿,便优化并记录一下。 这里着重的就是三个东西来完成此次优化: webpack.optimize.CommonsChunkPlugin OptimizeCssAssetsPlugin BundleAnalyzerPlugin 首先,记录一下目前线上的包有什么问题(这个项目是一个多入口的vue项目): 只抽离了vendor.js,却没有抽离各个入口的共有代码 每个入口模块的css也没有抽离出共有代码,导致500k的样式文件在每个入口的css文件里都有一份,浏览器缓存用不起来 css文件没有压缩,去注释等优化工作,在线上直接裸奔,传输的大小过大 有些基础库虽然不是每个入口包都需要的,但迟早是需要的,是否也应该进一步优化出来成为一个单独的包引用,而不是打在各个入口包里 所以接下来我们就利用工具解决上面的问题到达优化的目的。 CommonsChunkPlugin 就是常用的提取各个包共有模块的工具,不过我觉得这个插件设计的不是那么易于理解和使用,文档看了有些懵。。。不过我还是按照自己的实验和理解来记录一下如何使用他。 在分析之前,

从插件组件说到vue的slot上监听

最开始写网页的时候我很崩溃,为什么写的代码很快就不能看了,一坨一坨的,对自己写的东西觉得非常没有安全感,以至于很长一段时间里我都在做重复而难以维护的事情。我感觉前端开发有两件事儿是特别需要重视的,一个就是可维护性,一个就是复用性。 可维护性有很多因素,我觉得最重要的就是模块化,遥想现在的老系统的代码都是要么js一坨,要么script标签引入一坨而且顺序还得小心翼翼,真是太惨了。。。 而可复用性就是今天要记录的一些东西,虽然说的是vue里具体的解决方案。可是很多东西都是相通的。 比如最开始的时候: 第一天,我有一个table页面,好的,我html一画,js数据一拿,事件一监听完工; 第二天,我又有一个这样的table页面,差不多,好的,我把昨天写的copy过来,改改,完工; 第三天,我又有一个这样的table页面,也差不多,好的个鬼。。。。我要疯了,难道我还要copy吗?好吧,忍了。。。copy去 第四天,好了我没有同样的页面,总算松了一口气,可是需求让我把每个table都加上排序功能,好的,啊。。不对,我要加在哪里。。。第四天我总于崩溃了。。。 后来,我发现了有jq插件这种好东西,

提交表单数据的不同

前后端通信的时候,我们肯定要定义传输的格式,以便进行交流,我们利用http进行数据传输时有不少提交数据的方式,之前也就是用别人封装好的,也没有太总结过~~废话少说,listing it~ 在http的协议里有个header字段来进行数据格式的约束,就是Content-Type 字段。它有三个指令: midea-type: 资源类型MIME charset:字符集 boundary:简单来说用来区分资源的分块标识 例如 Content-Type: text/html; charset=utf-8 Content-Type: multipart/form-data; boundary=something 我们主要来总结下常见的MIME type: text/html text/css application/javascript application/json multipart/form-data application/x-www-form-urlencoded 后三种就是我们常见的表单提交的三种payload格式,一个是json字符串,一个是分片表单提交,一个是url表单提交。 后两种有什么区别呢?一般要提交文件的时候是要用分片的方式提交的,

new Promise vs Promise.resolve

异步嘛,新项目上了ES6,反正就是用,虽然没有用async/await,感觉promise也可以处理大部分情况了,毕竟项目的异步数据流没有那么复杂,这里记录一下下,有时候封装异步操作为promise,看到别人的代码有用new的,有直接调resolve的,故查了一下两者的区别。 Promise.resolve(x); 和 new Promise(function(r){ r(x); }); 是有一样的效果的,都是返回一个promise,来让使用者使用。只是Promise.resolve返回的是一个已经resolved的promise,而new Promise返回的是一个既没有resolve也没有reject的promise。 在stackoverflow上有人提到了对异常的捕获也不一样,我没有太读懂,回头在补充吧~ 通常Promise.resolve的用例就是把objects或者是thenables的对象转换成promise对象来使用。

ES6箭头函数

ES6的箭头函数其实就是词法作用域的一种方式,它本身没有this,所以会向上寻找有this的作用域当做自己的作用域;而普通函数的this是运行时动态绑定的,也就是指向调用者的作用域(上下文环境) 所以呢? function Person() { var self = this; self.age = 0; setInterval(function growUp() { self.age++; }, 1000); } // 可以改成这么写,是不是简化了很多? function Person() { this.age = 0; setInterval(() => { this.age++; // 这个this指向的就是箭头函数外面的this }, 1000); } // 那如果这样呢?套嵌箭头函数呢? function Person() { this.age = 0; setInterval(() => { setTimeout(() => { this.age++; // 这个this呢?由于它会像父级作用域寻找,发现是箭头函数,

vue-cli定制脚手架

年初的时候公司的老后台系统实在难以维护和继续在其上开发了,因为这个系统被很多人写过页面,有前端有后端,编写前端代码时都非常随意,加之没有模块化,复用性和可维护性都极低,便下定决定,重新搞一套。 经过一段时间的调研选择了vue全家桶+elementUI来开发后台系统,让交互体验更好,让开发体验更好,让生产效率提高。 从零搭建其实考虑的事情还挺多的,比如: 如何管理代码仓库 开发环境,测试环境搭建 如何接入公司的打包上线流程 如何目录划分 如何划分模块 登录和权限如何做 这篇文章来记录下和脚手架相关的改造,首先其实就是上了vue-cli来做,可是呢?由于预计项目会有很多页面,这些页面其实是分模块的,不同模块的页面之前其实关系不大。所以我觉得一个用户其实大部分时候只会用到其中一个模块的页面,如果把所有页面做成一个单页应用很多资源加载就不是很必要了,所以第一个改造就是:做成多入口打包,也就是做成多个单页应用,每个模块一个入口。 /build/utils exports.getEntries = function (globPath) { var entries = {} glob.sync(globPath).forEach(function (entry) { var basename

Date

嗯嗯,今天复习一下js中原生的Date对象~不不。。是预习。。。 翻了一下MDN,没错Date对象有一大坨方法,先不管那么多,先来了解一下构造方法: 四种用法: new Date(): 默认是当前时间 new Date(value):value是时间戳 new Date(dateString):这个dateString比较多,不太好记忆,用到的时候试试就好啦,该字符串必须能被Date.parse()识别才行哦,不过文档上是不推荐在ES5之前使用的,因为哥浏览器实现差异大, 手动解析会更好一些。 new Date(year, month, day, hour, minutes, secondes, milliseconds) Date拥有的方法众多,我觉得很有用的是几个get方法: 年:getFullYear() 月:getMoth() + 1 注意它从0开始的 日:getDate() 注意不是getDay, getDay返回的是星期中的第几天(0-6)

DOM之度量

一个网页就是一个图纸,前端工程师的任务就是把图纸中所有元素的尺寸和大小规划好,然后把它们安放在图纸相应的位置。有时候我们需要度量元素的位置和坐标,那么我们来复习一下和度量有关的那些事儿吧~翻译原文的链接here css盒模型 一个文档例子 <div id="example"> ## Introduction The contents. </div> 这个文档盒子绝对定位,有borders、paddings、margins、和滚动条: #example { position: absolute; width: 300px; height: 200px; left: 160px; top: 160px; padding: 20px; margin: 20px; overflow: auto; border: 25px solid #F0E68C; } 然后我们看看css样式对这个盒子起的作用,看上面的数字标注,很清晰吧。

DOM之样式

jQuery有css这个方法很便利的获取或者设置文档的样式,如果原生的方式呢?可以回顾一下js是如果操作DOM样式的。 className className属性总是和html上的class特性保持一致的。用法例如: <body class="class1 class2"> <script> alert(document.body.className) document.body.className += ' class3' </script> </body> 如果想要删除一个class,可以把字符串中的class字符replace成空,也可以应空格split字符串后删除class再join回来。多数js框架都会提供内置方法来做这些工作,例如jq中: $( "p" ).removeClass( "myClass noClass" ).addClass( "yourClass" ); style

DOM之访问

今天无意中看到一篇文章觉得可以很好的回顾一下关于DOM基础知识,故翻译了一下~原文链接是here 所有的起源都来源于document这个对象。这个对象提供了提供了很多方法来搜索和修改元素。 根元素:documentElement和body DOM的根元素总是document.documentElement, 它是一个可以引用最开始的HTML标签的特殊属性。另一个起点的属性是document.body,它表示了BODY标签。 这两个进入点都是有效的,但是document.body可以为null,比如这种情况,在HEAD标签里试图访问body就会是null,因为此时还没有解析到body标签。 <!DOCTYPE HTML> <html> <head> <script> alert("Body from HEAD: "+document.body) // null </script> </head> <body>

从快排递归说起

快排最简洁的是递归写法,可是当我问自己你真的想明白到底发生了什么吗?如果你有些不能肯定,那么我们一起来看看到底发生了什么。 其实快排的原理用语言描述起来挺容易的,简单说就是在数组中找一个值作为对比值(常常找中间那个元素),然后把数组中小于此值的值放入一个数组,把大于此值得放入另一个数组。然后针对这两个数组重复递归上面的过程,把所有的值连接起来就是最后的结果了。 让我们来写写代码: var qsort = function(arr) { if(arr.length <= 1) { return arr; } var pivot = arr.splice(Math.floor(arr.length/2), 1)[0], left = [], right =[]; for(var i=0; i<arr.length; i++) { if(arr[i] < pivot)

mobile

移动端适配页面快速搭建

遥想去年入前端坑的时候,就很快遇到了移动端页面的开发,天(er)真(bi)的我立马上去量设计稿,然后撸起袖子就是干!可是打开调试一看乱套了,先不说布局上的问题,就是大小看起来也不太对啊,太大了!然后就去问老司机,他说尺寸你要除以2才行,我心里挺郁闷的,为啥啊。。当时羡慕紧,就先这么搞,然后加上百分比布局,完成了第一次的开发任务。。。 但是!这只是叫完成,我非常不喜欢心里有梗的感觉,我觉得这事儿没这么简单,而且随着后期开发的进行,有一天设计mm给我说你这个线好粗啊,能不能再细点儿,我心中一万个不(cao)情(ni)愿(ma)飞过,我这已经是1px了啊。。。 还有最关键的我发现用百分比布局有个极大的缺陷,就是当你感知设计的设计意图的时候,(我们的设计师同学们的设计意图有多重要,我觉得好的设计师一定是设计意图非常犀利的),有些设计元素并不是单纯的左对齐,右对齐,或者和某个元素有某种视觉上的联系。也就是说,这个时候百分比布局就要头疼了,这个元素到底是百分之多少呢,用尺子量一下,可以啊,可是你把设备屏幕放大或者缩小看看,哭还是不哭?。。。。 是的,

React

React起手-组合vs继承

当然,React也是提倡组合优于继承的,这里对一些新手来说,往往他们喜欢用继承,我们来看一下如果用组合来更好的来解决问题吧~ 这里的这个例子所实现的功能,当时用vue1实现的时候特别困难,如今vue2应该也支持了相应的功能,不过当我看到入门文章的这里的时候,我感觉这是React很强大的地方,简单来说就是,可以进行依赖注入,注入什么呢?当然什么都可以,这就给UI组件强大的灵活能力,即父组件只用实现那些不变的部分,那些变化的部分我只需要抽取出来行程单独的子组件,这样父组件在不知道他内部某些部分是什么样子的时候就可以进行抽象。 还是先看例子来理解一下: function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ); } function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="

React

React起手-提炼状态

官方文档叫Lifting State up,不知道我翻译的是否妥当,哈哈哈。 组件之间的数据有些肯定是共享的,也就是说这个共享数据不管在什么地方被改变了,所有组件都要及时的反应到自身上,官方推荐提炼共有状态到他们最近的祖先上。举个例子来理解这个东东,例如有个温度计,当温度到100以上时候水开,反之不开。 function BoilingVerdict(props) { if (props.celsius >= 100) { return <p>The water would boil.</p>; } return <p>The water would not boil.</p>; } 然后我们添加一个计算器来输入温度 class Calculator extends React.Component

React

React起手-表单

对于表单的处理,react的处理和原生很相像,所以没有什么多说的,就是看例子吧~ 以下就是input, textarea, select的用法,其实都一样,把state的值挂载到相应位置的value上,并且监听相应的事件即可,注意事件的写法onChange驼峰哦。回调函数的第一个参数是event哦,原生event对象可以做一些例如消除默认行为和停止冒泡的事情。这些被控制的组件叫做controlled components。 然后你会发现这也太麻烦啦,每一个表单控件我都得写一个handler区处理它,这样的话不仅麻烦而且和原生代码以及非react得库难以整合,所以有uncontrolled components, 来改善这一情况,会另起文章来记录~ class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.

React

React起手-列表渲染

列表渲染也很简单,利用map方法返回一个新的渲染列表即可,例如: const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li>{number}</li> ); ReactDOM.render( <ul>{listItems}</ul>, document.getElementById('root') ); 基础列表组件的构造中,有一个重要的属性值key需要你进行指定,这个很重要,和帮助框架进行性能优化有关,具体深入原因后续会继续了解,先来看例子: function NumberList(props) { const numbers = props.numbers; const listItems

React

React起手-事件处理

React的事件处理和DOM的事件处理是很相似的,只是有一些语法上的区别: React的事件名是驼峰的,不是小写的 在JSX语法中,你传递一个fucntion作为时间处理器,而不是一个string 举个例子: <button onClick={activateLasers}> Activate Lasers </button> 而且如果你想拿到事件对象event,这个对象是React按照w3c标准完成的,所以不用担心浏览器的兼容性,可以像如下这样: function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); } return ( <a href="#" onClick={handleClick}> Click me </a>

React

React起手-条件渲染

可以根据state的值进行组件的条件渲染。例如: function Greeting(props) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />; } ReactDOM.render( // Try changing to isLoggedIn={true}: <Greeting isLoggedIn={false} />, document.getElementById('root') ); 你还可以用变量去存储组件,以便进行条件筛选,使得渲染函数的返回值更加清爽,例如: class LoginControl extends React.Component { constructor(props) { super(props); this.handleLoginClick = this.

js

小心事件多次绑定

今天同事让我看一个问题,就是jquery中的on事件的回调函数中引用了外部的一个变量a,但是经过一些操作之后在触发事件回调时候a的变量的值总和预期的不一致,好久没写jquery看了半天也没看出来哪里有问题,后来发现原来绑定的这个on语句在操作的时候会不断被执行,意味着添加了好多次的回调函数,而回调触发的时候就会触发n多次。这就意味着如果每次添加on的时候引用的变量a是不同的话,回调函数多次执行时引用的a的值也就是不同的(这次闭包添了乱orz。。)。 所以呢?结论就是绑定事件时最好进行单次绑定,重复绑定时要小心了,看看业务逻辑是否真的需要这么干,当然上面的解决办法也很简单,先解绑元素之前的事件再添加现有的事件即可。 $().off('change').on('change', function(){});

从exports和module.exports说起

虽然暂时工作上没有用到commonJS的模块化写法,但是还是经常看到这种写法的源码或者文章,有时候看到exports和module.exports就有点儿傻傻分不清楚了。。。我想初学者可能会和我一样的疑问吧,结果一查还真是一大把。。看了几篇文章,其中stackoverflow上有个哥们写的很好,故记录在此。 其实记住和理解这张图就很容易区分了: 这个图展示了两者的关系,为了方便理解,我觉得可以这么来解释,当一个js文件需要模块化的时候,node环境中会给文件注入exports和module.exports这两个变量,并且刚开始的时候这两个变量是指向同一个空对象的,随后你拿着这两个变量做了一系列操作后,注意这是关键:只有module.exports会被返回以便后续其他模块require引用使用。 所以到这里只是解释了运行的关系,那为啥弄两个呢?对啊为啥啊?只要module.exports不就行了,你赋值给它返回也是它多好多正常,非要弄个exports干啥幺蛾子。。。。哈哈,我理解的是,没错,你总是用module.exports是可以的而且不会出错,但是每次都这么写: module.exports.a = 1; module.exports.b = function() {}; module.exports.c = 'ccc'; 觉得累么??那这样写好了: exports.a