前端部分知识总结

javascript/jquery

浏览数:184

2019-5-3

AD:资源代下载服务

乱序 不间断更新

绝大多数写的比较浅显 看个乐子

display:none 和visibility:hidden的区别

display:none
彻底消失
将会隐藏它以及所有的后代元素
占据的空间消失,浏览器不会解析该元素
页面产生回流+重绘

visibility:hidden
视觉消失可以理解为透明度为0
占据的空间仍存在,浏览器仍然会解析该元素
页面产生重绘
visibility具有继承性,父元素设置visibility:hidden,子元素也会继承该属性,当子元素重新设置visibility:visible,元素又会重新显示,而display:none不会

页面的呈现流程&回流&重绘

页面的呈现流程

  1. 浏览器将读取的所有html代码解析,生成一个Dom树 ->dom tree
  2. 浏览器将所有样式解析成样式结构体 ->style rules
  3. Dom数和样式结构体结合生成构建呈现树 render tree ->attachment
  4. 浏览器根据render tree 绘制页面

some tips

  • 在解析样式结构体的过程中浏览器会去除不能识别的样式(IE去掉-moz开头的样式,firefox去除_开头的样式)
  • render tree与dom tree区别很大,render tree能够识别样式,且不会包含隐藏的节点(display:none),visibility:hidden仍会包含在render tree内。在render tree中,每一个节点被称为box

回流&重绘

回流:render tree中部分(全部)元素的规模尺寸布局等改变而需要重新构建页面。
重绘:render tree中一些元素需要更新属性,但这些属性只影响元素的外观、风格而不引起布局的改变

在解析样式结构体的过程中浏览器会去除不能识别的样式
回流必将引起重绘,重绘不一定引起回流
参考文档:关于呈现、回流、重绘

get请求和post请求

get:通过查询字符串的方式来进行传递

用于获取少量信息(单次运输量不大于64k),使用url传递参数->很不安全

post:通过表单的方式传递

用于修改服务器的资源,无信息量限制,采用请求体承载的方式,不易暴露
    

本质上同根同源
get&post 都是http协议中用于发送请求的方法,而http是基于tcp/ip的关于数据如何在万维网通信的协议
如何理解?
TCP->汽车 HTTP->交通规则 浏览器->运输公司
get->将货物放在车顶上(url) ,只产生一个数据包
post->将货物放在车厢里 , 产生header+body两个数据包

post产生两个数据包,先发送header确认后再发送body,然而并不是所有浏览器都在post中发两次包,如firefox就只发一次

域名的组成

http://    www.baidu.com    :8080    /dir/other.html
协议        主机名            端口     文件路径 参数 文件片段



transition和transform

transform
对元素进行移动、缩放、转动、拉长或拉伸
方法:
translate():元素从当前位置移动根据给定的top left 坐标移动

transform:tanslate(50px,30px)    

rotate():元素顺时针旋转给定的角度,负值->逆时针旋转

transform:rotata(20deg)

scale():根据给定的XY轴参数、元素的尺寸会增加或减少(拉伸、收缩)

transform:scale(1.2,0.8)

skew():翻转

transform:skew(20deg, 20deg);
//围绕 X 轴把元素翻转20度,围绕 Y 轴翻转20度

transition过渡
元素从一种样式逐渐变为另一种样式,属于一种简单的动画属性
四个属性:
transition-property: 过渡属性的样式(默认值为all)
transition-duration: 过渡持续时间(默认值为0s)必须值
transiton-timing-function: 过渡函数(默认值为ease函数)
transition-delay: 过渡延迟时间(默认值为0s)

div{
width:100px;
transition: width 1s;
//时长为一秒的宽度变化效果
}
div:hover{
width:500px;
}

参考:深入理解trasition
参考:transition和transform

虚拟DOM

