admin管理员组

文章数量:1547228

Html/Css

行内元素/块级元素,非替换元素/替换元素

  1. 块级元素,会独占一行,默认情况下,其宽度自动填满其父元素宽度。块级元素可以设置width,height属性,即使设置了宽度,仍然是独占一行。可以设置margin和padding属性。块级元素对应于display:block。块级元素可以包含块级元素和行内元素。
  2. 行内元素,不会独占一行,相邻的行内元素会排列在同一行里,直到一行排不下,才会换行。行内元素设置width,height属性都无效,它的长度高度主要根据内容决定。行内元素的margin和padding在水平方向会产生边距效果,但竖直方向的却不会产生边距效果。行内元素只能包含行内元素
  3. 替换元素,浏览器根据元素的标签和属性,来决定元素的具体显示内容。例如浏览器会根据 <img>标签的 src 属性的值来读取图片信息并显示出来,而如果查看 HTML 代码,则看不到图片的实际内容;又例如根据 <input>标签的 type 属性来决定是显示输入框,还是单选按钮等。
    <img> 、<input>、<textarea> 、<select> 、<object> 都是替换元素。
  4. 不可替换元素,HTML 的大多数元素是不可替换元素,即其内容直接表现给用户端(例如浏览器)。例如:<p>段落的内容</p>是一个不可替换元素,文字「段落的内容」全被显示。

<img>标签的title和alt属性

  alt属性和title属性的区别是前者是在图片无法加载的时候才会显示的其值,而title是在图片正常加载鼠标划上去显示的值,虽然alt也有后者的功能,但只是在低版本的ie浏览器才支持,高版本及标准浏览器不支持这个功能了。

DOCTYPE 标签

  <!DOCTYPE> 声明必须位于HTML5文档中的第一行。该标签告知浏览器html文档所使用的规范。doctype 声明不属于 HTML 标签。严格模式的排版和 JS 运作模式是以该浏览器支持的最高标准运行。DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现。在混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。

link 和 @import

  1. link属于XHTML标签,除了加载CSS外,还能用于定义RSS,定义rel连接属性等作用;而@import是CSS提供的,只能用于加载 CSS。
  2. 加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。
  3. @import 是 CSS2.1 提出的,只在 IE5 以上才能被识别,而 link 是 XHTML 标签,无兼容问题。
  4. link 支持使用 JS 控制 DOM 去改变样式,而 @import 不支持。link最大限度支持并行下载,@import过多嵌套导致串行下载,会使文档样式短暂失效。

script标签的defer和async

  script 标签有2个属性 async(异步) 和 defer(推迟)。
9. async:异步加载,不确定何时会加载好;页面加载时,带有 async 的脚本也同时加载,加载完成后会立即执行,如果有一些需要操作 DOM 的脚本加载比较快时,这样会造成 DOM 还没有加载好,脚本就进行操作,会造成错误。
10. defer:页面加载时,带有defer的脚本也同时加载,加载后会等待页面加载好后,才执行。

实现元素水平垂直居中的方法

  1. 利用定位+margin:auto;
  2. 利用定位+margin:负值;
  3. 利用定位+transform;
  4. table布局;
  5. flex布局;
  6. grid布局;
iframe

  iframe元素会创建包含另外一个文档的内联框架(即行内框架)。<iframe>标签用于指定内联框架。内联框架用于向网页中引入另一个网页。

<iframe  src=“hello.html”  width=“200px”  height=“400px” name="ifra">
</iframe>

<iframe>标签常用属性:

  1. src属性:是在该内联框架中指定一个外部的页面地址;
  2. name属性:是设置iframe的名字

优点:用来加载速度较慢的内容(如广告);可以使脚本并行下载;可以实现跨子域通信;
缺点:iframe标签会阻塞页面的的加载,会阻塞主页面的onload事件;无法被一些搜索引擎索识别;会产生很多页面,不容易管理;iframe的创建比一般的DOM元素慢了1-2个数量级。

BFC

  即块级格式化上下文,它是页面中的一块渲染区域,并且有一套属于自己的渲染规则:

  1. 内部的盒子会在垂直方向上一个接一个的放置;
  2. 对于同一个BFC的俩个相邻盒子的margin会发生重叠,与方向无关。
  3. 每个元素的左外边距与包含块的左边界相接触,即使浮动元素也是如此;
  4. BFC的区域不会与float的元素区域重叠
  5. 计算BFC的高度时,浮动子元素也参与计算;
  6. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素

