前端经典面经--助你金九银十面试无烦恼

画一条0.5px 的线

参考回答:

采用meta viewport 的方式

采用border-image 的方式

采用transform: scale()的方式

复制代码

link 标签和import 标签的区别

参考回答:

  • link 属于html 标签,而@import 是css 提供的.

  • 页面被加载时,link 会同时被加载,而@import 引用的css 会等到页面加载结束后加载。

  • link 是html 标签,因此没有兼容性,而@import 只有IE5 以上才能识别。link 方式样式的权重高于@import 的。

transition 和animation 的区别

参考回答: Animation 和transition 大部分属性是相同的,他们都是随时间改变元素的属性值,他们的主要区别是transition 需要触发一个事件才能改变属性,而animation 不需要触发任何事件的情况下才会随时间改变属性值,并且transition 为2 帧,从from … to,而animation可以一帧一帧的。

BFC(块级格式化上下文,用于清楚浮动,防止margin 重叠等)

参考回答:

  • 直译成:块级格式化上下文,是一个独立的渲染区域,并且有一定的布局规则。

  • BFC 区域不会与float box 重叠

  • BFC 是页面上的一个独立容器,子元素不会影响到外面

  • 计算BFC 的高度时,浮动元素也会参与计算

那些元素会生成BFC:

  • 根元素

  • float 不为none 的元素

  • position 为fixed 和absolute 的元素

  • display 为inline-block、table-cell、table-caption,flex,inline-flex 的元素

  • overflow 不为visible 的元素

垂直居中的方法

参考回答:

// (1)margin:auto 法

css:

div{

width: 400px;

height: 400px;

position: relative;

border: 1px solid #465468;

}

img{

position: absolute;

margin: auto;

top: 0;

left: 0;

right: 0;

bottom: 0;

}

html:

// 定位为上下左右为0,margin:0 可以实现脱离文档流的居中.

复制代码

// (2)margin 负值法

.container{

width: 500px;

height: 400px;

border: 2px solid #379;

position: relative;

}

.inner{

width: 480px;

height: 380px;

background-color: #746;

position: absolute;

top: 50%;

left: 50%;

margin-top: -190px; /height 的一半/

margin-left: -240px; /width 的一半/

}

// 补充:其实这里也可以将marin-top 和margin-left 负值替换成,

// transform:translateX(-50%)和transform:translateY(-50%)

复制代码

(3)table-cell(未脱离文档流的)

//设置父元素的display:table-cell,并且vertical-align:middle,这样子元素可以实现垂直居中。

div{

width: 300px;

height: 300px;

border: 3px solid #555;

display: table-cell;

vertical-align: middle;

text-align: center;

}

img{

vertical-align: middle;

}

复制代码

//(4)利用flex

//将父元素设置为display:flex,并且设置align-items:center;justify-content:center;

.container{

width: 300px;

height: 200px;

border: 3px solid #546461;

display: -webkit-flex;

display: flex;

-webkit-align-items: center;

align-items: center;

-webkit-justify-content: center;

justify-content: center;

}

.inner{

border: 3px solid #458761;

padding: 20px;

}

复制代码

关于JS 动画和css3 动画的差异性

参考回答: 渲染线程分为main threadcompositor thread,如果css 动画只改变transformopacity,这时整个CSS 动画得以在compositor trhead 完成(而JS 动画则会在main thread 执行,然后出发compositor thread进行下一步操作),特别注意的是如果改变transformopacity是不会layout 或者paint 的。

区别:

  • 功能涵盖面,JS 比CSS 大

  • 实现/重构难度不一,CSS3 比JS 更加简单,性能跳优方向固定

  • 对帧速表现不好的低版本浏览器,css3 可以做到自然降级

  • css 动画有天然事件支持

  • css3 有兼容性问题

说一下块元素和行元素

参考回答:

  • 块元素:独占一行,并且有自动填满父元素,可以设置margin 和pading 以及高度和宽度。

  • 行元素:不会独占一行,width 和height 会失效,并且在垂直方向的padding 和margin会失效。

多行元素的文本省略号

display: -webkit-box

-webkit-box-orient:vertical

-webkit-line-clamp:3 // 设置成几就在第几行显示省略号

overflow:hidden

复制代码

visibility=hidden, opacity=0,display:none 区别

参考回答:

  • opacity=0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click 事件,那么点击该区域,也能触发点击事件的

  • visibility=hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元已经绑定的事件。

  • display=none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉一样。

双边距重叠问题(外边距折叠)

参考回答: 多个相邻(兄弟或者父子关系)普通流的块元素垂直方向marigin 会重叠。

折叠的结果为:

  1. 两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。

  2. 两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。

  3. 两个外边距一正一负时,折叠结果是两者的相加的和。

position 属性比较

参考回答:

固定定位fixed: 元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动。Fixed 定位使元素的位置与文档流无关,因此不占据空间。Fixed 定位的元素和其他元素重叠。

相对定位relative: 如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直或水平位置,让这个元素“相对于”它的起点进行移动。在使用相对定位时,无论是否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。

绝对定位absolute: 绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于<html>absolute 定位使元素的位置与文档流无关,因此不占据空间。absolute 定位的元素和其他元素重叠。

粘性定位sticky: 元素先按照普通文档流定位,然后相对于该元素在流中的flow root(BFC)和containing block(最近的块级祖先元素)定位。而后,元素定位表现为在跨越特定阈值前为相对定 位,之后为固定定位。

默认定位Static: 默认值。没有定位,元素出现在正常的流中(忽略top, bottom, left, right 或者z-index 声明)。 inherit: 规定应该从父元素继承 position 属性的值。

清除浮动

参考回答:

  1. 使用带clear属性的空元素

/**

在浮动元素后使用一个空元素如

,并在CSS 中予.clear{clear:both;}

属性即可清理浮动。亦可使用


来进行清理。

*/

.news {

background-color: gray;

border: solid 1px black;

}

.news img {

float: left;

}

.news p {

float: right;

}

.clear {

clear: both;

}

some text

/** 优点:简单,代码少,浏览器兼容性好。 缺点:需要添加大量无语义的html元素,代码不够优雅,后期不容易维护。 */ 复制代码

  1. 使用CSS 的overflow 属性

/**

给浮动元素的容器添加overflow:hidden;或overflow:auto;可以清除浮动,另外在IE6 中还

需要触发hasLayout ,例如为父元素设置容器宽高或设置zoom:1。

在添加overflow 属性后,浮动元素又回到了容器层,把容器高度撑起,达到了清理浮动

的效果。

*/

.news {

background-color: gray;

border: solid 1px black;

overflow: hidden; *zoom: 1;

}

.news img {

float: left;

}

.news p {

float: right;

}

some text

复制代码

  1. 给浮动元素的容器也添加上浮动属性即可清除内部浮动,但是这样会使其整体浮动,影响布局,不推荐使用。

  2. 使用邻接元素处理.

// 什么都不做,给浮动元素后面的元素添加clear 属性。

.news {

background-color: gray;

border: solid 1px black;

}

.news img {

float: left;

}

.news p {

float: right;

}

.content{

clear:both;

}

some text

复制代码

  1. 使用CSS 的:after 伪元素

/**

结合 :after 伪元素(注意这不是伪类,而是伪元素,代表一个元素之后最近的元素)和 IEhack ,

可以完美兼容当前主流的各大浏览器,这里的 IEhack 指的是触发 hasLayout。

给浮动元素的容器添加一个clearfix的class,然后给这个class添加一个:after伪元素

实现元素末尾添加一个看不见的块元素(Block element)清理浮动。

*/

.news {

background-color: gray;

border: solid 1px black;

}

.news img {

float: left;

}

.news p {

float: right;

}