为什么用虚拟dom?
生成页面时,浏览器从构建DOM树开始从到到尾执行一遍流程。比如在一次操作时,需要更新10个DOM节点,理想状态是一次性构建完DOM树,再执行后续操作。但是浏览器并不会这么做,收到第一个更新DOM请求后会马上执行流程,因此需要执行10次。频繁的操作会引起页面卡顿。真实的DOM节点,哪怕最简单的一个div也会包含很多属性

虚拟DOM干什么?
如一次操作有10个更新DOM的动作,虚拟DOM不会立刻操作DOM,而是将10次更新的diff内容保存到一个本地的js对象中,最终将js对象一次行attach到DOM树上,避免了大量的无谓计算量

虚拟的DOM的核心思想:对复杂的文档DOM结构,提供一种方便的工具,进行最小化地DOM操作

React的生命周期

三个状态:装配 更新 卸载

初始化渲染:
constructor()构造函数

componentWillMount组件将要加载(17版本弃用,在这里请求异步数据,render可能不会渲染到,因为componentWillMount执行后,render立马执行)
整个生命周期只调用一次(组件更新不再调用)

render()渲染方法

componentDidMount 组件已经加载
整个生命周期只调用一次(组件更新不再调用)
↑在这里可以异步请求数据,在这里设置状态会触发重新渲染,但是不推荐使用setstate函数,会触发额外一次渲染,且在浏览器刷新屏幕之前执行,会导致性能问题

更新:
共有五个环节(不同的情况有不同的执行步骤)