触发BFC的条件包含不限于:
(1)根元素,即HTML元素;
(2)浮动元素:float值为left、right;
(3)overflow值不为 visible,为 auto、scroll、hidden;
(4)display的值为inline-block、flex、inline-flex、grid、inline-grid等;
(5)position的值为absolute或fixed;
BFC应用在以下场景:防止margin重叠(塌陷);清除内部浮动;自适应多栏布局

清除浮动的方法

(1)给父级盒子添加高度
(2)额外标签法,在浮动元素末尾添加一个空的块级标签。原理:clear:both的作用是不允许周围有浮动现象,所以就可以达到清除浮动的效果。
(3)给父级添加 overflow 属性。overflow:hidden本身的意思是溢出的元素隐藏显示。
(4)给父级添加after伪元素。利用after伪元素定义一个clearfix类,浮动元素的父级元素调用此类可以实现清除浮动的效果。这个方式的原理和额外标签法的方式异曲同工,只是向浮动元素的后面添加了一个块级元素。

position属性

(1)position: relative;相对定位,不会使元素脱离文档流,不影响其他元素的偏移,因此会在此元素未添加定位时所在位置留下空白。提升层级(用z-index样式的值可以改变一个定位元素的层级关系,从而改变元素的覆盖关系,值越大越在上面,z-index只能在position属性值为relative或absolute或fixed的元素上有效。)
(2)position: absolute 绝对定位,使元素完全脱离文档流(在文档流中不再占位),使内联元素在设置宽高的时候支持宽高,使区块元素在未设置宽度时由内容撑开宽度,相对于最近一个有定位的父元素偏移(若其父元素没有定位则逐层上找,直到document——页面文档对象),相对定位一般配合绝对定位使用,提升层级
(3)position: fixed 固定定位,生成固定定位的元素在浏览器中不占位置,相对于浏览器窗口进行定位,不以body为依据。
(4)position:static 默认布局。元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)
(5)position:sticky 粘性定位,该定位基于用户滚动的位置。它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;它会固定在目标位置。

CSS隐藏元素的方式

通过css实现隐藏元素方法有如下:

方法一:display:none

.conceal {display:none} //display:none是通常最实用的隐藏元素的方法
此元素原本所占据的位置,会被其他元素占据,也就是说它会导致浏览器的重排和重绘。消失后,自身绑定的事件不会触发,也不会有过渡效果。特点:元素不可见,不占据空间,无法响应点击事件

方法二:visibility:hidden

visibility:hidden从页面上来看仅仅是隐藏该元素,DOM结果依然会存在,只是处于一个不可见的状态。不会发生重排,但是会发生重绘。特点:元素不可见,占据空间,无法响应点击事件。
.conceal {visibility:hidden }

方法三: opacity:0

opacity属性表示元素的透明度,将元素的透明度设置为0之后,元素也是可以达到隐藏效果。不会引发重排,一般情况下也会引发重绘。注意:其子元素不能设置opacity来达到显示的效果。特点:改变元素透明度,元素不可见,占据页面空间,可以响应点击事件。
.conceal {opacity:0}

方法四:设置height、width模型属性为0

要用这种方法实现隐藏需将元素的margin、border、padding、height和width等影响元素盒模型的属性设置成0,如果元素内有子元素的内容,还要设置其overflow:hidden 来隐藏子元素。元素不可见,不占据空间,无法响应点击事件
.conceal {margin:0;border:0;padding:0;height:0;width:0;overflow:hidden;}

方法五:position:absolute

元素不可见,不影响布局
.conceal { position: absolute;top: -9999px;left: -9999px;}

方法六:clip-path

clip-path 通过裁剪的形式,元素不可见,占据空间,无法响应点击事件
.conceal {clip-path: polygon(0px 0px,0px 0px,0px 0px,0px 0px);}

页面渲染的流程

  解析html绘制DOM树,解析css绘制CSS树,把DOM和CSSOM组合生成render tree(渲染树),在渲染树的基础上进行布局,分析每个节点的几何结构,把每个节点绘制到屏幕上(painting)。

重排和重绘

  DOM发生改变的时候触发重排,使DOM重新排列。重绘不一定会重排,但重排一定会发生重绘,重绘和重排都会耗费浏览器的性能,尽量避免。
