Repository navigation
Expand file tree
/
Copy pathcontent.json
More file actions
1 lines (1 loc) · 35.4 KB
/
Copy pathcontent.json
File metadata and controls
1 lines (1 loc) · 35.4 KB
1
{"meta":{"title":"wintercomming的博客","subtitle":"欢迎来到wintercomming技术博客之家","description":"一个向全能努力的前端工程师","author":"mingjie yao","url":"http://yoursite.com"},"pages":[{"title":"tags","date":"2019-01-15T02:21:38.000Z","updated":"2019-01-15T02:22:22.513Z","comments":false,"path":"tags/index.html","permalink":"http://yoursite.com/tags/index.html","excerpt":"","text":""},{"title":"categories","date":"2019-01-15T02:22:41.000Z","updated":"2019-01-15T02:23:07.063Z","comments":false,"path":"categories/index.html","permalink":"http://yoursite.com/categories/index.html","excerpt":"","text":""}],"posts":[{"title":"数组迭代方法总结","slug":"数组迭代方法总结","date":"2019-01-18T12:49:30.000Z","updated":"2019-01-18T12:59:27.483Z","comments":true,"path":"2019/01/18/数组迭代方法总结/","link":"","permalink":"http://yoursite.com/2019/01/18/数组迭代方法总结/","excerpt":"","text":"话不多说,一图搞定!! 数组迭代方法 上面是数组的一些高阶函数,有很多妙用,让我记忆深刻的是之前灯南学长的reduce和indexOf & lastindexOf实现数组去重,在以后的工作和学习中若遇到其他巧妙地运用方法会将其整理于此","categories":[],"tags":[{"name":"javascript基础","slug":"javascript基础","permalink":"http://yoursite.com/tags/javascript基础/"}]},{"title":"前端跨域","slug":"前端跨域","date":"2019-01-17T07:58:48.000Z","updated":"2019-02-26T15:05:41.775Z","comments":true,"path":"2019/01/17/前端跨域/","link":"","permalink":"http://yoursite.com/2019/01/17/前端跨域/","excerpt":"","text":"跨域是什么?有什么用?想要了解这个,还得从网络资源讲起。 电脑的设计包含了很多人类的主观思想,电脑和电脑之间的交流也一样,不过他们使用的是计算机语言,当我们请求服务器,就建立了一个电脑与电脑之间的交流 当我们建立连接并接受数据以后","categories":[],"tags":[{"name":"javascript基础","slug":"javascript基础","permalink":"http://yoursite.com/tags/javascript基础/"}]},{"title":"JavaScript面向对象之继承封装和多态","slug":"JavaScript面向对象之继承封装和多态","date":"2019-01-17T07:20:17.000Z","updated":"2019-01-21T03:54:27.594Z","comments":true,"path":"2019/01/17/JavaScript面向对象之继承封装和多态/","link":"","permalink":"http://yoursite.com/2019/01/17/JavaScript面向对象之继承封装和多态/","excerpt":"","text":"继承 封装 多态封装继承和多态是面向对象编程的三大特性,在js里面也是不可缺少的一环,下面将介绍js封装继承和多态的一些方法 继承","categories":[],"tags":[{"name":"javascript基础","slug":"javascript基础","permalink":"http://yoursite.com/tags/javascript基础/"}]},{"title":"DOM树和浏览器渲染机制","slug":"DOM树和浏览器渲染机制","date":"2019-01-17T07:19:11.000Z","updated":"2019-02-26T08:37:58.116Z","comments":true,"path":"2019/01/17/DOM树和浏览器渲染机制/","link":"","permalink":"http://yoursite.com/2019/01/17/DOM树和浏览器渲染机制/","excerpt":"","text":"了解浏览器有什么作用?在网页开发的长期过程中,浏览器对于大部分WEB开发者就好似黑盒子一般的存在,很少有人注意到这方面的问题,直到近些年代码的开放、性能优化的需求、网页知识链的扩增才渐渐让开发者注意到了浏览器内部的问题,不过对于大部分初学者可能还是对此知之甚少。 实际上经过一些顶尖开发者的努力,发现了浏览器不少的问题和运行机制,不过今天我们讲讲最基本的浏览器知识,那就是渲染机制 浏览器内核这个问题其实在很久之前就开始讨论,由于浏览器的内核不同也让众多开发者脑子隐隐作痛,IE6 7 8的适配成为前端工作者的一个噩梦,许多人闻之色变. 最近微软也是宣布将放弃IE,开发者拍手叫好,同时也代表前端技术统一的时代会加速来临,一直以来不成体系的知识是初级开发者难以提升的难点之一 话说回来,浏览器的内核主要分为几种 chrome的WebKit内核(著名的V8是其中一部分) firefox的Gecko内核 微软的Trident内核 Chromium(用 electron开发)的BLINK内核 这对了解渲染机制很重要,因为首先你要清楚他是用什么实现的 内核如何渲染实际上,内核是一个大的说法,我们知道,浏览器的一个tab页面就是一个进程(当然也不一定,存在一定特殊情况,如多个空白页面),当一个tab页面被打开时就代表一个浏览器引擎开始运作,我们在服务器获取资源后,浏览器就会开始渲染资源。 其中内核包含两部分(目前的说法),js引擎和渲染引擎,js引擎顾名思义就是用于处理js代码的引擎,而渲染引擎则是用于绘制页面的引擎,两者都是单独的线程,而这样代表了两者只能同时运行一个,所以在head标签内添加script标签会阻塞代码运行,在最老的浏览器里面,甚至有一些只拥有渲染引擎的浏览器。 在渲染资源的开端,浏览器会将HTML和CSS分开处理,首先会将HTML处理为DOM树(可以理解为一个对象),树是数据结构的一种,这样也方便后续的操作。在形成DOM树后,CSS代码也会被逐步解析,形成CSSOM树,对应DOM上面的一个个节点,两者都处理完成后,引擎将其合并,形成render tree,所有的步骤都有大量的优化,而chrome浏览器比Firefox快就是因为这些点(我猜的),形成render tree后引擎开始绘制,这个步骤会被某些特殊的事件延迟,常规做法是禁止延迟的,绘制会在内存里面形成位图,即我们所能看见的部分的像素点位置和颜色,随后再显示在屏幕上。到此用户便可以看见页面元素了,通常用户体验感受最深刻的也是这一部分。 因为优化用户体验的原因,一般主流网站会在位图描绘完毕后加载JavaScript代码,而JS代码里面也存在很多获取DOM元素的方法和事件,所以放在此处也是最合适的选择。 结语虽然过程并不多,但实际上浏览器内部对此进行了大量的优化,也限于我水平的因素,不能了解到更多底层的知识,不过这一块的知识是相当深厚的,值得大量的WEB应用开发者去推敲和研究。","categories":[],"tags":[{"name":"浏览器","slug":"浏览器","permalink":"http://yoursite.com/tags/浏览器/"}]},{"title":"实习所遇问题总结","slug":"实习所遇问题总结","date":"2019-01-17T07:18:02.000Z","updated":"2019-02-26T11:43:46.131Z","comments":true,"path":"2019/01/17/实习所遇问题总结/","link":"","permalink":"http://yoursite.com/2019/01/17/实习所遇问题总结/","excerpt":"","text":"1.代码命名规范和注释虽然这个问题经常在提,但是它还是发生了,说一说我的感受: 命名一定要足够清晰,比如该组件是登录页面下的username输入窗口,可以命名为login_UsernameInput,因为公司项目是多人合作,阅读代码需要消耗不少的时间成本,所以要尽可能的命名为能够一眼就看得懂得单词或者语句。 公司必须要有自己的一套代码规范的方案,无论是驼峰命名还是用‘_’隔开,而且需要建立起完整的code review制度,特别是对于TOC项目,有很多组件在各个项目之间甚至跨平台或者产品迭代都会复用,如果在开发中代码规范不够严谨,会造成一定的误解,开发效率也会降低,甚至会遇到找不到变量,变量名重复等等问题。 强迫症患者可以忽视以上信息 2.函数和组件可复用的重要性我在刚开始编写业务复杂的页面时,会选择直接上手,一开始的理解是这样: 现在有一个业务 六个输入框都调用同样函数,自然会将函数写为一个。 但是实际开发中往往会遇到以下问题: 六个输入框中,均需要验证输入字符是否符合规范,他们都需要验证是否含有空格,其中1、4要验证是否含有数字,2、5要验证是否含有小写字母,3、6要验证是否含有大写字母,而1不仅需要验证数字,还要验证小写字母,等等等等等等 此类问题数不胜数,不仅是函数之间的问题,很可能就是子组件的问题,甚至页面区块的问题,在遇到此类问题时,一定要舍得下时间先分析代码的拆分,哪些是可以组合复用的,哪些是独立执行的,这样写出来的代码不仅条理清晰而且体积小,复用性高,会节省很多的无谓搬砖劳动,实际上归其本质jQuery、Lodash、underscore等等js库最初也是编写者为了代码的简洁复用创造而出,看似并不起眼的问题实际上能造成很大的影响 3.当UI库或其他功能组件无法达到预期目的应该怎么办?工作过程中,遇到了以下问题: iview的表格组件不能合并单元格。 刚开始我一直在阅读文档细节,企图找出关于合并单元格的介绍,最后发现iview表格组件确实不存在合并单元格的情况。 这个时候当然要:自己写一个外观相似的组件了(外观相似度90%以上)。因为如果相似度不够高,用户就会别扭。 在此之前我一直以为这些库肯定面面俱到,直到发现了错误,同时也鼓励了我,虽然最后我因为排期原因并没有将其封装成组件,而是用了原生表格加上相应的样式表代替,但是对我个人启发很大,当所有事情都开始依赖别人的东西的时候,创造力就已经被剥夺得寥寥无几了。 4.阅读文档要认真对于大部分技术来说,官方文档是相对更权威的材料,而记载的问题如果没有仔细观看和记住,会在出错时埋下一个坑 思考来源:在项目中使用v-for遍历对象并显示时,发现若对象有属性值为数组时,改变数组内元素页面不会对应刷新,实际上官方文档有说过这个问题,因为v-for的双向绑定并不是深度遍历的,只会监控对象属性值的变化,而不会监控对象属性值的属性变化。","categories":[],"tags":[{"name":"日常问题","slug":"日常问题","permalink":"http://yoursite.com/tags/日常问题/"}]},{"title":"偏函数与柯里化","slug":"偏函数与柯里化","date":"2019-01-17T07:17:22.000Z","updated":"2019-01-17T07:17:22.957Z","comments":true,"path":"2019/01/17/偏函数与柯里化/","link":"","permalink":"http://yoursite.com/2019/01/17/偏函数与柯里化/","excerpt":"","text":"","categories":[],"tags":[]},{"title":"promise","slug":"promise","date":"2019-01-17T07:16:52.000Z","updated":"2019-01-17T07:16:52.074Z","comments":true,"path":"2019/01/17/promise/","link":"","permalink":"http://yoursite.com/2019/01/17/promise/","excerpt":"","text":"","categories":[],"tags":[]},{"title":"javascript闭包","slug":"javascript闭包","date":"2019-01-17T07:15:48.000Z","updated":"2019-01-17T07:15:48.538Z","comments":true,"path":"2019/01/17/javascript闭包/","link":"","permalink":"http://yoursite.com/2019/01/17/javascript闭包/","excerpt":"","text":"","categories":[],"tags":[]},{"title":"BFC详解","slug":"BFC详解","date":"2019-01-17T07:13:57.000Z","updated":"2019-02-26T07:35:52.488Z","comments":true,"path":"2019/01/17/BFC详解/","link":"","permalink":"http://yoursite.com/2019/01/17/BFC详解/","excerpt":"","text":"什么是BFC从英文释义上来讲 BFC = block-level box(块级盒子) + Formatting Context block-level box便不用介绍了,众所周知盒子分为block box(块级元素) ,inline box(行内元素)和 inline-block box(同时拥有block可以定义宽高的特性和inline不换行的特性)三种,各有其不同特性。 Formatting Context则是CSS2.1的一种规范,这种规范决定了子元素布局和元素与其他元素的关系,BFC只是其中的一种,除了BFC还有IFC,FFC(flex布局)和GFC(grid布局)所以很多人将BFC翻译为:块级格式化上下文 如何形成一个BFC满足下列条件中至少一项,即可触发 BFC: 1.float 的值不为none。 2.position 的值不为static或者relative。 3.display的值为 table-cell, table-caption, inline-block, flex, 或者 inline-flex中的其中一个。 4.overflow的值不为visible。 BFC能干什么?1.边距重叠(也称margin 重叠) 正常的盒子规则中,上下盒子都有margin的话,距离并非两者margin相加,而是算为两个盒子最大margin值,这个时候就会出现margin重叠问题。边距重叠会带来布局上的困扰,如果你是用margin来让元素之间保持距离的话,BFC就能帮上大忙了 两个块元素要产生折叠现象,必须满足一个必备条件:这两个元素的 margin 必须是 相邻 的;那么如果定义相邻呢,w3c 规范,两个 margin 是邻接的必须满足以下条件: 必须是处于常规文档流(非float和绝对定位)的块级盒子,并且处于同一个 BFC 当中。 没有inline盒子,没有空隙,没有 padding 和 border 将他们分隔开。 都属于垂直方向上相邻的外边距。 2.清除内部浮动 BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 这是BFC其中的一个规范,我们知道,float浮动会使元素脱离常规文档流,往往使布局变得不可控,但是我们可以将其父级盒子变成BFC,这样子元素则会相对于父元素内部浮动,而不会影响外面的元素了","categories":[],"tags":[{"name":"CSS","slug":"CSS","permalink":"http://yoursite.com/tags/CSS/"}]},{"title":"防抖和节流","slug":"防抖和节流","date":"2019-01-17T07:13:38.000Z","updated":"2019-01-20T15:45:35.392Z","comments":true,"path":"2019/01/17/防抖和节流/","link":"","permalink":"http://yoursite.com/2019/01/17/防抖和节流/","excerpt":"","text":"什么是防抖?什么是节流?在了解如何实现防抖和节流之前,我们先来了解防抖和节流到底是用来做什么的 在前端开发中会遇到一些频繁的事件触发,比如: window 的 resize、scrollmousedown、mousemovekeyup、keydown 而这些事件的频繁触发会导致很多问题,性能不好以及多次请求等等问题 例如:多次点击搜索引擎搜索按钮 于是根据业务需求出现了防抖和节流两种解决方法 防抖的中心思想是:如果用户在规定时间内触发多次事件且之间间隔不超过规定时间,都统一在用户最后一次触发事件规定时间后执行该事件 节流则不同 节流的中心思想是:无论用户在规定的时间范围内触发了多少次事件,该时间范围内只执行一次事件 如何实现防抖?首先是不带立即执行参数的防抖 1234567function doubance(func ,time){let timeout;return function(){ clearTimeout(timeout) time = setTimeout(func,timeout)}} 但是往往都需要有一个立即执行的选项 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748// 这个是用来获取当前时间戳的function now() { return +new Date()}/** * 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行 * * @param {function} func 回调函数 * @param {number} wait 表示时间窗口的间隔 * @param {boolean} immediate 设置为ture时,是否立即调用函数 * @return {function} 返回客户调用函数 */function debounce (func, wait = 50, immediate = true) { let timer, context, args // 延迟执行函数 const later = () => setTimeout(() => { // 延迟函数执行完毕,清空缓存的定时器序号 timer = null // 延迟执行的情况下,函数会在延迟函数中执行 // 使用到之前缓存的参数和上下文 if (!immediate) { func.apply(context, args) context = args = null } }, wait) // 这里返回的函数是每次实际调用的函数 return function(...params) { // 如果没有创建延迟执行函数(later),就创建一个 if (!timer) { timer = later() // 如果是立即执行,调用函数 // 否则缓存参数和调用上下文 if (immediate) { func.apply(this, params) } else { context = this args = params } // 如果已有延迟执行函数(later),调用的时候清除原来的并重新设定一个 // 这样做延迟函数会重新计时 } else { clearTimeout(timer) timer = later() } }} 如何实现节流12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455_.throttle = function(func, wait, options) { var context, args, result; var timeout = null; // 之前的时间戳 var previous = 0; // 如果 options 没传则设为空对象 if (!options) options = {}; // 定时器回调函数 var later = function() { // 如果设置了 leading,就将 previous 设为 0 // 用于下面函数的第一个 if 判断 previous = options.leading === false ? 0 : _.now(); // 置空一是为了防止内存泄漏,二是为了下面的定时器判断 timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { // 获得当前时间戳 var now = _.now(); // 首次进入前者肯定为 true // 如果需要第一次不执行函数 // 就将上次时间戳设为当前的 // 这样在接下来计算 remaining 的值时会大于0 if (!previous && options.leading === false) previous = now; // 计算剩余时间 var remaining = wait - (now - previous); context = this; args = arguments; // 如果当前调用已经大于上次调用时间 + wait // 或者用户手动调了时间 // 如果设置了 trailing,只会进入这个条件 // 如果没有设置 leading,那么第一次会进入这个条件 // 还有一点,你可能会觉得开启了定时器那么应该不会进入这个 if 条件了 // 其实还是会进入的,因为定时器的延时 // 并不是准确的时间,很可能你设置了2秒 // 但是他需要2.2秒才触发,这时候就会进入这个条件 if (remaining <= 0 || remaining > wait) { // 如果存在定时器就清理掉否则会调用二次回调 if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { // 判断是否设置了定时器和 trailing // 没有的话就开启一个定时器 // 并且不能不能同时设置 leading 和 trailing timeout = setTimeout(later, remaining); } return result; }; };","categories":[],"tags":[{"name":"javascript基础","slug":"javascript基础","permalink":"http://yoursite.com/tags/javascript基础/"}]},{"title":"浅拷贝和深拷贝","slug":"浅拷贝和深拷贝","date":"2019-01-17T03:06:39.000Z","updated":"2019-01-17T03:56:02.301Z","comments":true,"path":"2019/01/17/浅拷贝和深拷贝/","link":"","permalink":"http://yoursite.com/2019/01/17/浅拷贝和深拷贝/","excerpt":"","text":"什么是浅拷贝?什么是深拷贝?首先介绍一下浅拷贝:在javascript的实际运用中经常会出现以下问题:有一个对象,我们将其值赋给了另一个对象,如下:12345let Obj = { name:'james', age:18,}let Obj2 = Obj; 看起来没什么问题,但是当我们对Obj进行改动的时候Obj2也会对应的进行改变,在一些业务逻辑中我们常常会需要解决这样的问题,于是出现了浅拷贝 但是浅拷贝也不是万能的例如遇到如下情况: 123456789let Obj = { name:'james', age:18, todo:{ wash:'room', eat:'dinner' }}let Obj2 = Obj; 这个时候浅拷贝就不是可靠的了,当我们改动浅拷贝后的Obj2中的todo属性,会发现Obj会相应的改变,这个时候就需要深拷贝了即当对象内还有属性是对象时,对其进行深拷贝才能解决刚才的问题 如何浅拷贝1.使用Object.assign来解决这个问题。123456let Obj = { name:'james', age:18,}let Obj1 = Object.assign({},Obj);let Obj2 = Obj1; 2.使用es6的展开运算符(…)来解决问题.12345let Obj = { name:'james', age:18,}let Obj2 = ...Obj1; 如何深拷贝通常可以用JSON.parse(JSON.stringify(object))来解决这个问题 123456789let Obj = { name:'james', age:18, todo:{ wash:'room', eat:'dinner' }}let Obj2 = JSON.parse(JSON.stringify(Obj)); 该方法虽然简便,但是有弊端1.会忽略 undefined2.会忽略 symbol3.不能序列化函数4.不能解决循环引用的对象 遇到以上情况时,就可以使用其他的方法,因为上面方法是最简便的,所以一般优先考虑上一个方法 其他的深拷贝方法原理一般是半递归(我本人自己的说辞) 例如 使用for-in解决此问题1234567891011121314151617181920212223242526272829let Obj = { name:'james', age:18, todo:{ wash:'room', eat:'dinner' }}function deepclone(Obj){ function isObject(Obj){if(typeof(Obj)=='Object'){ return true;}else{ return false;} } if(!isObject(Obj)){return '你输入的不是一个对象' }let newObj = {};for(key in Obj){newObj[key]=isObject(Obj[key])?deepclone(Obj[key]):Obj[key];}return newObj} 可以看出,函数内会遍历对象属性并且判断处理后给新对象赋值,如果判断出某个属性的值是对象则遍历该函数一次,所以我称其为半遍历。","categories":[],"tags":[{"name":"javascript基础","slug":"javascript基础","permalink":"http://yoursite.com/tags/javascript基础/"}]},{"title":"javascript原型和原型链","slug":"javascript原型和原型链","date":"2019-01-17T01:43:21.000Z","updated":"2019-01-17T02:55:22.336Z","comments":true,"path":"2019/01/17/javascript原型和原型链/","link":"","permalink":"http://yoursite.com/2019/01/17/javascript原型和原型链/","excerpt":"","text":"首先先看一张图: 原型链 原型链是什么?原型是什么?在我的理解中,原型链是javascript的一种语言机制所产生的内部结构,这种内部结构不仅实现了内部的一些方法和属性的继承,而且明确了构造函数和实例的关系,同时它也带来了一些不必要的麻烦,原型则是用于实现原型链的中间产物,而作为一个经常与javascript打交道的前端工程师来说,理解其特性的运用和原理是必不可少的。 原型链的规则作为一种语言的内部机制,自然有自己的一套内部准则,我把它归纳为以下几点: 1、每一个构造函数都有自己的prototype(显式原型)属性,指向一个普通对象2、每一个实例都有自己的proto(隐式原型)属性,指向内部的[[proto]],最终也指向其构造函数的prototype.3、原型也可以拥有自己的属性,可以用自己的constractor属性指回相应的构造函数 这三条规则规定了原型链的运作规则 鸡生蛋?蛋生鸡?不过若是细心的话,可以发现上面的图里面还有一个function.prototype,那是因为所有的函数都是由Function构造函数所创建的实例,而奇怪的是,图中的Function构造函数的proto与prototype所指向的是同一个对象,这就存在疑惑了,难道Function的构造函数是其自身?实际上并不是,javascript环境初始化时,会自动创建Function和Object,并不会存在鸡生蛋,蛋生鸡的问题","categories":[],"tags":[{"name":"javascript基础","slug":"javascript基础","permalink":"http://yoursite.com/tags/javascript基础/"}]},{"title":"诗歌闲谈(一)","slug":"诗歌闲谈(一)","date":"2019-01-16T03:11:36.000Z","updated":"2019-01-16T03:12:40.282Z","comments":true,"path":"2019/01/16/诗歌闲谈(一)/","link":"","permalink":"http://yoursite.com/2019/01/16/诗歌闲谈(一)/","excerpt":"","text":"《闲谈》 ———wintercomming待日月无光华,望朝晚无弥霞。却问,你要去哪? 若心灵而不静,似叶落而不停。但曰,我心空明。 念我心之空悠,点流水之忧愁。话是,人道风流。","categories":[],"tags":[{"name":"诗歌闲谈","slug":"诗歌闲谈","permalink":"http://yoursite.com/tags/诗歌闲谈/"}]},{"title":"动画相关总结","slug":"动画相关总结","date":"2019-01-15T05:01:32.000Z","updated":"2019-01-17T09:12:22.539Z","comments":true,"path":"2019/01/15/动画相关总结/","link":"","permalink":"http://yoursite.com/2019/01/15/动画相关总结/","excerpt":"","text":"CSS动画 随着CSS3和HTML5以及新时代移动端前端时代的来临,CSS3几乎成为了所有前端工程师必备的技能之一,而其中最核心也最常用的新特性之一便是CSS3动画了,这篇文章也是本人对于CSS动画的总结与思考 重绘(repaint)、重排(relayout)与重组(recomposite)首先,我们需要了解重绘(repaint)、重排(relayout)、重组(recomposite)的概念:最常见的区别:document.write:重排整个页面innerHTML:重绘部分页面1.重绘(repaint)重绘定义:完成重排后,浏览器会重新绘制受影响的部分到屏幕,该过程称为重绘 重绘是以上三种方法中消耗性能最高的方式,所以在项目中应该尽量避免重绘,常用的有尽量使用webkit-transform: translateX(3em)的方案代替使用left: 3em ,因为left会触发重排(relayout)与重绘(repaint),而webkit-transform只触发页面重组(recomposite) 当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。 触发重绘的条件:改变元素外观属性。如:color,background-color等。 重排定义:当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。 触发重排的条件:任何页面布局和几何属性的改变都会触发重排,比如: 1、页面渲染初始化;(无法避免) 2、添加或删除可见的DOM元素; 3、元素位置的改变,或者使用动画; 4、元素尺寸的改变——大小,外边距,边框; 5、浏览器窗口尺寸的变化(resize事件发生时); 6、填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变; 7、读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) ) 重排必定会引发重绘,但重绘不一定会引发重排。 requestAnimationFrame这是一个在我印象中并不常用的JavaScript API,之所以放在这里是因为其特殊特性在接下来的时间内值得好好运用 requestAnimationFrame主要用途是按帧对网页进行重绘,即每一帧都刷新一次,提高动画的流畅度 以下是此api的使用及兼容 12345678910window.requestAnimFrame=(function(){ return window.requestAnimationFrame|| window.webkitRequestAnimationFrame|| window.mozRequestAnimationFrame|| window.oRequestAnimationFrame|| window.msRequestAnimationFrame|| function(callback){ window.setTimeout(callback,1000/60) //适应刷新频率为60hz的屏幕 }})(); 上面的函数内最后一个选项是为了兼容ie浏览器所返回的对应的函数,不过此方法有一个缺陷,就是无法适应不同频率的屏幕,无法达到对应屏幕的理想帧数另外值得注意的是,W3C认为requestAnimationFrame是一个宏任务(marcotask),在实际运用中要注意 transition(过渡)动画transition(过渡)是CSS3动画规范内的一种 如:1234567img{ height:100px; trasition: 1s 1s height ease;}img:hover{height:300px;} 也就是说,规定了transition动画的元素上对其样式进行的修改都会变成以动画的形式 transition也有其局限性 1.transition需要事件触发,无法像@keyframe一样自动播放2.transition是一次性的,无法自动重复发生,3.transition只能定义开始状态和结束状态,也就是说,用transition无法创建有多个过渡状态的复杂动画4.一条transition,只能定义一个属性的变化 小技巧:显然,通过以上描述,transition可以归结为制作简单动画的首选,而不负众望,其性能尤其是在移动端上的性能尤为可观,大大提高了用户体验,所以在制作简单动画的过程中尽量使用transition。 使用transition的另一个好处是可以通过js来控制动画,具体可以观看之前在百度IFE上的博文:博文地址 animation动画animation使用@keyframe来定义动画,最后绑定在对应元素的样式上来产生效果,如: 123456789101112131415161718@keyframe move{ 0% { width:200px; } 50% { width:100px; } 100%{ width:200px; }}div{ width:100px;}div:hover{ animation:1s move} animation动画的内容更为丰富,可以用animation-delay规定动画何时开始,animation-iteration-count规定动画播放次数,animation-play-state规定动画当前应该状态","categories":[],"tags":[{"name":"CSS","slug":"CSS","permalink":"http://yoursite.com/tags/CSS/"}]},{"title":"javascript的执行上下文与执行机制","slug":"javascript的执行上下文与执行机制","date":"2019-01-15T04:11:08.000Z","updated":"2019-01-17T03:00:27.928Z","comments":true,"path":"2019/01/15/javascript的执行上下文与执行机制/","link":"","permalink":"http://yoursite.com/2019/01/15/javascript的执行上下文与执行机制/","excerpt":"","text":"关于这个系列 javascript语言有很多奥秘,譬如其运行机制,内部原理,在历史的这一段日子里,它不仅带来了复杂的交互效果和充分的性能效益,而且吸引了越来越多的开发者加入其中,但是随着时间进程的发展,很多时候开发者们因为花样繁复的JS库与框架而忽略了JS本身的内部机制。无可厚非,这样做是增加了效率,但是随着Web的蓬勃发展和JS社区的踊跃贡献,JS的思想和创造年年翻新,现有的一切被淘汰也是时间的问题。所以开发者花费时间去研究其语言的内部机制是一个不被社会洪流淘汰的最佳选择,而本系列恰好记录了本人对于JS的理解和思考,会陆续将所学更新于此,希望对大家有所帮助。 受水平和技术有限,灵感和部分例子来自于Github里《JavaScript开发者应懂的33个概念》系列集合,有兴趣的可以在github里面找到这个合集查看完整的讲解。 执行上下文 这是一个很难具体阐述的概念,而且绕口的文字也让很多人费解,我也很难阐述他究竟是个什么东西,为什么取了个这样的名字,但是我认为执行上下文就是javascript所运行的整个环境,它将整个js文件的一些段落或某一个段落包裹起来,分别执行,可以把它理解为某一段代码是在怎么样的一个地方去执行的,如果感觉非常费解,其实你可以把整个js文件比喻成一个房屋,房屋里面拥有着不同的居住环境,不信你可以看看执行上下文的种类在房屋内充当了什么样的位置: 1.全局执行上下文 全局执行上下文就是属于最外层的上下文,简单的说就是除了函数里面的上下文,初始化全局执行上下文的时候它会做两件事情,会创建一个window对象,并且把this指向window对象,整个全局环境都属于全局执行上下文的环境,怎么去理解呢?想象一下刚刚上面我所说的房屋,对于整个JS文件而言他就是整个房屋,而全局执行上下文就好像人所能够移动的区域,客厅,厨房和饭厅就像一段段代码,我们的浏览器或者node环境也就是查房员,他负责查房后汇报房间里拥有什么东西,直到从门口开始把每一个房间都走完。 2.函数执行上下文 函数执行上下文就是全局执行上下文所不能执行的地方,它往往存在与函数内部,全局在遇到这种环境时会避开它,就好像房间里的鱼缸,鸟窝,它们都是鱼和鸟活动的区域,在调用整个函数时,查房人就会往里面放上相应的动物,直到它们把整个环境走完以后再取出来,这些动物不仅有自己的语言,行为和动作,而鸟笼,鱼缸,狗窝它们大小也不一,当关上门时它们的世界就和整个房屋隔绝了开来,我们称这一些地方叫做函数执行上下文。 3.eval函数上下文 eval函数会将一段字符串当做JS代码来执行,而它自己也有属于自己的上下文,这就好像一个便携帐篷,在需要的时候把它在房屋里面打开,拥有了属于自己内部的区域; 执行栈 刚刚说了执行上下文的概念,但是不少人会注意到有一个缺陷,就是我们如何把鱼放入鱼缸,鸟放入鸟窝跑一个遍呢?或者说我鱼缸里面的虾窝,狗窝毛毯上的跳蚤窝又是怎么去查看的呢?其实这就引入了我们执行栈的概念;而管理员就是通过这个东西把它们放入对应的地方汇报信息的。 要搞懂执行栈,首先要理解栈是一个什么东西,有人会说栈是一种基本数据结构,先入先出,但本人就经常把队列和栈搞混(可能比较愚笨),但是笨有笨的方法,我可以想象,我把栈看成是军队训练时要爬的人墙,每次要爬山墙的人都是最后一个进入人墙,但是确实最先一个离开人墙,执行栈也是一样,全局执行上下文就相当于栈的底部,而每次执行到某个函数,其内部的函数上下文就会跳到全局的身上,执行完成便翻过这道墙,当然函数上下文里面的函数执行也是一样,他会跳到上一个函数上下文上边,这就形成了一个FQ的机制直到整个墙翻完为止。 对于常理来说,是这样,但是总有一些奇怪的人,想自己组成一个小团队,他们为了不影响别人,决定在大部队翻过墙以后再自己FQ,这些小团队有可能是一个人也有可能是几个人,而这就牵扯到了JS的异步 异步 异步是一个特殊的概念,在javascript中,整个语言的执行是单线程的,就是一次只能够做一次事情,而一些特殊的事情为了不影响其他事情的执行他们选择等待,当其他事情执行结束时他再去执行自己,一切都是这么的规范和有理,和现实中的混乱相距甚远; 而这一批有礼貌的事情是哪一些呢? 1.setTimeout 2.promise 3.事件绑定 4.ajax 5.回调函数 他们都很有礼貌,每次都会等到执行完成后再去执行自身,至少我之前是这么认为的; 慢慢的和他们相处长了以后,我发现,有一些伪君子,他们虽然也在最后执行,但是他们会插到所有有礼貌的人最前面,也就是说,他们在所有异步的成员里面首先执行,而这就牵扯到了微任务和宏任务的问题了 而微任务就是这一批伪君子,这使我不得不介绍一下他们: micro-task(微任务):Promise,process.nextTick,Object.observe 下面这张图是从掘金《这一次,彻底弄懂 JavaScript 执行机制》一文中copy所得,方便大家理解微任务和宏任务 此文到这里就结束了,相信大家也初步理解了机制,很多东西需要代码才能辅助理解,代码我会在之后补上,先告一段落","categories":[],"tags":[{"name":"javascript基础","slug":"javascript基础","permalink":"http://yoursite.com/tags/javascript基础/"}]}]}