.clearfix:after{

content: “020”;

display: block;

height: 0;

clear: both;

visibility: hidden;

}

.clearfix {

/* 触发 hasLayout */

zoom: 1;

}

some text

复制代码

CSS3 中对溢出的处理

参考回答: text-overflow 属性,值为clip 是修剪文本;ellipsis 为显示省略符号来表被修剪的文本; string 为使用给定的字符串来代表被修剪的文本。

float 的元素,display 是什么

参考回答: display 为block

隐藏页面中某个元素的方法

参考回答:

display:none; visibility:hidden; opacity: 0; position 移到外部,z-index 涂层遮盖等等

  1. opacity:0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定

一些事件,如click 事件,那么点击该区域,也能触发点击事件的

  1. visibility:hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已

经绑定的事件

  1. display:none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元

素删除掉。

复制代码

三栏布局的实现方式,尽可能多写,浮动布局时,三个div 的生成顺序有没有影响

参考回答:

  1. 使用float+margin:给 div 设置 float:left,left 的 div 添加属性 margin-right:left 和 center 的间隔 px, right 的 div 添加属性margin-left:left和 center 的宽度之和加上间隔。

  2. 使用 float+overflow:给 div 设置float:left,再给 right 的 div 设置overflow:hidden。这样子两个盒子浮动,另一个盒子触发 bfc 达到自适应。

  3. 使用position:父级div 设置position:relative,三个子级div 设置position:absolute,这个要计算好盒子的宽度和间隔去设置位置,兼容性比较好。

  4. 使用 table 实现:父级div 设置 display:table,设置 border-spacing:10px//设置间距,取值随意,子级div设置display:table-cell,这种方法兼容性好,适用于高度宽度未知的情况,但是margin失效,设计间隔比较麻烦。

  5. flex 实现:parent 的div 设置display:flex;left 和center 的div 设置margin-right;然后right 的div设置flex:1;这样子right 自适应,但是flex 的兼容性不好。

  6. grid 实现:parent 的div 设置display:grid,设置grid-template-columns 属性,固定第一列第二列宽度,第三列auto,

calc 属性

参考回答: Calc 用户动态计算长度值,任何长度值都可以使用calc()函数计算,需要注意的是,运 算符前后都需要保留一个空格,例如:width: calc(100% - 10px);

display:table 和本身的table 有什么区别

参考回答: display:table 和本身table 是相对应的,区别在于,display:table 的css 声明能够让一个html 元素和它的子节点像table 元素一样,使用基于表格的css 布局,是我们能够轻松定义一个单元格的边界,背景等样式,而不会产生因为使用了table 那样的制表标签导致的语义化问题。之所以现在逐渐淘汰了table 系表格元素,是因为用div+css 编写出来的文件比用table边写出来的文件小,而且table 必须在页面完全加载后才显示,div 则是逐行显示,table的嵌套性太多,没有div 简洁。

z-index 的定位方法

参考回答: z-index 属性设置元素的堆叠顺序,拥有更好堆叠顺序的元素会处于较低顺序元素之前,z-index 可以为负,且z-index 只能在定位元素上奏效,该属性设置一个定位元素沿z 轴的位置,如果为正数,离用户越近,为负数,离用户越远,它的属性值有auto,默认,堆叠顺序与父元素相等,number,inherit,从父元素继承z-index 属性的值。

line-height 和height 的区别

参考回答: line-height 一般是指布局里面一段文字上下行之间的高度,是针对字体来设置的,height 一般是指容器的整体高度。

设置一个元素的背景颜色,背景颜色会填充哪些区域?

参考回答: background-color 设置的背景颜色会填充元素的content、padding、border 区域。

属性选择器和伪类选择器的优先级

参考回答: 属性选择器和伪类选择器优先级相同

inline-block、inline 和block 的区别;为什么img 是inline 还可以设置宽高

参考回答:

  • Block 是块级元素,其前后都会有换行符,能设置宽度,高度,margin/padding 水平垂直方向都有效。

  • Inline:设置width 和height 无效,margin 在竖直方向上无效,padding 在水平方向垂直方向都有效,前后无换行符

  • Inline-block:能设置宽度高度,margin/padding 水平垂直方向都有效,前后无换行符

用css 实现一个硬币旋转的效果

参考回答:

#euro {

width: 150px;

height: 150px;

margin-left: -75px;

margin-top: -75px;

position: absolute;

top: 50%;

left: 50%;

transform-style: preserve-3d;

animation: spin 2.5s linear infinite;

}

.back {

background-image: url(“/uploads/160101/backeuro.png”);

width: 150px;

height: 150px;

}

.middle {

background-image: url(“/uploads/160101/faceeuro.png”);

width: 150px;

height: 150px;

transform: translateZ(1px);

position: absolute;

top: 0;

}

.front {

background-image: url(“/uploads/160101/faceeuro.png”);

height: 150px;

position: absolute;

top: 0;

transform: translateZ(10px);

width: 150px;

}

@keyframes spin {

0% {

transform: rotateY(0deg);

}

100% {

transform: rotateY(360deg);

}

}

复制代码

了解重绘和重排吗,知道怎么去减少重绘和重排吗,让文档脱离文档流有哪些方法

参考回答: DOM 的变化影响到了预算内宿的几何属性比如宽高,浏览器重新计算元素的几何属性,其他元素的几何属性也会受到影响,浏览器需要重新构造渲染书,这个过程称之为重排,浏览器将受到影响的部分重新绘制在屏幕上的过程称为重绘,引起重排重绘的原因有:

  1. 添加或者删除可见的DOM 元素,

  2. 元素尺寸位置的改变

  3. 浏览器页面初始化,

  4. 浏览器窗口大小发生改变,重排一定导致重绘,重绘不一定导致重排,

减少重绘重排的方法有:

  1. 不在布局信息改变时做DOM 查询,

  2. 使用csstext,className 一次性改变属性

  3. 使用fragment

  4. 对于多次重排的元素,比如说动画。使用绝对定位脱离文档流,使其不影响其他元素

box-sizing 的语法和基本用处

参考回答:

box-sizing 规定两个并排的带边框的框,语法为box-sizing:content-box/border-box/inherit

content-box:宽度和高度分别应用到元素的内容框,在宽度和高度之外绘制元素的内边距和边框

border-box:为元素设定的宽度和高度决定了元素的边框盒,

inherit:继承父元素的box-sizing

复制代码

JavaScript


get 请求传参长度的误区

参考回答: 误区:我们经常说get 请求参数的大小存在限制,而post 请求的参数大小是无限制的。实际上HTTP 协议从未规定GET/POST 的请求长度限制是多少。对get 请求参数的限制是来源与浏览器或web 服务器,浏览器或web 服务器限制了url 的长度。为了明确这个概念,我们必须再次强调下面几点:

  1. HTTP 协议未规定GET 和POST 的长度限制。

  2. GET 的最大长度显示是因为浏览器和web 服务器限制了URI 的长度。

  3. 不同的浏览器和WEB 服务器,限制的最大长度不一样。

  4. 要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度8182byte。

补充get 和post 请求在缓存方面的区别

参考回答: get 请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以 使用缓存。post 不同,post 做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用 缓存。因此get 请求适合于请求缓存。

说一下闭包

参考回答: 一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用, 子函数所在的父函数的作用域不会被释放。

说一下类的创建和继承

参考回答:

// 1)类的创建(es5):new 一个function,在这个function 的prototype 里面增加属性和方法。

// 下面来创建一个Animal 类:

// 定义一个动物类

function Animal (name) {

// 属性

this.name = name || ‘Animal’;

// 实例方法

this.sleep = function(){

console.log(this.name + ‘正在睡觉!’);

}

}

// 原型方法

Animal.prototype.eat = function(food) {

console.log(this.name + ‘正在吃:’ + food);

};