重绘是在一个元素的外观被改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。
重排就是重新排列(reflow):当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。

减少重排和重绘

(1)避免一条一条的修改DOM的样式,可以直接修改DOM的className一次性改变属性;
(2)避免把DOM结点的属性值放在一个循环里当成循环里的变量;
(3)给动画的HTML元素使用fixed或absolute的position,那么修改他们的css是不会重排;
(4)避免在大量元素上使用:hover;
(5)分离读写操作;(6)避免使用Table布局;(7)避免设置多层内联样式;(8)避免在布局信息改变时查询布局信息;

CSS Sprites

  CSS Sprites是一种网页图片应用处理方式。它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去。利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position可以用数字精确的定位出背景图片的位置。利用CSS Sprites能很好地减少网页的http请求,从而大大的提高页面的性能,这也是CSS Sprites最大的优点;CSS Sprites能减少图片的字节,曾经比较过多次3张图片合并成1张图片的字节总是小于这3张图片的字节总和。解决了网页设计师在图片命名上的困扰,只需对一张集合的图片命名就可以了,从而提高了网页的制作效率。维护起来更加方便。

px rem em

  px,表示像素,所谓像素就是呈现在我们显示器上的一个个小点,每个像素点都是大小等同的,所以像素作为计量单位被分在了绝对长度单位中。一旦设置了就无法因为适应页面大小而改变。
  em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(1em=16px)。
  rem是相对于根元素。总之em相对于父元素,rem相对于根元素。
vw,就是根据窗口的宽度,分成100等份,100vw就表示满宽,50vw就表示一半宽。同理,vh则为窗口的高度

浏览器内核

Wekbit:Apple的Safari, Google的Chrome。
Gecko:Firefox便是使用的Gecko 内核。Gecko内核是开源的,最大优势是可以跨平台。
Trident内核:微软的IE系列。搜狗浏览器是双核的,双核并不是指一个页面由2个内核同时处理,而是所有网页由webkit内核处理,只有银行网站用IE内核。
Presto内核:代表浏览器是Opera浏览器(中文译为“欧朋浏览器”),Presto 内核是世界公认最快的渲染速度的引擎,但是在 2013 年之后,Open宣布加入谷歌阵营,弃用了该内核。
Blink内核:由谷歌和 Opera 开发,2013 年4月发布,现在 Chrome 内核是Blink。

JavaScript

JavaScript的数据类型

基本数据类型:Number、String、Boolean、Null、Undefined、Symbol、bigInt
引用数据类型:object、Array、Date、Function、RegExp

变量和函数声明的提升

在js中变量和函数的声明会提升到最顶部执行,函数的提升高于变量的提升。函数内部如果用 var 声明了相同名称的外部变量,函数将不再向上寻找。匿名函数不会提升。

判断变量的类型

typeof:判断基本数据类型
instanceof:判断引用数据类型,判断一个实例是否属于某种类型
使用constructor判断变量的类型
使用Object.prototype.toString.call判断变量的类型
使用jquery中$.type判断变量的类型。

数据类型转换

其他数据类型转换为数字型
方法一:Number()
  1. 空字符串转为0,其他任何非有效数字字符都是NaN
    Number('') -> 0 Number('12c') -> NaN
  2. 布尔值转换为数字:true -> 1 , false -> 0
  3. null -> 0 , undefined -> NaN
  4. Symbol无法转换为数字,会报错:Uncaught TypeError: Cannot convert a Symbol value to a number
  5. BigInt去除’n’(超过安全数字的,会按照科学计数法处理) Number(10n) -> 10