1.componentWillReceiveProps(nextprops获取更新状态以及相应的组件状态,组件将要接收参数

2.shouldComponentUpdate(nextprops,nextstate)根据下一个props和state决定组件是否应该更新
↑immutable data在此使用immutable是一旦创建,就不能再被更改的数据

3.componentWillUpdate()组件将要更新 做准备工作(定时、网络请求等)
在这里可以更改state 但是不能使用setState函数 会引起函数调用componentshouldupdate从而进入死循环
4.render()渲染

getSnapshotBeforeUpdate(nextprops,nextstate)在更新前截图//不会用

5.componentDidUpdate() 组件已经更新完毕
可以在这里获取DOM

卸载
只有一个步骤,因为卸载后将失去控制能力
componentWillUnmount()组件将要卸载
在这里清除一些不需要的监听和计时器

三种模式下的执行步骤:

  1. 父组件带动子组件更新 -> 12345
  2. setState() 跳过componentWillReceiveProps() ->2345
  3. forceUpdate()强制更新 跳过shouldComponentUpdate()无需判读->345

defaultProps()
设定默认props 在组件没有被传入时生效,避免报错
propTypes 类型检查

import PropTypes from 'prop-types'.//结合第三方prop-types库
static propTypes = {
    title:PropTypes.string
}

原型&原型链

原型是JavaScript中继承的基础,JavaScript的继承就是基于原型的继承

什么是原型?
我们创建的每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象可以包含由特定类型的所有实例共享的属性和方法。而prototype就是通过调用构造函数创建的对象实例的原型对象

原型所指的就是一个对象,实例继承对象的属性。在原型上定义的属性,通过继承,实例也拥有了这个属性
实例通过_proto_这个属性直接访问到原型

function Person(){
Person.prototype.type   = 'object named Person';
person = new Person();
person._proto_ === Person.prototype;//两者等价

}

构造函数->prototype->访问原型
原型->constructor->访问构造函数

使用原型的好处:
可以让对象的实例共享它所包含的属性和方法,不必在构造函数中添加定义对象信息,而是可以将这些信息添加到原型中(如果使用构造函数就要让每个方法都在实例中创建一遍)

constructor是原型的一个属性,Constructor是真正的构造函数

什么是原型链?
_proto_是实例指向原型对象的一个指针,是任何对象都有的属性,js万物皆对象,所以就形成了一条由_proto_连起来的链条,递归访问到头,终值为null

在读取一个实例的属性时,如果该属性在当前实例没有找到,那么就会循着_proto_指定的原型继续向上找,如果还找不到,则寻找原型的原型,如果一直没有找到,则直到搜索到null为止

原型继承

Son.prototype = new Father();//Son继承了Father,通过原型,形成链条

参考文章:原型
参考文章:原型链

函数提升与变量提升的优先级

变量提升
ES6之前没有块级作用域,只有全局作用域和局部作用域,变量提升就是将变量声明提升到它所在作用域的最开始的部分

函数提升
创建函数有两种形式:函数声明和函数字面量,只有函数声明有变量提升

console.log(a)  // f a() { console.log(a) }
console.log(b) //undefined,不存在函数提升
    
function a() {
        console.log(a) 
}

var b = function(){
        console.log(b)
}

函数提升与变量提升的优先级
函数提升要比变量提升的优先级要高一些,且不会被变量声明覆盖,但是会被变量赋值之后覆盖。

console.log(a);    // f a() {console.log(10)}
console.log(a());    //  undefined
var a = 3;

function a() {
        console.log(10) //10
}
console.log(a)   //3
a = 6;
console.log(a());  //a is not a function;

正常的执行顺序

 var a = funtion () {
        console.log(10)
    }
    var a;
    console.log(a);    // f a() {console.log(10)}
    console.log(a());  //  undefined

    a = 3;
    console.log(a)   //3
    a = 6;
    console.log(a());   //a() is not a function;

参考文章

JS处理异步的几种方式

  1. 事件监听
    onclick方法、addEventlistener、attachEvent(不支持ie,执行顺序3-2-1)
  1. setTimeout超时调用
    setInterval间歇调用,按照指定的时间间隔反复执行任务代码
  2. generator 能够多次返回的“函数”
    每执行一次后就暂停,返回的值就是yield的返回值,每次返回一个值,直到done为true,这个generate对象已经全部执行完毕
  3. promise
    三种状态:等待(pengding) 成功(resolved) 失败(rejected)
  4. async/await
    一种特殊的语法,可以更舒适地与promise协同工作
    async放置在一个函数前面,使函数总是返回一个promise,即使其中包含非promise(会自动将返回值包装成promise的resolved值)
    await只能使用在async内,能够使JavaScript等待,直到promise处理结束
    1.如果它是一个错误,异常就产生了,就像在那个地方调用了throw error一样。
    2.否则,它会返回一个结果,我们可以将它分配给一个值

    参考

  5. 观察者模式
    publish()/subscribe
    又称为发布、订阅模式
    某个任务执行完毕,则向信号中心发布一个信号,其他任务可以向信号中心订阅该信号,从而知道何时执行自己的任务
//f2()
 jQuery.subscribe("done", f2);
//f1()
function f1(){

    setTimeout(function () {

      // f1的任务代码

      jQuery.publish("done");

    }, 1000);

  }

//f2执行完毕后可以取消订阅
  jQuery.unsubscribe("done", f2);

该方法优于事件监听,可以通过查看消息中心了解现在有多少信号、订阅者,从而监控程序的执行状态
参考文档

回调函数的优劣

优点:容易理解和部署
缺点:不利于代码阅读、维护,各个部分耦合性很高,流程混乱,且每个任务只能指定一个回调函数

跨域及跨域的方式

什么是跨域:
浏览器不能执行其他网站的脚本,由浏览器的同源策略造成,是浏览器对JavaScript施加的安全限制
判读是同域:
相同域名,端口相同,协议相同

Jsonp:
Json with Padding,为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。

Jsonp的产生:
ajax直接请求普通文件存在跨域无权限访问的问题,而web页面调用js时不受跨域影响,凡是带有src属性标签的都拥有跨域能力->在远程服务器上把数据装进js格式的文件里,可以实现跨域访问
JSON的纯字符数据格式可以简洁的描述复杂的程序,JSON还被原生js支持
所以,web客户端调用跨域服务器生成的js文件(JSON),便获得了自己想要的数据

Jsonp原理
利用script标签没有跨域限制的“漏洞”达到和第三方通讯的目的
首先在客户端注册一个回调函数,然后把回调函数的名字传给服务器,这时服务器生成json数据,以JavaScript的方式生成function,将jasonp以入参的方式放到function里,生成JavaScript文档,返回给客户端,浏览器解析这个script,执行JavaScript文档,此时数据作为参数传入了客户端之前定义的回调函数里。

jsonp是请求之后后台包装好一段json,并且把数据放在一个callback函数,返回一个js文件,动态引入这个文件,下载完成js之后,会去调用这个callback,通过这样访问数据
json 是一种数据格式,jsonp 是一种数据调用的方式,带callback的json就是jsonp

跨域的几种方法

  1. Jsonp
    优点:不受同源策略限制,兼容性好,低版本的浏览器也可以运行,在请求完毕后可以通过调用callback的方式回传结果。
    缺点:只支持get请求不支持post请求,只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
  2. document.domain跨域
    前提条件:
    这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域.
    方法:
    需要在a.html里与b.html里都加入:document.domain = “xxx.com”;
  3. HTML5的postMessage方法跨域
    高级浏览器Internet Explorer 8+, chrome,Firefox , Opera 和 Safari 都将支持这个功能。这个功能主要包括接受信息的”message”事件和发送消息的”postMessage”方法。
    比如damonare.cn域的A页面通过iframe嵌入了一个google.com域的B页面,可以通过以下方法实现A和B的通信
  4. CORS跨域
    基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。
    对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
    更适用于现代浏览器

参考文档

函数柯里化

把能够接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下参数而且返回结果的函数技术

柯里化是指这样一个函数(假设叫做createCurry),他接收函数A作为参数,运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数。

函数柯里化(function currying)又称部分求值。一个currying的函数首先会接受一些参数,接受了这些参数后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包里被保存起来。待到函数真正需要求值的时候,之前传入的参数都会被一次性用于求值。

Q:函数经过createCurry转化为一个柯里化函数,最后执行的结果,不是正好相当于执行函数自身吗?柯里化是不是把简单的问题复杂化了?

好处:
1.参数复用
2.提前返回
3.延时执行

参考文档
参考文档,高阶

模块化、CommonJs

对模块化的理解
功能封装,针对Javascript代码,隔离、组织复制的javascript代码,将它封装成一个个具有特定功能的的模块。
模块可以通过传递参数的不同修改这个功能的的相关配置,每个模块都是一个单独的作用域,根据需要调用。
模块化就是为了减少系统耦合度,提高内聚性,减少资源循环依赖,增强系统框架设计。
CommonJs
它的终极目标是提供一个类似Python,Ruby和Java标准库。这样的话,开发者可以使用CommonJS API编写应用程序,然后这些应用可以运行在不同的JavaScript解释器和不同的主机环境中。
CommonJs的特点:

  1. 所有代码都运行在模块作用域,不会污染全局作用域。
  2. 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  3. 模块加载的顺序,按照其在代码中出现的顺序。

AMD规范和commonJS规范
1.相同点:都是为了模块化。
2.不同点:AMD规范则是非同步加载模块,允许指定回调函数。CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
参考文档

情景题,加载图片

  • 懒加载

    利用jQuery实现图片懒加载的原理。它的基本思想是:在输出HTML的时候,不要直接输出<img src=”xxx”,而是输出如下的img标签:

<img src="/static/loading.gif" data-src="http://真正的图片地址/xxx.jpg">
监听scroll事件,调用目标元素(绿色方块)的getBoundingClientRect()方法,得到它对应于视口左上角的坐标,再判断是否在视口之内。这种方法的缺点是,由于scroll事件密集发生,计算量很大,容易造成性能问题。

参考:JQuery实现

使用IntersectionObserve(callback,option) api监听图片素到视口的距离判断是否加载图片,实现懒加载
callback一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。
参考

有些事件(resize Mousemove scroll)几乎是不间断触发的,如果存在复杂的函数方法,非常影响性能,所以需要函数节流

  • 函数节流

    函数节流的基本思想是设置一个定时器,在指定时间间隔内运行代码时清除上一次的定时器,并设置另一个定时器,直到函数请求停止并超过时间间隔才会执行。
    一个函数执行一次后,只有大于设定的执行周期后才会执行第二次

  • 防抖
    函数调用n秒后才会执行,如果函数在n秒内被调用的话则函数不执行,重新计算执行时间

函数的节流和函数的去抖都是通过减少实际逻辑处理过程的执行来提高事件处理函数运行性能的手段,并没有实质上减少事件的触发次数。

节流和防抖的区别
函数节流是指一定时间内js方法只跑一次。
比如人的眨眼睛,就是一定时间内眨一次。这是函数节流最形象的解释。
函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。
比如生活中的坐公交,就是一定时间内,如果有人陆续刷卡上车,司机就不会开车。只有别人没刷卡了,司机才开车。

代码实现
节流
声明一个变量为标志位,当这个变量为true的时候,代表现在的滚动处理事件是空闲的,可以使用。直接return并将变量设为false这样,其他请求执行滚动事件的方法,就被挡回去了。然后用settimeout规定时间间隔,再执行定时函数内的代码,执行完毕将变量重新设为true
防抖
也需要一个settimeout辅助,延迟执行需要跑的代码
如果方法多次触发,则把上次记录的延迟执行代码用clearTimeout清掉,重新开始。
如果计时完毕,没有方法进来访问触发,则执行代码。
 函数防抖的实现重点,就是巧用setTimeout做缓存池,而且可以轻易地清除待执行的代码。clearTimeout(timer)
参考

react父组件更新,子组件更新问题

只要父组件的render了,那么默认情况下就会触发子组件的render过程,子组件的render过程又会触发它的子组件的render过程,一直到React元素(即jsx中的<div>这样的元素)。当render过程到了叶子节点,即React元素的时候,diff过程便开始了,这时候diff算法会决定是否切实更新DOM元素。
React不能检测到你是否给子组件传了属性,所以它必须进行这个重渲染过程(术语叫做reconciliation)
链接描述

let&const

let、const、var的区别
var:可以跨块级作用域访问,不能跨函数作用域访问
let:只能在块级作用域访问,不能跨函数使用
const:定义常量,必须初始化且不能修改,只能在块级作用域内使用
关于变量提升:var不论声明在何处都会莫默认提升到函数/全局最顶部,但是let和const不会进行变量提升

promise.all()和promise.race() 的区别

async await实现sleep

function sleep(ms){
  return new Promise((resolve)=>setTimeout(resolve,ms));
}
async function test(){
  var temple=await sleep(1000);
  console.log(1111)
  return temple
}
test();
//延迟1000ms输出了1111

async/await相对于promise的优势

  1. 代码更加简洁,能够更好的处理then链
    不必编写.then,不必创建一个匿名函数来处理响应,不必将命名数据传递给我们不需要使用的变量。我们也避免了嵌套代码。
  2. 更好的处理中间值
    比如说time1 time2 time3 ,promise传递参数很麻烦,而用async/await就不需要多余的中间值
  3. 更易于调试

promise因为没有代码块,所以不能在一个返回的箭头函数中设置断点。如果你在一个 .then 代码块中使用调试器的步进(step-over)功能,调试器并不会进入后续的 .then 代码块,因为调试器只能跟踪同步代码的每一步。
使用 async/await,你就不必再使用箭头函数。你可以对 await 语句执行步进操作

参考

diff算法

传统算法就是对每个节点一一对比,循环遍历所有的子节点,然后判断子节点的更新状态,分别为remove、add、change。如果before的子节点仍有子节点依旧顺次执行。

参考
参考

flex弹性布局

主要思想是给予容器控制内部元素高度和宽度的能力

主轴main axis 纵轴 cross axis
1点:

        display: flex;
        justify-content: center;
        align-items:center;

2点:竖列布局且在主轴方向采用justify-content的两端对齐布局,这样两个圆点会在左边呈现,然后采用align-items让其居中

        display: flex;
        flex-direction: column;//垂直显示
        justify-content: space-between;
        align-items:center;

3点:用到align-self属性让第二个和第三个圆点有自己的属性设置,分别在纵轴方向上居中和低端对齐

    .item:nth-child(2){
        align-self:center;
    }
    .item:nth-child(3){
        align-self:flex-end;
    }

五点布局
思路:先竖着放两行圆点,每行圆点里横着放两个圆点,所以最外层父元素设置align,里面的父元素设置justify-content形成4点
让圆点(即子元素)在横轴上居中在竖轴上居中,分别用justify-content和align-items形成1点

        display: flex;
        flex-wrap:wrap;//必要时拆行显示
        align-content:space-between;//各行在弹性盒容器中平均分布
    .column{
        flex-basis:100%;
        display:flex;
        justify-content: space-between;
    }

6点:
跟四点的一样,先竖放三行在每行横放两个圆点

实现骰子布局

雪碧图

一个网页可能有许多的小图标,访问时会发送很多次的请求,造成资源浪费、访问速度变慢。可以使用一张图片来代替小图标,按一定的距离排开
前提条件
需要一个宽和高设置好的容器
需要设置background-position的值(默认为(0,0),也就是图片的左上角),即移动图片到自己想要的图标位置。

用css Gaga 自动生成雪碧图

css代码为:background-position:-xpx -ypx;

前端攻防

1.XSS攻击:
跨站脚本攻击指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入的恶意html代码会被执行,对受害用户可能采取Cookie资料窃取、会话劫持、钓鱼欺骗等各种攻击。
预防方法:

  • 设计xss Filter,分析用户提交的输入,并消除潜在的跨站脚本攻击、恶意的HTML等。在需要html输入的地方对html标签及一些特殊字符( ”
    < > & 等等 )做过滤,将其转化为不被浏览器解释执行的字符。
  • 前端防御组件:js-xss

2.CSRF跨站点伪造请求
攻击者通过各种方法伪造一个请求,模仿用户提交表单的行为,从而达到修改用户的数据,或者执行特定任务的目的。
解决方法:

  • 采用POST请求,增加攻击的难度.用户点击一个链接就可以发起GET类型的请求。而POST请求相对比较难,攻击者往往需要借助javascript才能实现。
  • 对请求进行认证,确保该请求确实是用户本人填写表单并提交的,而不是第三者伪造的.具体可以在会话中增加token,确保看到信息和提交信息的是同一个人。(验证码)

3.Http Heads攻击
HTTP协议在Response header和content之间,有一个空行,即两组CRLF(0x0D 0A)字符。这个空行标志着headers的结束和content的开始。“聪明”的攻击者可以利用这一点。只要攻击者有办法将任意字符“注入”到headers中,这种攻击就可以发生。

解决办法:
服务器一般会限制request headers的大小。例如Apache server默认限制request header为8K。如果超过8K,Aapche Server将会返回400 Bad Request响应。
对于大多数情况,8K是足够大的。假设应用程序把用户输入的某内容保存在cookie中,就有可能超过8K.攻击者把超过8k的header链接发给受害者,就会被服务器拒绝访问.解决办法就是检查cookie的大小,限制新cookie的总大写,减少因header过大而产生的拒绝访问攻击
参考

闭包
垂直居中实现

redux原理

Javascript全局函数

JS的内置对象

作者:李默