// 这样就生成了一个Animal 类,实力化生成对象后,有方法和属性。

//(2)类的继承——原型链继承

// --原型链继承

function Cat(){ }

Cat.prototype = new Animal();

Cat.prototype.name = ‘cat’;

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.eat(‘fish’));

console.log(cat.sleep());

console.log(cat instanceof Animal); //true

console.log(cat instanceof Cat); //true

/**

介绍:在这里我们可以看到new 了一个空对象,这个空对象指向Animal 并且Cat.prototype

指向了这个空对象,这种就是基于原型链的继承。

特点:基于原型链,既是父类的实例,也是子类的实例

缺点:无法实现多继承

*/

//(3)构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

function Cat(name){

Animal.call(this);

this.name = name || ‘Tom’;

}

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // false

console.log(cat instanceof Cat); // true

// 特点:可以实现多继承

// 缺点:只能继承父类实例的属性和方法,不能继承原型上的属性和方法。

/**

(4)实例继承和拷贝继承

实例继承:为父类实例添加新特性,作为子类实例返回

拷贝继承:拷贝父类元素上的属性和方法

上述两个实用性不强,不一一举例。

*/

/**

(5)组合继承:相当于构造继承和原型链继承的组合体。通过调用父类构造,继承父

类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

*/

function Cat(name){

Animal.call(this);

this.name = name || ‘Tom’;

}

Cat.prototype = new Animal();

Cat.prototype.constructor = Cat;

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // true

console.log(cat instanceof Cat); // true

// 特点:可以继承实例属性/方法,也可以继承原型属性/方法

// 缺点:调用了两次父类构造函数,生成了两份实例

/**

(6)寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的

构造的时候,就不会初始化两次实例方法/属性

*/

function Cat(name){

Animal.call(this);

this.name = name || ‘Tom’;

}

(function(){

// 创建一个没有实例方法的类

var Super = function(){};

Super.prototype = Animal.prototype;

//将实例作为子类的原型

Cat.prototype = new Super();

})();

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // true

console.log(cat instanceof Cat); //true

// 较为推荐

复制代码

说说前端中的事件流

参考回答: HTML 中与javascript 交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll 等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2 级事件流包括下面几个阶段。

  • 事件捕获阶段

  • 处于目标阶段

  • 事件冒泡阶段

addEventListener:addEventListener 是DOM2 级事件新增的指定事件处理程序的操作, 这个方法接收3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最 后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示 在冒泡阶段调用事件处理程序。

IE 只支持事件冒泡。

如何让事件先冒泡后捕获

参考回答: 在DOM 标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行,直到冒泡事件被捕获后再执行捕获之间。

说一下事件委托

参考回答: 简介:事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父 元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判 断事件发生元素DOM 的类型,来做出不同的响应。

举例:最经典的就是ul 和li 标签的事件监听,比如我们在添加事件时候,采用事件委 托机制,不会在li 标签上直接添加,而是在ul 父元素上添加。

好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发 机制。

说一下图片的懒加载和预加载

参考回答:

  • 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。

  • 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。

两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

mouseover 和mouseenter 的区别

参考回答:

  • mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout。

  • mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave。

JS 的new 操作符做了哪些事情

参考回答: new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

改变函数内部this 指针的指向函数(bind,apply,call 的区别)

参考回答: 通过apply 和call 改变函数的this 指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply 是数组,而call 则是arg1,arg2…这种形式。通过bind 改变this 作用域会返回一个新的函数,这个函数不会马上执行。

JS 的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop,offsetTop,clientTop 的区别?

参考回答:

  • clientHeight:表示的是可视区域的高度,不包含border 和滚动条。

  • offsetHeight:表示可视区域的高度,包含了border 和滚动条。

  • scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。

  • clientTop:表示边框border 的厚度,在未指定的情况下一般为0。

  • scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent 属性指定的父坐标(css定位的元素或body 元素)距离顶端的高度。

JS 拖拽功能的实现

参考回答:

  1. 首先是三个事件,分别是mousedown,mousemove,mouseup

  2. 当鼠标点击按下的时候,需要一个tag 标识此时已经按下,可以执行mousemove 里面的具体方法。

  3. clientX,clientY 标识的是鼠标的坐标,分别标识横坐标和纵坐标,并且我们用offsetX和offsetY 来表示元素的元素的初始坐标,移动的举例应该是:鼠标移动时候的坐标-鼠标按下去时候的坐标。也就是说定位信息为:鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的offetLeft.还有一点也是原理性的东西,也就是拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left以及

top 等等值。 补充:也可以通过html5 的拖放(Drag 和drop)来实现。

异步加载JS 的方法

参考回答:

  • defer:只支持IE 如果您的脚本不会改变文档的内容,可将defer 属性加入到<script>标签中,以便加快处理文档的速度。因为浏览器知道它将能够安全地读取文档的剩余部分而不用执行脚本,它将推迟对脚本的解释,直到文档已经显示给用户为止。

  • async,HTML5 属性仅适用于外部脚本,并且如果在IE 中,同时存在defer 和async,那么defer 的优先级比较高,脚本将在页面完成时执行。创建script 标签,插入到DOM 中。

Ajax 解决浏览器缓存问题

参考回答:

  • 在ajax 发送请求前加上anyAjaxObj.setRequestHeader("If-Modified-Since","0")

  • 在ajax 发送请求前加上anyAjaxObj.setRequestHeader("Cache-Control","no-cache")

  • 在URL 后面加上一个随机数: "fresh=" + Math.random()

  • 在URL 后面加上时间搓:"nowtime=" + new Date().getTime()

  • 如果是使用jQuery,直接这样就可以了$.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。

JS 的节流和防抖

参考回答:

防抖(Debouncing):防抖技术即是可以把多个顺序地调用合并成一次,也就是在一定时间内,规定事件被触发的次数。

// 防抖动函数

function debounce(func, wait, immediate) {

var timeout;

return function() {

var context = this, args = arguments;

var later = function () {

timeout = null ;

if (!immediate) func.apply(context, args);

};

var callNow = immediate && !timeout;

clearTimeout(timeout);

timeout = setTimeout(later, wait);

if (callNow) func.apply(context, args);

};

};

var myEfficientFn = debounce(function() {

// 滚动中的真正的操作

}, 250);

// 绑定监听

window.addEventListener('resize', myEfficientFn);

复制代码

节流(Throttling):节流函数,只允许一个函数在 X 毫秒内执行一次。

// 简单的节流函数

function throttle(func, wait, mustRun) {

var timeout,

startTime = new Date();

return function() {

var context = this,

args = arguments,

curTime = new Date();

clearTimeout(timeout);

// 如果达到了规定的触发时间间隔,触发 handler

if(curTime - startTime >= mustRun){

func.apply(context,args);

startTime = curTime;

// 没达到触发间隔,重新设定定时器

}else{

timeout = setTimeout(func, wait);

}

};

};

// 实际想绑定在 scroll 事件上的 handler

function realFunc(){

console.log(“Success”);

}

// 采用了节流函数

window.addEventListener(‘scroll’,throttle(realFunc,500,1000));

复制代码

JS 中的垃圾回收机制

参考回答: JS 的垃圾收集机制原理其实是很简单的:找到那些不再继续使用的变量,然后释放其占用的内存。具体实现的方法有两种:标记清除和引用计数。

标记清除:这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离开环境。垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。

引用计数法:引用计数是一张不太常见的垃圾收集策略。引用计数的含义是跟踪记录每个值被引用的次数。当生命了一个变量将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当某个值的引用次数变成0时,则说明没有办法再访问这个值,而且这个值也没有存在的意义了,所以它会被释放。

eval 是做什么的