方法二:parseInt([val],[radix])
  1. parseInt([val],[radix])
    a. [val]值必须是一个字符串,如果不是先隐式转换为字符串【通过String([val])转换】
    b. [radix]进制
    –如果不写,或者写0:默认是10进制,如果字符串是以0x开始的,默认是16进制
    –有效范围:2~36之间,如果不在这个区间,结果直接是NaN
    从字符串左侧的第一个字符开始寻找,查找出符合[radix]进制的值【遇到不符合的就结束查找,不论后面是否还有符合的】
    parseInt(‘12px13’,2) -> 1
    parseInt(‘10102px13’,2) -> 1010【二进制】 ->10【十进制】
    方法三:parseFloat([val])
    (1) 转换规则如下
    a. [val]必须是一个字符串,如果不是,就要隐式转换为字符串
    b. 然后从字符串左侧的第一个字符串开始寻找,把找到的有效数字字符最后转换为数字【一个都没找到就是NaN】
    c. 遇到一个非有效数字字符,不论后面是否是有效数字字符,都不在查找了
    d. parseFloat可以多识别一个小数点
    例题
    let arr = [27.2,0,‘0013’,‘14px’,123]
    arr = arr.map(parseInt)
    console.log(arr) //[27,NaN,1,1,27]
    // arr.map((item,index){return item*10})方法:迭代数组的每一项,并对其进行修改(原始数组不变,返回新数组)
    // arr.map(parseInt)相当于把parseInt方法作为参数,然后原数组中的item和index作为parseInt方法的参数
    // parseInt(27.2,0) -> parseInt(‘27.2’,10) -> 27【十进制】
    // parseInt(0,1) -> NaN
    // parseInt(‘0013’,2) -> 001【二进制】 -> 1【十进制】
    // parseInt(‘14px’,3) -> 1【3进制】 -> 1【十进制】
    // parseInt(123,4) -> 123【4进制】 -> 27【十进制】
    // parseInt(0013,2) -> parseInt(11,2) -> parseInt(‘11’,2) ->11【二进制】-> 3【十进制】 【先将0013按照8进制转为10进制的数字11】
    // JS遇到以0开始的“数字”,会默认将其按照8进制转为10进制,然后在进行其他操作
  2. 其他数据类型转换为字符串
    方法一:默认使用String([val])方法
    (1) 若val是一个原始值,则转换结果直接包裹括号即可。特殊情况 String({}) //‘[object Object]’
    (2) 若val是一个对象,转换规则如下
    a. 先调用对象的Symbol.toPrimitive方法,
    b. 如果没有Symbol.toPrimitive方法,在调用对象的indexOf,获取原始值
    【每个对象都有indexOf方法,即便它本身没有,但可以通过原型链访问到Object的原型上的indexOf方法】
    【数组的原始值还是数组】
    c. 如果获取的原始值不是基本数据类型,则调用对象的toString方法将其转换为字符串
    方法二:"+"出现字符串拼接的情况
    (1) "+"两边,一边是字符串
    (2) "+"两边,一边是对象
    (3) "+"出现在值的左侧,除了字符串拼接的情况,而且该值会转换为数字
    let i =‘10’
    console.log(+i) //10
    注意:String([val])和val.toString()的结果不一样
    (1) String([val])的结果除了是字符串外,也可以是别的类型;val.toString()的结果只能是字符串
  3. 其他数据类型转换为布尔值
    除0、NaN、空字符串、null、undefined返回的值是false外,其余都是true
  4. ==比较时的相互转换规则
    ==:两边数据类型不同,需要先转换为相同的类型,然后在进行比较
    (1) 对象==字符串,对象转字符串【Symbol.toPrimitive -> valueOf -> toString】
    (2) null == undefined -> true null/undefined和其他任何值都不相同
    null===undefined -> false
    (3) 对象==对象 比较的是内存地址,地址相同则相等
    (4) NaN !==NaN true NaN==NaN false Object.is(NaN,NaN) true
    (5) 除了以上情况,只要两边类型不一致,剩下的都是转换为数字,然后在进行比较
    console.log([] == false) //true 两边都转换为数字
    console.log(![] ==false) //true 先处理![] -> false false == false -> true
    “===”: 如果两边类型不同,直接返回false,不会发生数据类型转换

DOM事件流和事件委托

  DOM事件流包括三个阶段:捕获阶段、目标阶段、冒泡阶段。
首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个是冒泡阶段,在这个阶段对事件做出响应。事件发生时会在元素节点之间按照特定的顺序传播,这个传播的过程就是DOM事件流。简单的说:事件的传播过程即DOM事件流