参考回答: 它的功能是将对应的字符串解析成JS 并执行,应该避免使用JS,因为非常消耗性能(2次,一次解析成JS,一次执行)

如何理解前端模块化

参考回答: 前端模块化就是复杂的文件编程一个一个独立的模块,比如JS 文件等等,分成独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题, 所以有了commonJS 规范,AMD,CMD 规范等等,以及用于JS 打包(编译等处理)的工具webpack

说一下CommonJS、AMD 和CMD

参考回答: 一个模块是能实现特定功能的文件,有了模块就可以方便的使用别人的代码,想要什么功能就能加载什么模块。 CommonJS:开始于服务器端的模块化,同步定义的模块化,每个模块都是一个单独的 作用域,模块输出,modules.exports,模块加载require()引入模块。 AMD:中文名异步模块定义的意思。 requireJS 实现了AMD 规范,主要用于解决下述两个问题。

  1. 多个文件有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器

  2. 加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应的时间越长。

// 语法:requireJS 定义了一个函数define,它是全局变量,用来定义模块。

// requireJS 的例子:

//定义模块

define([‘dependency’], function(){

var name = ‘Byron’;

function printName(){

console.log(name);

}

return {

printName: printName

};

});

//加载模块

require([‘myModule’], function (my){

my.printName();

}

// RequireJS 定义了一个函数define,它是全局变量,用来定义模块:

define(id?dependencies?,factory)

// 在页面上使用模块加载函数:

require([dependencies],factory);

复制代码

总结AMD 规范:require()函数在加载依赖函数的时候是异步加载的,这样浏览器不 会失去响应,它指定的回调函数,只有前面的模块加载成功,才会去执行。 因为网页在加载JS 的时候会停止渲染,因此我们可以通过异步的方式去加载JS,而如果 需要依赖某些,也是异步去依赖,依赖后再执行某些方法。

对象深度克隆的简单实现

function deepClone(obj){

var newObj= obj instanceof Array ? []:{};

for(var item in obj){

var temple= typeof obj[item] == ‘object’ ? deepClone(obj[item]):obj[item];

newObj[item] = temple;

}

return newObj;

}

复制代码

ES5 的常用的对象克隆的一种方式。注意数组是对象,但是跟对象又有一定区别,所以我们一开始判断了一些类型,决定newObj 是对象还是数组。

实现一个once 函数,传入函数参数只执行一次

function ones(func){

var tag=true;

return function(){

if(tag==true){

func.apply(null,arguments);

tag=false;

}

return undefined

}

}

复制代码

将原生的ajax 封装成promise

var myNewAjax=function(url){

return new Promise(function(resolve,reject){

var xhr = new XMLHttpRequest();

xhr.open(‘get’,url);

xhr.send(data);

xhr.onreadystatechange=function(){

if(xhr.status200&&readyState4){

var json=JSON.parse(xhr.responseText);

resolve(json)

}else if(xhr.readyState==4&&xhr.status!=200){

reject(‘error’);

}

}

})

}

复制代码

JS 监听对象属性的改变

// 我们假设这里有一个user 对象,

// (1)在ES5 中可以通过Object.defineProperty 来实现已有属性的监听

Object.defineProperty(user,‘name’,{

set:function(key,value){

}

})

// 缺点:如果id 不在user 对象中,则不能监听id 的变化

// (2)在ES6 中可以通过Proxy 来实现

var user = new Proxy({},{

set:function(target,key,value,receiver){

}

})

// 这样即使有属性在user 中不存在,通过user.id 来定义也同样可以这样监听这个属性的变化哦。

复制代码

如何实现一个私有变量,用getName 方法可以访问,不能直接访问

// (1)通过defineProperty 来实现

obj={

name:yuxiaoliang,

getName:function(){

return this.name

}

}

object.defineProperty(obj,“name”,{

//不可枚举不可配置

});

// (2)通过函数的创建形式

function product(){

var name=‘yuxiaoliang’;

this.getName=function(){

return name;

}

}

var obj=new product();

复制代码

==和===、以及Object.is 的区别

参考回答:

// (1) ==

// 主要存在:强制转换成number,null==undefined

" "==0 //true

“0”==0 //true

" " !=“0” //true

123==“123” //true

null==undefined //true

// (2)Object.js

// 主要的区别就是+0!=-0 而NaN==NaN

// (相对比=的改进)

复制代码

setTimeout、setInterval 和requestAnimationFrame 之间的区别

参考回答: 与setTimeout 和setInterval 不同,requestAnimationFrame 不需要设置时间间隔, 大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60 次。大多数浏览器都 会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也 不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms。 RAF 采用的是系统时间间隔,不会因为前面的任务,不会影响RAF,但是如果前面的 任务多的话,会响应setTimeout 和setInterval 真正运行时的时间间隔。

特点:

  • requestAnimationFrame 会把每一帧中的所有DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。

  • 在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的CPU、GPU 和内存使用量

  • requestAnimationFrame 是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU 开销。

自己实现一个bind 函数

参考回答:

// 原理:通过apply 或者call 方法来实现。

// (1)初始版本

Function.prototype.bind=function(obj,arg){

var arg=Array.prototype.slice.call(arguments,1);

var context=this;

return function(newArg){

arg=arg.concat(Array.prototype.slice.call(newArg));

return context.apply(obj,arg);

}

}

// (2) 考虑到原型链

// 为什么要考虑?因为在new 一个bind 过生成的新函数的时候,必须的条件是要继承原函数的原型

Function.prototype.bind=function(obj,arg){

var arg=Array.prototype.slice.call(arguments,1);

var context=this;

var bound=function(newArg){

arg=arg.concat(Array.prototype.slice.call(newArg));

return context.apply(obj,arg);

}

var F=function(){}

//这里需要一个寄生组合继承

F.prototype=context.prototype;

bound.prototype=new F();

return bound;

}

复制代码

JS 怎么控制一次加载一张图片,加载完后再加载下一张

参考回答:

// (1)方法1

onloading……

// (2)方法2

onloading……

复制代码

js中的数据类型

参考回答:

基本数据类型:Undefined、Null、Boolean、Number、String,Symbol

引用数据类型:Object

JS 判断类型

参考回答: 判断方法:typeof(),instanceof,Object.prototype.toString.call(),constructor等

数组去重

参考回答:

  • indexOf 循环去重

  • ES6 Set 去重;Array.from(new Set(array))

  • Object 键值对去重;把数组的值存成Object 的key 值,比如Object[value1] = true,在判断另一个值的时候,如果Object[value2]存在的话,就说明该值是重复的。

闭包有什么用

参考回答:

(1)什么是闭包:

闭包是指有权访问另外一个函数作用域中的变量的函数。 闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是 就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈 上分配而是在堆上分配。当在一个函数内定义另外一个函数就会产生闭包。

(2)为什么要用:

匿名自执行函数:我们知道所有的变量,如果不加上var 关键字,则默认的会添加到全 局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误 用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链 上遍历的)。除了每次使用变量都是用var 关键字外,我们在实际情况下经常遇到这样一 种情况,即有的函数只需要执行一次,其内部变量无需维护,可以用闭包。 结果缓存:我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象, 每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函 数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如 果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部 的引用,从而函数内部的值可以得以保留。 封装:实现类和继承等。

能来讲讲JS 的语言特性吗

参考回答:

  • 运行在客户端浏览器上;

  • 不用预编译,直接解析执行代码;

  • 是弱类型语言,较为灵活;

  • 与操作系统无关,跨平台的语言;

  • 脚本语言、解释性语言

JS 实现跨域

参考回答: JSONP:通过动态创建script,再请求一个带参网址实现跨域通信。document.domain + iframe 跨域:两个页面都通过js 强制设置document.domain 为基础主域,就实现了同域。 location.hash + iframe 跨域:a 欲与b 跨域相互通信,通过中间页c 来实现。三个页面, 不同域之间利用iframe 的location.hash 传值,相同域之间直接js 访问来通信。 window.name + iframe 跨域:通过iframe 的src 属性由外域转向本地域,跨域数据即由iframe的window.name 从外域传递到本地域。

postMessage 跨域:可以跨域操作的window 属性之一。

CORS:服务端设置Access-Control-Allow-Origin 即可,前端无须设置,若要带cookie 请 求,前后端都需要设置。 代理跨域:启一个代理服务器,实现数据的转发

重排和重绘,讲讲看

参考回答: 重绘(repaint 或redraw):当盒子的位置、大小以及其他属性,例如颜色、字体大小等 都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面 上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重 新绘制,使元素呈现新的外观。

触发重绘的条件:改变元素外观属性。如:color,background-color 等。

注意:table 及其内部元素可能需要多次计算才能确定好其在渲染树中节点的属性值,比 同等元素要多花两倍时间,这就是我们尽量避免使用table 布局页面的原因之一。

重排(重构/回流/reflow):当渲染树中的一部分(或全部)因为元素的规模尺寸,布局, 隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是 在页面第一次加载的时候。

重绘和重排的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新 构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称 为重绘。所以,重排必定会引发重绘,但重绘不一定会引发重排。

promise+Generator+Async 的使用

参考回答: Promise 解决的问题:回调地狱 Promise 规范:

  • promise 有三种状态,等待(pending)、已完成(fulfilled/resolved)、已拒绝(rejected).Promise的状态只能从“等待”转到“完成”或者“拒绝”,不能逆向转换,同时“完成”和“拒绝”也不能相互转换.

  • promise 必须提供一个then 方法以访问其当前值、终值和据因。promise.then(resolve,reject),resolve 和reject 都是可选参数。如果resolve 或reject 不是函数,其必须被忽略.then 方法必须返回一个promise 对象.

/**使用:

实例化promise 对象需要传入函数(包含两个参数),resolve 和reject,内部确定状态.resolve

和reject 函数可以传入参数在回调函数中使用.

resolve 和reject 都是函数,传入的参数在then 的回调函数中接收.

_/

var promise = new Promise(function(resolve, reject) {

setTimeout(function(){

resolve(‘好哈哈哈哈’);

});

});

promise.then(function(val){

console.log(val)

})

// then 接收两个函数,分别对应resolve 和reject 状态的回调,函数中接收实例化时传入的参数.

promise.then(val=>{

//resolved

},reason=>{

//rejected

})

/**catch 相当于.then(null, rejection)

当then 中没有传入rejection 时,错误会冒泡进入catch 函数中,若传入了rejection,则错误会

被rejection 捕获,而且不会进入catch.此外,then 中的回调函数中发生的错误只会在下一级

的then 中被捕获,不会影响该promise 的状态._/

new Promise((resolve,reject)=>{

throw new Error(‘错误’)

}).then(null,(err)=>{

console.log(err,1);//此处捕获

}).catch((err)=>{

console.log(err,2);

});

// 对比

new Promise((resolve,reject)=>{

throw new Error(‘错误’)

}).then(null,null).catch((err)=>{

console.log(err,2);//此处捕获

});

// 错误示例

new Promise((resolve,reject)=>{

resolve(‘正常’);

}).then((val)=>{

throw new Error(‘回调函数中错误’)

},(err)=>{

console.log(err,1);

}).then(null,(err)=>{

console.log(err,2);//此处捕获,也可用catch

});

// 两者不等价的情况:

// 此时,catch 捕获的并不是p1 的错误,而是p2 的错误,

p1().then(res=>{

return p2()//p2 返回一个promise 对象

}).catch(err=> console.log(err))

/** 一个错误捕获的错误用例:

该函数调用中即使发生了错误依然会进入then 中的resolve 的回调函数,因为函数p1 中实

例化promise 对象时已经调用了catch,若发生错误会进入catch 中,此时会返回一个新的

promise,因此即使发生错误依然会进入p1 函数的then 链中的resolve 回调函数._/

function p1(val){

return new Promise((resolve,reject)=>{

if(val){

var len = val.length;//传入null 会发生错误,进入catch 捕获错

resolve(len);

}else{

reject();

}

}).catch((err)=>{

console.log(err)

})

};

p1(null).then((len)=>{

console.log(len,‘resolved’);

},()=>{

console.log(‘rejected’);

}).catch((err)=>{

console.log(err,‘catch’);

})

/** Promise 回调链:

promise 能够在回调函数里面使用return 和throw, 所以在then 中可以return 出一个

promise 对象或其他值,也可以throw 出一个错误对象,但如果没有return,将默认返回

undefined,那么后面的then 中的回调参数接收到的将是undefined._/

function p1(val){

return new Promise((resolve,reject)=>{

val1?resolve(1):reject()

})

};

function p2(val){

return new Promise((resolve,reject)=>{

val2?resolve(2):reject();

})

};

let promimse = new Promise(function(resolve,reject){

resolve(1)

})

.then(function(data1) {

return p1(data1)//如果去掉return,则返回undefined 而不是p1 的返回值,会导致报错

})

.then(function(data2){

return p2(data2+1)

})

.then(res=>console.log(res))

复制代码

Generator 函数:

generator 函数使用:

  • 分段执行,可以暂停

  • 可以控制阶段和每个阶段的返回值

  • 可以知道是否执行到结尾

function* g() {

var o = 1;

yield o++;

yield o++;

}

var gen = g();

console.log(gen.next()); // Object {value: 1, done: false}

var xxx = g();

console.log(gen.next()); // Object {value: 2, done: false}

console.log(xxx.next()); // Object {value: 1, done: false}

console.log(gen.next()); // Object {value: undefined, done: true}

复制代码

generator 和异步控制: 利用Generator 函数的暂停执行的效果,可以把异步操作写在yield 语句里面,等到调用 next 方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操 作可以放在yield 语句下面,反正要等到调用next 方法时再执行。所以,Generator 函数 的一个重要实际意义就是用来处理异步操作,改写回调函数。

async 和异步: async 表示这是一个async 函数,await 只能用在这个函数里面。 await 表示在这里等待异步操作返回结果,再继续执行。 await 后一般是一个promise 对象 示例:async 用于定义一个异步函数,该函数返回一个Promise。 如果async 函数返回的是一个同步的值,这个值将被包装成一个理解resolve 的Promise, 等同于return Promise.resolve(value)。 await 用于一个异步操作之前,表示要“等待”这个异步操作的返回值。await 也可以用 于一个同步的值。

let timer = async function timer(){

return new Promise((resolve,reject) => {

setTimeout(() => {

resolve(‘500’);

},500);

});

}

timer().then(result => {

console.log(result); //500

}).catch(err => {

console.log(err.message);

});

//返回一个同步的值

let sayHi = async function sayHi(){

let hi = await ‘hello world’;

return hi; //等同于return Promise.resolve(hi);

}

sayHi().then(result => {

console.log(result);

});

复制代码

ES6 箭头函数的特性

参考回答: 箭头函数与普通函数的区别在于:

  • 箭头函数没有this,所以需要通过查找作用域链来确定this 的值,这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的this,

  • 箭头函数没有自己的arguments 对象,但是可以访问外围函数的arguments 对象

  • 不能通过new 关键字调用,同样也没有new.target 值和原型

JS 加载过程阻塞,解决方法。

参考回答: 指定script 标签的async 属性。如果async=“async”,脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)如果不使用async 且defer=“defer”:脚本将在页面完成解析时执行

服务端编程/Ajax


JSONP 的缺点

  • JSON 只支持get,因为script 标签只能使用get 请求;

  • JSONP 需要后端配合返回指定格式的数据。

跨域(jsonp,ajax)

JSONP:ajax 请求受同源策略影响,不允许进行跨域请求,而script 标签src 属性中的链 接却可以访问跨域的js 脚本,利用这个特性,服务端不再返回JSON 格式的数据,而是 返回一段调用某个函数的js 代码,在src 中进行了调用,这样实现了跨域。

如何实现跨域

  • JSONP:通过动态创建script,再请求一个带参网址实现跨域通信。document.domain +iframe 跨域:两个页面都通过js 强制设置document.domain 为基础主域,就实现了同域。location.hash + iframe 跨域:a 欲与b 跨域相互通信,通过中间页c 来实现。三个页面,不同域之间利用iframe 的location.hash 传值,相同域之间直接js 访问来通信。window.name + iframe 跨域:通过iframe 的src 属性由外域转向本地域,跨域数据即由iframe的window.name 从外域传递到本地域。

  • postMessage 跨域:可以跨域操作的window 属性之一。

  • CORS:服务端设置Access-Control-Allow-Origin 即可,前端无须设置,若要带cookie 请求,前后端都需要设置。

  • 代理跨域:起一个代理服务器,实现数据的转发

实现一个Ajax

AJAX 创建异步对象XMLHttpRequest操作XMLHttpRequest 对象

  1. 设置请求参数(请求方式,请求页面的相对路径,是否异步)

  2. 设置回调函数,一个处理服务器响应的函数,使用onreadystatechange ,类似函数指针

  3. 获取异步对象的readyState 属性:该属性存有服务器响应的状态信息。每当readyState 改变时,onreadystatechange 函数就会被执行。

  4. 判断响应报文的状态,若为200 说明服务器正常运行并返回响应数据。

  5. 读取响应数据,可以通过responseText 属性来取回由服务器返回的数据。

var xhr = new XMLHttpRequest();

xhr.open(‘get’, ‘aabb.php’, true);

xhr.send(null);

xhr.onreadystatechange = function() {

if(xhr.readyState4) {

if(xhr.status200) {

console.log(xhr.responseText);

}

}

}

复制代码

移动web 开发


知道PWA 吗

PWA 全称Progressive Web App,即渐进式WEB 应用。一个PWA 应用首先是一个网页,可以通过Web 技术编写出一个网页应用. 随后添加上App Manifest 和Service Worker来实现PWA 的安装和离线等功能

Rem, Em

rem 单位如何转换为像素值 当使用rem 单位的时候,页面转换为像素大小取决于叶根元素的字体大小,即HTML 元素的字体大小。根元素字体大小乘rem 的值。例如,根元素的字体大小为16px,那么 10rem 就等同于10*16=160px。

em 是如何转换成px 的 当使用em 单位的时候,像素值是将em 值乘以使用em 单位的元素的字体大小。例如一 个div 的字体为18px,设置它的宽高为10em,那么此时宽高就是18px*10em=180px。

.test{

width: 10em;

height: 10em;

background-color: #ff7d42;

font-size: 18px;

}

/**

一定要记住的是,em 是根据使用它的元素的font-size 的大小来变化的,而不是根据父

元素字体大小。有些元素大小是父元素的多少倍那是因为继承了父元素中font-size 的设

定,所以才起到的作用。

*/