提高内存和性能 – 事件委托

  对 “事件处理程序过多” 问题的解决方案就是事件委托。事件委托指的是,不在事件的发生地(直接 dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素 DOM 的类型,来做出不同的响应。
  事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一项类型的所有事件。例如,click事件会一直冒泡到window层次。也就是说,我们可以为整个页面指定一个onclick事件,而不必给每个可单击的元素分别添加事件
  举例:最经典的就是 ul 和 li 标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在 li 标签上直接添加,而是在 ul 父元素上添加。 好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制。

Cookie/storage

都是保存在浏览器端,并且是同源的

1、cookie本身用于客户端和服务端通信,但是它有本地存储的功能,于是就被“借用”。

cookie用于存储的缺点:①存储量太小,只有 4kb ②所有 http请求都带着,会影响获取资源的效率
③api简单,需要封装才能用 document.cookie。
Cookie的主要作用:
(1)保存用户登录状态。例如将用户 id 存储于一个 cookie 内,这样当用户下次访问该页面时就不需要重新登录了。
(2)cookie 还可以设置过期时间,当超过时间期限后,cookie 就会自动消失。因此,系统往往可以提示用户保持登录状态的时间:常见选项有一个月、三个月、一年等。
(3)跟踪用户行为。例如一个天气预报网站,能够根据用户选择的地区显示当地的天气情况。 如果每次都需要选择所在地是烦琐的,当利用了 cookie 后就会显得很人性化了,系统能够记住上一次访问的地区,当下次再打开该页面时,它就会自动显示上次用户所在地区的天气情况。因为一切都是在后台完成,所以这样的页面就像为某个用户所定制的一样,使用起来非常方便定制页面。

2、localStorage,sesseionStorage

html5专门为存储而设计,最大容量5M。api简单易用。lcoalStorage.setItem(key,value);localStoragegetItem(key);
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage仅仅是会话级别的存储。而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

map与forEach的区别

(1)forEach()方法不会返回执行结果,而是undefined
(2)map()方法会得到一个新的数组并返回
(3)同样的一组数组,map()的执行速度优于 forEach()(map() 底层做了深度优化)
forEach() 适合于并不打算改变数据的时候,而只是想用数据做一些事情(比如存入数据库)
let arr = [‘a’, ‘b’, ‘c’, ‘d’];
arr.forEach((val) => {console.log(val)}); // 依次打印出 a,b,c,d
map() 适用于要改变数据值的时候,它更快,而且返回一个新的数组
let arr = [1, 2, 3, 4, 5];
let arr2 = arr.map(num => num * 2).filter(num => num > 5); // arr2 = [6, 8, 10]
forEach 方法,是最基本的方法,就是遍历与循环,默认有 3 个传参:分别是遍历的数组内容 item、数组索引 index、和当前遍历数组 Array
map 方法,基本用法与 forEach 一致,但是不同的,它会返回一个新的数组,所以 callback需要有 return 值,如果没有,会返回 undefined。

数组和对象的常见方法

前五个迭代数组的方法语法都一样,都不会改变原数组
Array.map();Array.forEach()
Array.filter():此方法类似于筛选向方法中传入一个判断条件,将满足条件的值变成一个新的数组返回。
Array.every():此方法是将所有元素进行判断返回一个布尔值,如果所有元素都满足判断条件的话,则返回true,如果不满足就返回 false。遍历数组每一项,若全部为true,才返回true ,否则返回false
Array.some():此方法和every类似,唯一区别就是some遍历数组中的每一项,若其中一项为true,则返回值是true,every遍历数组每一项,若全部为true,才返回true ,否则返回false。
Array.reduce():reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。可以用来写求和求积、最大值、最小值。
Array.push():此方法用来向数组末尾添加一个或多个元素,返回新增后数组的长度。
Array.pop():此方法删除数组中的最后一位元素,并返回删除的元素。
Array.shift():此方法删除数组中的第一个元素。
Array.unshift():此方法向数组前添加一个或多个元素,并返回新增后数组的长度。
Array.isArray():此方法是用来判断一个对象是不是数组,是的话返回true,不是返回false。
Array.concat():此方法是一个可以将多个数组合并成一个数组的方法。不会改变原数组,返回合并之后的数组。
Array.toString():此方法是用来将数组转变为字符串格式。
Array.join():通过指定连接符生成字符串。原数组不变
Array.splice(开始位置, 删除的个数,元素),万能的方法可以实现数组的增、删、改。
Array.slice():此方法返回从原数组中指定开始下标到结束下标之间的项组成的新数组(原数组不变)截取数组。前闭后开
Array.includes():此方法用来判断数组中是否有指定的元素,有的话返回true,没有的话返回false。
Array.indexOf():从数组的开头向后查找,接受两个参数,要查找的项和查找起点的位置索引。
Array.sort():按指定的参数对数组进行排序,返回的值是经过排序后的数组(无参,函数)
Array.fill():此方法用来替换数组中的元素,会改变原数组。
接受三个参数,第一个参数为替换的值,如果只传入一个值会吧数组中的值全部替换。
第二个参数是标记为从第几个位置开始替换,会从标记的位置开始把后面的元素全部替换。
第三个参数是结束时的索引。

对象的方法

1.Object.assign()
此方法用于克隆对象,传入两个参数,第一个参数为原对象,第二个参数为需要克隆的对象。会合并为一个新的对象,改变第一个参数的对象。
2.Object.is()
此方法是用来比较的接受两个参数,第一个参数是需要比较的第一个值,第二个参数是需要比较的第二个值。
返回值:布尔值,如果两个值相同返回true,不相同返回false。
注意,该函数与运算符不同,不会强制转换任何类型,应该更加类似于=,但值得注意的是它会将+0和-0视作不同值
3.Object.keys()
此方法是用来获取对象的key值的。返回一个包含key值的数组。
4.Object.defineProperty()
defineProperty为设置对象的属性的属性特征 value设置属性名,enumerable设置该属性是否可以被枚举。未设置的枚举的属性不能被for in遍历和keys获取。
该方法接受三个参数,第一个参数为要加入属性的对象,第二个参数为属性的key值,第三个参数为一个对象。
5.Object.defineProperties()
可添加多个属性,与Object.defineProperty()对应。
6.Object.isPrototypeOf()
此方法是用来检查一个对象是否存在另一个对象的原型链中。

requestAnimationFrame

  在Web应用中,实现动画效果的方法比较多,Javascript 中可以通过定时器 setTimeout/ setInterval 来实现,css3 可以使用 transition和 animation 来实现,html5 中的 canvas 也可以实现。除此之外,html5 还提供一个专门用于请求动画的API,那就是 requestAnimationFrame。
  setTimeout/ setInterval 的显著缺陷就是设定的时间并不精确,它们只是在设定的时间后将相应任务添加到任务队列中,而任务队列中如果还有前面的任务尚未执行完毕,那么后添加的任务就必须等待,这个等待的时间造成了原本设定的动画时间间隔不准。
  requestAnimationFrame的到来就是解决这个问题的 ,它采用的是系统时间间隔(约16.7ms),使各种网页动画有一个统一的刷新机制,从而节省系统资源,提高系统性能。requestAnimationFrame() 方法告诉浏览器用户希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。 特点:
(1)requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
(2)在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这就意味着更少的 CPU、GPU 和内存使用量
(3)requestAnimationFrame 是由浏览器专门为动画提供的 API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了 CPU 开销。

this指向

  1. 单独使用 this,它指向全局(Global)对象。
  2. 在对象方法中,this 指向调用它所在方法的对象。
  3. 函数使用中,this 指向函数的调用者。
  4. 严格模式下函数是没有绑定到 this 上,这时候 this 是 undefined。
  5. 在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素。
  6. apply 和 call、bind允许切换函数执行的上下文环境(context),可以将 this 引用到任何对象。

作用域链

一、作用域
作用域就是变量和函数生效的区域或集合,即作用域决定了代码区块中变量和其他资源的可见性

  1. 全局作用域
    任何不在函数中或是大括号中声明的变量,都会在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问。
  2. 函数作用域
    函数作用域也叫局部作用域,如果一个变量是在函数内部声明的,他就在该函数的作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问。
  3. 块级作用域
    ES6引入了let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号之外不能访问这些变量。
    二、词法作用域
    词法作用域,又叫静态作用域,变量被创建时就确定好了,而非执行阶段确定的。也就是说我们写好代码时它的作用域就确定了,JavaScript 遵循的就是词法作用域
var a = 2;
function foo(){
    console.log(a)
}
function bar(){
    var a = 3;
    foo();
}
bar();

上述代码变成下图:
由于JavaScript遵循词法作用域,相同层级的 foo 和 bar 就没有办法访问到彼此块作用域中的变量,所以输出2。

三、作用域链

  当在Javascript中访问一个变量的时候,首先Javascript引擎会在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域。如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错。

let/const/var的区别

(1)块级作用域:块作用域由{ }包括,let和const具有块级作用域,var不存在块级作用域。
(2)变量提升:var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否在会报错。
(3)给全局添加属性:浏览器的全局对象是window。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是let和const不会。
(4)重复声明:var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的变量。const和let不允许重复声明变量。
(5)暂时性死区:在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上称为暂时性死区。使用var声明的变量不存在暂时性死区。
(6)初始值设置:在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
指针指向: let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。

箭头函数

  1. 如果形参只有一个,则小括号可以省略;
  2. 函数体如果只有一条语句,则花括号可以省略,并省略return,函数的返回值为该条语句的执行结果;
  3. 箭头函数 this 指向声明时所在作用域下 this 的值;
  4. 不能作为构造实例化对象;不能使用 arguments 关键字;可以用 Rest 参数代替
  5. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数
JavaScript的运行机制

  JavaScript 是一门单线程的语言。单线程就意味着,一次只能执行一个任务,其他任务都需要排队等待。在 HTML5 中提出了 web worker 标准,它提供了一套完整的 API 去允许在主线程以外去执行另一个线程,但是不能访问 DOM。这不意味着 JavaScript 从此拥有了多线程的能力。在 JS中还有着独特执行机制,它将主线程中的任务分为同步任务和异步任务。
  同步任务:是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务,例如:console.log
  异步任务:不进入主线程、通过事件循环机制处理,在任务队列中注册回调函数最终拿到结果,例如:setTimeout

事件循环

首先我们用一张图来理解事件循环

  运行机制:所有同步任务在主线程上执行,形成一个执行栈,也就是上图蓝色箭头表示。主线程以外有一个异步任务队列(红色箭头),会等到异步任务返回结果后将它放入任务队列。当主线程中执行栈代码执行完毕,也就是同步任务执行完毕,就会开始读取任务队列代码,再放入执行栈中执行。
  不断地重复上面三步,这就是事件循环。用图形来描绘的话,就是上图中的三个黑色箭头,连成的闭环。也就是说:只要主线程执行栈空了,就会去读取任务队列,这个过程是循环不断的,这种运行机制就叫做事件循环。
  常见的会放入异步任务队列的事件:DOM 事件、Promise、Ajax 请求、setTimeout 和 setlnterval、文件上传

宏任务和微任务

宏任务有:HTML解析、鼠标事件、键盘事件、网络请求、执行主线程js代码和定时器
微任务有:promise.then,DOM 渲染,async,process.nextTick
那它是怎么被执行的呢?
当执行栈中的同步任务执行完毕后,先执行微任务;
微任务队列执行完毕后,会读取宏任务;
执行宏任务的过程中,遇到微任务,再加入微任务队列;
宏任务执行完后,再次读取微任务队列,依次循环;

微任务永远在宏任务执行之前被执行完毕

垃圾回收机制

  JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,没有被释放,导致该内存无法被使用,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。

垃圾回收方式

  通常有两种方式:标记清除(mark and sweep)、引用计数(reference counting)
标记清除
这是JavaScript中最常用的垃圾回收方式。
(1)当变量进入执行环境时(函数中声明变量),就标记这个变量为“进入环境”,当变量离开环境时(函数执行结束),则将其标记为“离开环境”,离开环境之后还有的变量则是需要被删除的变量。
(2)垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记。
(3)去掉环境中的变量以及被环境中变量引用的变量的标记。
(4)之后再被加上标记的变量即是需要回收的变量(因为环境中的变量已经无法访问到这些变量)
(5)最后,垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
引用计数
  这种方式常常会引起内存泄漏,低版本的IE使用这种方式。机制就是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给该变量时该值引用次数加1,当这个变量指向其他一个时该值的引用次数便减一。当该值引用次数为0时,则说明没有办法再访问这个值了,被视为准备回收的对象,每当过一段时间开始垃圾回收的时候,就把被引用数为0的变量回收。引用计数方法可能导致循环引用,类似死锁,导致内存泄露。
例如:

function problem() {
    var objA = new Object();
    var objB = new Object();
    objA.someOtherObject = objB;
    objB.anotherObject = objA;
}

objA和objB相互引用,两个对象的引用次数都是2。函数执行完成之后,objA和objB还将会继续存在,因为他们的引用次数永远不会是0。这样的相互引用如果说很大量的存在就会导致大量的内存泄露。

内存泄漏

定义:程序中己动态分配的堆内存由于某种原因程序未释放或无法释放引发的各种问题。
js中可能出现的内存泄漏原因:
(1)全局变量引起的内存泄露
(2)闭包引起的内存泄露:慎用闭包
(3)dom清空或删除时,事件未清除导致的内存泄漏
(4)循环引用带来的内存泄露

闭包

  闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。基本上就是一个函数内部返回一个函数。
  我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而使函数内部的值可以得以保留。

  • 好处:可以读取函数内部的变量、将变量始终保持在内存中、可以封装对象的私有属性和私有方法
  • 坏处:比较耗费内存、使用不当会造成内存溢出的问题

== 和 ===的区别

==是非严格意义上的相等,值相等就相等,会进行数据类型转换。
===是严格意义上的相等,会比较两边的数据类型和值大小,值和引用地址都相等才相等

跨域的原理

  跨域是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对 JavaScript 实施的安全限制,那么只要协议、域名、端口有任何一个不同,都被当作是不同的域。

如何解决跨域

  1. jsonp跨域:通过动态创建 script,再请求一个带参网址实现跨域通信。
  2. document.domain + iframe 跨域:两个页面都通过 js 强制设置 document.domain 为基础主域,就实现了同域。
  3. nodejs中间件代理跨域;
  4. 后端在头部信息里面设置安全域名;

严格模式的限制

变量必须声明后再使用;
函数的参数不能有同名属性,否则报错;
不能使用 with 语句;
禁止 this 指向全局对象;

attribute 和 property 的区别

(1)attribute 是 dom 元素在文档中作为 html 标签拥有的属性;property 就是 dom 元素在 js 中作为对象拥有的属性。
(2)Property的属性值可以是任意类型,attribute的属性值类型只能是string类型
(3)Property包含attribute中HTML自带的属性,不包含自定义属性
(4)attribute的值更像是初始值,会同步到property中。Attribute的值的修改也会同步到property中,但property修改则不会映射到attribute

异步编程的实现方式

(1)回调函数
优点:简单、容易理解
缺点:不利于维护、代码耦合高
(2)事件监听
优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数
缺点:事件驱动型,流程不够清晰
(3)发布/订阅(观察者模式)
类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者
(4)Promise 对象
优点:可以利用 then 方法,进行链式写法;可以书写错误时的回调函数
缺点:编写和理解,相对比较难
(5)Generator 函数
优点:函数体内外的数据交换、错误处理机制
缺点:流程管理不方便
(6)async 函数
优点:内置执行器、更好的语义、更广的适用性、返回的是 Promise、结构清晰
缺点:错误处理机制

项目性能优化

减少 HTTP 请求数;减少 DNS 查询;避免重定向;图片懒加载;减少 DOM 元素数量;减少 DOM 操作;
使用外部 JavaScript 和 CSS;压缩 JavaScript、CSS、字体、图片等;优化 CSS Sprite;
尽量减少 iframe 使用;避免图片 src 为空;把样式表放在 link 中;把 JavaScript 放在页面底部;

负载均衡

多台服务器共同协作,不让其中某一台或几台超额工作,发挥服务器的最大作用
(1)http 重定向负载均衡:调度者根据策略选择服务器以 302 响应请求,缺点只有第一次有效果,后续操作维持在该服务器 (2)dns 负载均衡:解析域名时,访问多个 ip 服务器中的一个
(3)反向代理负载均衡:访问统一的服务器,由服务器进行调度访问实际的某个服务器,对统一的服务器要求大,性能受到服务器群的数量

原型、原型链、继承

所有的函数都有prototype属性(原型);所有的对象都有__proto__属性
在Javascript中,每个函数都有一个原型属性prototype指向自身的原型,而由这个函数创建的对象也有一个__proto__属性指向这个原型,而函数的原型是一个对象,所以这个对象也会有一个__proto__指向自己的原型,这样逐层深入直到找到Object对象的原型,这样就形成了原型链。

HTML和HTML5区别

主要有三个区别:
1、文档声明区别
HTML:超文本标记语言,一种纯文本类型的语言。
HTML5.0:文档声明HTML5方便书写,精简,有利于程序员快速的阅读和开发。
2、结构语义区别
html:没有体现结构语义化的标签,如:


html5:添加了许多具有语义化的标签,如: 、 、
3、绘图区别
HTML:指可伸缩矢量图形,用于定义网络的基于矢量的图形。
HTML5:HTML5的canvas元素使用脚本(通常使用JavaScript)在网页上绘制图像,可以控制画布每一个像素。
实现浏览器响应式布局
使用媒体查询(@media);
使用flex弹性布局;使用百分比单位;使用rem单位;使用VH、HW单位;

本文标签: 三剑客面试题csshtmljs