复制代码

em 单位的继承效果 使用em 单位存在继承的时候,每个元素将自动继承其父元素的字体大小,继承的效果 只能被明确的字体单位覆盖,比如px 和vw。只要父级元素上面一直有fontsize 为em 单 位,则会一直继承,但假如自己设置了font-size 的单位为px 的时候,则会直接使用自 己的px 单位的值。

根html 的元素将会继承浏览器中设置的字体大小 除非显式的设置固定值去覆盖。所以html 元素的字体大小虽然是直接确定rem 的值, 但这个字体大小首先是来源于浏览器的设置。(所以一定要设置html 的值的大小,因 为有可能用户的浏览器字体大小是不一致的。)

当em 单位设置在html 元素上时 它将转换为em 值乘以浏览器字体大小的设置。

html{

font-size: 1.5em;

}

/**

可以看到,因为浏览器默认字体大小为16px,所以当设置HTML 的fontsize 的值为1.5em

的售后,其对应的px 的值为16*1.5=24px

所以此时,再设置其他元素的rem 的值的时候,其对应的像素值为n*24px。

例如,test 的rem 的值为10,

*/

.test{

width: 10rem;

height: 10rem;

background-color: #ff7d42;

}

/**

总结:

  1. rem 单位翻译为像素值的时候是由html 元素的字体大小决定的。此字体大小会

被浏览器中字体大小的设置影响,除非显式的在html 为font-size 重写一个单位。

  1. em 单位转换为像素值的时候,取决于使用它们的元素的font-size 的大小,但是有

因为有继承关系,所以比较复杂。

优缺点

em 可以让我们的页面更灵活,更健壮,比起到处写死的px 值,em 似乎更有张力,改

动父元素的字体大小,子元素会等比例变化,这一变化似乎预示了无限可能,

em 做弹性布局的缺点还在于牵一发而动全身,一旦某个节点的字体大小发生变化,那

么其后代元素都得重新计算

*/

复制代码

移动端适配1px 的问题

  1. 用小数来写px 值(不推荐)

// IOS8 下已经支持带小数的px 值, media query 对应devicePixelRatio 有个查询值

// -webkit-min-device-pixel-ratio, css 可以写成这样

// 通过-webkit-min-device-pixel-ratio 设置。

.border { border: 1px solid #999 }

@media screen and (-webkit-min-device-pixel-ratio: 2) {

.border { border: 0.5px solid #999 }

}

@media screen and (-webkit-min-device-pixel-ratio: 3) {

.border { border: 0.333333px solid #999 }

}

// 如果使用less/sass 的话只是加了1 句mixin

// 缺点: 安卓与低版本IOS 不适用, 这个或许是未来的标准写法, 现在不做指望

复制代码

  1. flexible.js

这是淘宝移动端采取的方案, 前面已经 说过1px 变粗的原因就在于一刀切的设置viewport 宽度, 如果能把viewport 宽度设置 为实际的设备物理宽度, css 里的1px 不就等于实际1px 长了么. flexible.js 就是这样 干的. <meta name=”viewport”>里面的scale 值指的是对ideal viewport 的缩放, flexible.js 检 测到IOS 机型, 会算出scale = 1/devicePixelRatio, 然后设置viewport

  1. 伪类+transform 实现

/** 对于解决1px 边框问题,我个人觉得最完美的解决办法还是伪类+transform 比较好。

原理:是把原先元素的border 去掉,然后利用:before 或者:after 重做border ,并

transform 的scale 缩小一半,原先的元素相对定位,新做的border 绝对定位。

media query

通过媒体查询,可以通过给不同分辨率的设备编写不同的样式来实现响应式的布局,比

如我们为不同分辨率的屏幕,设置不同的背景图片。比如给小屏幕手机设置@2x 图,为

大屏幕手机设置@3x 图,通过媒体查询就能很方便的实现。

但是媒体查询的缺点也很明显,如果在浏览器大小改变时,需要改变的样式太多,那么

多套样式代码会很繁琐。*/

@media screen and (min-width: 320px) {

html {

font-size: 50px;

}

}

@media

/** 方便应用广泛适用于pc 端手机页面,通常做自适应布局时我们比较常用。

缺点:相对于代码要重复很多,得知道设备的宽度,手机的分辨率很多所以麻烦了点,

不过性能方面肯定最高; 可能存在闪屏的问题

@media 处理手机和pc 端界面兼容的问题,在IE 上的访问出现问题,百度方法,找找

两种,一种是respond.js,另一种是

css3-mediaquerieshttp://blog.csdn.net/small_tu/article/details/47317453

*/

复制代码

手势事件

手势事件

事件详解

touchstart

当手指接触屏幕时触发 来代替 click 事件 来触发移动端的点击事件

touchmove

当手指接触屏幕时触发 代替 scroll 事件

touchend

当手指离开屏幕时触发 来代替 click 事件 来触发移动端的点击事件

2X 图3X 图适配

实际程序开发当中,我们代码中用的值是指逻辑分辨率pt,而不是像素分辨率px, 比如我们定义一个按钮的高度为45,这个45 指的是45pt 而不是45px。在非Retina 屏下1pt = 1px,4 和4.7 寸Retina 屏下1pt = 2px,5.5 和x 下1pt = 3px.我们制作不同尺寸的图片, 比如@1x 为22px,则@2x 为44px,@3x 为66px,命名分别为image.png,在项目的 Assets.xcassets 中新建New Image Set,修改名字为image,并把相应尺寸的图片拖放至相应位置。

/* 根据dpr 显示2x 图/3x 图*/

.bg-image(@url){

background-image:~“url(‘@{url}@2x.png’)”;

@media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3){

background-image:~“url(‘@{url}@3x.png’)”;

}

}

.bg-color(@color) {

background-color: @color;

}

复制代码

图片在安卓上,有些设备模糊问题

这个问题是 devicePixelRatio 的不同导致的,因为手机分辨率太小了,如果按照分辨率显示网页,字会非常小,所有苹果系统当初就把 iphone 4 的960x640像素的分辨率在网页里更改为480x320像素。这样是 devicePixelRatio = 2. 而 Android 的 devicePixelRatio 比较乱,值有1.5、2和3,为了在手机里更为清晰地显示图片, 必须使用2倍宽高的背景图来代替 img 标签(一般情况下都使用2倍) 例如:一个 div 的宽高是 100x100 背景图必须是200x200,然后设置 background-size:contain 样式,显示出来就比较清晰。

防止手机中页面放大和缩小

复制代码

transiton 闪屏

//设置内联的元素在3D 空间如何呈现:保留

3D-webkit-transform-style:preserve-3D;

//设置进行转换的元素的背面在面对用户时是否可见:隐藏

-webkit-backface-visibility:hidden;

复制代码

上下拉动滚动条时卡顿、慢

body {

-webkit-overflow-scrolling: touch;

overflow-scrolling:touch;

}

复制代码

长时间按住页面出现闪退

element{

-webkit-touch-callout: none;

}

复制代码

前端工程化


Babel 的原理是什么?

babel 的转译过程也分为三个阶段,这三步具体是:

  • 解析Parse: 将代码解析生成抽象语法树( 即AST ),即词法分析与语法分析的过程

  • 转换Transform: 对于AST 进行变换一系列的操作,babel 接受得到AST 并通babel-traverse 对其进行遍历,在此过程中进行添加、更新及移除等操作。

  • 生成Generate: 将变换后的AST 再转换为JS 代码, 使用到的模块是babel-generator

如何写一个babel 插件?

Babel 解析成AST,然后插件更改AST,最后由Babel 输出代码那么Babel 的插件模块需要你暴露一个function,function 内返回visitor

module.export = function(babel){

return {

visitor:{

}

}

}

复制代码

visitor 是对各类型的AST 节点做处理的地方,那么我们怎么知道Babel 生成了的 AST 有哪些节点呢?很简单,你可以把Babel 转换的结果打印出来

/** 这里我们看到const result = 1 + 2 中的1 + 1 是一个BinaryExpression 节点,那么在

visitor 中,我们就处理这个节点 */

var babel = require(‘babel-core’);

var t = require(‘babel-types’);

const visitor = {

BinaryExpression(path) {

const node = path.node;

let result;

// 判断表达式两边,是否都是数字

if (t.isNumericLiteral(node.left) && t.isNumericLiteral(node.right)) {

// 根据不同的操作符作运算

switch (node.operator) {

case “+”:

result = node.left.value + node.right.value;

break

case “-”:

result = node.left.value - node.right.value;

break;

case “*”:

result = node.left.value * node.right.value;

break;

case “/”:

result = node.left.value / node.right.value;

break;

case “**”:

let i = node.right.value;

while (–i) {

result = result || node.left.value;

result = result * node.left.value;

}

break;

default:

}

}

// 如果上面的运算有结果的话

if (result !== undefined) {

// 把表达式节点替换成number 字面量

path.replaceWith(t.numericLiteral(result));

}

}

};

module.exports = function (babel) {

return {

visitor

};

}

// 插件写好了,我们运行下插件试试

const babel = require(“babel-core”);

const result = babel.transform(“const result = 1 + 2;”,{

plugins:[

require(“./index”)

]

});

console.log(result.code); // const result = 3;

/** 与预期一致,那么转换const result = 1 + 2 + 3 + 4 + 5;呢?

结果是: const result = 3 + 3 + 4 + 5;

这就奇怪了,为什么只计算了1 + 2 之后,就没有继续往下运算了?

我们看一下这个表达式的AST 树

你会发现Babel 解析成表达式里面再嵌套表达式。

表达式( 表达式( 表达式( 表达式(1 + 2) + 3) + 4) + 5)

而我们的判断条件并不符合所有的,只符合1 + 2 */

// 判断表达式两边,是否都是数字

if (t.isNumericLiteral(node.left) && t.isNumericLiteral(node.right)) {}

/** 那么我们得改一改

第一次计算1 + 2 之后,我们会得到这样的表达式

表达式( 表达式( 表达式(3 + 3) + 4) + 5)

其中3 + 3 又符合了我们的条件, 我们通过向上递归的方式遍历父级节点

又转换成这样:

表达式( 表达式(6 + 4) + 5)

表达式(10 + 5)

15 */

// 如果上面的运算有结果的话

if (result !== undefined) {

// 把表达式节点替换成number 字面量

path.replaceWith(t.numericLiteral(result));

let parentPath = path.parentPath;

// 向上遍历父级节点

parentPath && visitor.BinaryExpression.call(this, parentPath);

}

/** 到这里,我们就得出了结果const result = 15;

那么其他运算呢: */

const result = 100 + 10 - 50>>>const result = 60;

const result = (100 / 2) + 50>>>const result = 100;

const result = (((100 / 2) + 50 * 2) / 50) ** 2>>>const result = 9;

复制代码

你的git 工作流是怎样的?

webpack 和gulp 区别(模块化与流的区别)

  • webpack 是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js 文件、css 文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。

  • gulp 强调的是前端开发的工作流程,我们可以通过配置一系列的task,定义task 处理的事务(例如文件压缩合并、雪碧图、启动server、版本控制等),然后定义执行顺序,来让gulp 执行这些task,从而构建项目的整个前端开发流程。

Vue


说说自己对vue的理解

Vue 是一个构建数据驱动的渐进性框架,它的目标是通过API 实现响应数据绑定和视图更新。 优点:

  1. 数据驱动视图,对真实dom 进行抽象出virtual dom(本质就是一个js 对象),并配合diff 算法、响应式和观察者、异步队列等手段以最小代价更新dom,渲染页面。

  2. 组件化,组件用单文件的形式进行代码的组织编写,使得我们可以在一个文件里编写html\css(scoped 属性配置css 隔离)\js 并且配合Vue-loader 之后,支持更强大的预处理器等功能。

  3. 由于采用虚拟dom,让Vue ssr 先天就足,强大且丰富的API 提供一系列的api 能满足业务开发中各类需求。

  4. 生命周期钩子函数,选项式的代码组织方式,写熟了还是蛮顺畅的,但仍然有优化空间(Vue3 composition-api)

缺点:

  1. 由于底层基于Object.defineProperty(vue3.0采用 new Proxy()) 实现响应式,而这个api 本身不支持IE8及以下浏览器

  2. csr 的先天不足,首屏性能问题(白屏)

  3. 由于百度等搜索引擎爬虫无法爬取js 中的内容,故spa 先天就对seo 优化心有余力不足(谷歌的puppeteer 就挺牛逼的,实现预渲染底层也是用到了这个工具)

什么是虚拟DOM?

虚拟dom 是相对于浏览器所渲染出来的真实dom 的,在react,vue 等技术出现之前, 我们要改变页面展示的内容只能通过遍历查询dom 树的方式找到需要修改的dom 然 后修改样式行为或者结构,来达到更新ui 的目的。 这种方式相当消耗计算资源,因为每次查询dom 几乎都需要遍历整颗dom 树,如果 建立一个与dom 树对应的虚拟dom 对象( js 对象),以对象嵌套的方式来表示dom 树,那么每次dom 的更改就变成了js 对象的属性的更改,这样一来就能查找js 对象 的属性变化要比查询dom 树的性能开销小。

vue 生命周期

vue 如何监听键盘事件?

// @keyup. 方法

<input ref=“myInput” type=“text” value=“hello world” autofocus

@keyup.enter=“handleKey”>

// addEventListener

复制代码

watch 怎么深度监听对象变化

deep 设置为true 就可以监听到对象的变化

let vm=new Vue({

el:“#first”,

data:{msg:{name:‘北京’}},

watch:{

msg:{

handler (newMsg,oldMsg){

console.log(newMsg);

},

immediate:true,

deep:true

}

}

})

复制代码

删除数组用delete 和Vue.delete 有什么区别?

  • delete:只是被删除数组成员变为empty / undefined,其他元素键值不变

  • Vue.delete:直接删了数组成员,并改变了数组的键值(对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开Vue 不能检测到属性被删除的限制)

watch 和计算属性有什么区别?

通俗来讲,既能用computed 实现又可以用watch 监听来实现的功能,推荐用computed, 重点在于computed 的缓存功能

computed 计算属性是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量 改变时,计算属性也会跟着改变;

watch 监听的是已经在data 中定义的变量,当该变量变化时,会触发watch 中的方法。

Vue 双向绑定原理

Vue 数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)。

说一下axios怎么用? 怎么解决跨域的问题?

axios 的是一种异步请求,用法和ajax 类似,安装npm install axios --save 即可使用,请 求中包括get,post,put, patch ,delete 等五种请求方式,解决跨域可以在请求头中添加 Access-Control-Allow-Origin,也可以在index.js 文件中更改proxyTable 配置等解决跨域 问题。

在vue 项目中如何引入第三方库(比如jQuery)?

// 1、绝对路径直接引入

// 在index.html 中用script 引入

// 然后在webpack 中配置external

externals: { ‘jquery’: ‘jQuery’ }

// 在组件中使用时import

import $ from ‘jquery’

// 2 、在webpack 中配置alias

resolve: { extensions: [‘.js’, ‘.vue’, ‘.json’], alias: { ‘@’: resolve(‘src’), ‘jquery’:

resolve(‘static/jquery-1.12.4.js’) } }
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

给大家分享一些关于HTML的面试题,有需要的朋友可以戳这里免费领取,先到先得哦。


能通过遍历查询dom 树的方式找到需要修改的dom 然 后修改样式行为或者结构,来达到更新ui 的目的。 这种方式相当消耗计算资源,因为每次查询dom 几乎都需要遍历整颗dom 树,如果 建立一个与dom 树对应的虚拟dom 对象( js 对象),以对象嵌套的方式来表示dom 树,那么每次dom 的更改就变成了js 对象的属性的更改,这样一来就能查找js 对象 的属性变化要比查询dom 树的性能开销小。

vue 生命周期

vue 如何监听键盘事件?

// @keyup. 方法

<input ref=“myInput” type=“text” value=“hello world” autofocus

@keyup.enter=“handleKey”>

// addEventListener

复制代码

watch 怎么深度监听对象变化

deep 设置为true 就可以监听到对象的变化

let vm=new Vue({

el:“#first”,

data:{msg:{name:‘北京’}},

watch:{

msg:{

handler (newMsg,oldMsg){

console.log(newMsg);

},

immediate:true,

deep:true

}

}

})

复制代码

删除数组用delete 和Vue.delete 有什么区别?

  • delete:只是被删除数组成员变为empty / undefined,其他元素键值不变

  • Vue.delete:直接删了数组成员,并改变了数组的键值(对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开Vue 不能检测到属性被删除的限制)

watch 和计算属性有什么区别?

通俗来讲,既能用computed 实现又可以用watch 监听来实现的功能,推荐用computed, 重点在于computed 的缓存功能

computed 计算属性是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量 改变时,计算属性也会跟着改变;

watch 监听的是已经在data 中定义的变量,当该变量变化时,会触发watch 中的方法。

Vue 双向绑定原理

Vue 数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)。

说一下axios怎么用? 怎么解决跨域的问题?

axios 的是一种异步请求,用法和ajax 类似,安装npm install axios --save 即可使用,请 求中包括get,post,put, patch ,delete 等五种请求方式,解决跨域可以在请求头中添加 Access-Control-Allow-Origin,也可以在index.js 文件中更改proxyTable 配置等解决跨域 问题。

在vue 项目中如何引入第三方库(比如jQuery)?

// 1、绝对路径直接引入

// 在index.html 中用script 引入

// 然后在webpack 中配置external

externals: { ‘jquery’: ‘jQuery’ }

// 在组件中使用时import

import $ from ‘jquery’

// 2 、在webpack 中配置alias

resolve: { extensions: [‘.js’, ‘.vue’, ‘.json’], alias: { ‘@’: resolve(‘src’), ‘jquery’:

resolve(‘static/jquery-1.12.4.js’) } }
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-y6t5t5H0-1713728557248)]

[外链图片转存中…(img-OLc4aiOf-1713728557249)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-4SpB7SgK-1713728557249)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-AKxuoBI1-1713728557249)]

最后

给大家分享一些关于HTML的面试题,有需要的朋友可以戳这里免费领取,先到先得哦。

[外链图片转存中…(img-FIfdCySL-1713728557250)]
[外链图片转存中…(img-kyNcumgz-1713728557250)]

《java面经-百度准入职老哥整理.pdf》是一份关于百度准入职面试的Java面经整理。这份面经是由百度准入职的老哥整理而成,其中记录了一些面试时可能会遇到的问题以及解答方法。 这份面经对于准备参加百度准入职面试的人来说非常有价值。首先,它列出了一些常见的面试问题,涵盖了Java语言的各个方面,包括基础知识、数据结构与算法、设计模式、多线程、网络编程等等。通过仔细研究和复习这些问题的答案,可以帮面试者全面了解Java语言的特性和应用。 其次,这份面经还提供了问题的解答思路和方法,帮面试者理清思路,正确回答问题。这对于很多面试者来说特别有帮,因为在面试时有时会遇到一些棘手的问题,有了这份面经的指导,面试者可以更好地掌握应对策略。 不过需要注意的是,面经作为一份参考资料,不能完全依赖于它来准备面试面试官可能会问一些不在面经中列出的问题,因此考生还是需要自己对Java语言有充分的了解,并能够熟练运用。同时,面试官还会关注考生的沟通能力、解决问题的能力以及对新技术的学习和掌握能力。 总体来说,《java面经-百度准入职老哥整理.pdf》是一份非常宝贵的资料,可以帮面试者对Java面试中可能会遇到的问题有更深入的了解,提供了解答思路和方法。但记住,面试准备还需要多方面的知识积累和实践经验的积累,才能在面试中展现自己的优势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值