前端面试题整理

147 阅读18分钟

一 HTML篇

1.你是怎么理解HTML语义化

​ 根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析。

​ 为了在没有CSS的情况下,页面也能呈现出很好地内容结构、代码结构:为了裸奔时好看;

​ 有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;

​ 用户体验:例如title、alt用于解释名词或解释图片信息、label标签的活用;

​ 便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页; ​ 便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。

2.你用过那些HTML5标签

​ 1.audio标签: HTML 元素用于在文档中嵌入音频内容。

​ 2.canvas标签:canvas元素创造了一个固定大小的画布,它公开了一个或多个渲染上下文,其可以用来绘制和处理要展示的内容。

​ 3. <article>标签规定独立的自包含内容

​ 4.<aside> 标签定义 article 以外的内容。aside 的内容应该与 article 的内容相关。

​ 5.<footer>

​ 6.<header>

​ 7.<section> 标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。

​ 8.<video> 标签定义视频,比如电影片段或其他视频流。

3.meta viewport 是作什么用的,怎么写?

​ 该meta标签的作用是让当前viewport的宽度等于设备的宽度

<meta name="viewport" content="width=device-width,initial-scale=1">

​ width设置layout viewport的宽度,为一个正整数,或字符串"width-device"

​ initial-scale设置页面的最大缩放值,为一个数字,可以带小数

4.<label>标签定义及用法

​ 在html中,<label>标签通常和<input>标签一起使用,<label>标签为input元素定义标注(标记)。

​ 5.行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

​ 行内元素:a、b、span、img、input、strong、select、label、em、button、textarea

​ 块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote

​ 空元素:即系没有内容的HTML元素,例如:br、meta、hr、link、input、img

6.a标签中 如何禁用href 跳转页面 或 定位连接

​ 当页面中a标签不需要任何跳转时,从原理上来讲,可分如下两种方法:

​ 标签属性href,使其指向空或不返回任何内容。

<a href="javascript:;" >点此无反应javascript:</a>
<a href="javascript:;" >点此无反应javascript:</a>
标签事件onclick,阻止其默认行为。如:
<a href="" onclick="return false;">return false;</a>
<a href="#" onclick="return false;">return false;</a>
7.canvas在标签上设置宽高 和在style中设置宽高有什么区别

​ 当我在canvas中设置宽高,相当于使用鼠标拖动了画布的边框使画布变大,但是里面的内容不会变化。当我在style中设置了宽高,相当于点击放大镜对整个图像进行方法,使得里面的内容也会跟着变化。

8.你作的页面在哪些流览器测试过?这些浏览器的内核分别是什么?

​ 1.Trident内核代表产品Internet Explorer,又称其为IE内核。

​ 2.WebKit内核代表作品Safari、Chromewebkit

​ 3.Gecko内核代表作品Mozilla

9.iframe有哪些缺点?

​ 1.iframe会阻塞主页面的Onload事件;

​ 2.iframe和主页面共享链接池,而浏览器对相同城的链接有限制,所以会影响页面的并行加载;

​ 3.不利于seo

​ 4.代码复杂,无法一下被搜索引擎索引到

​ 5.iframe框架页面会增加服务器的http请求,对于大型网站不可取

​ 6.很多的移动设备无法完全显示框架,设备兼容性差

10.HTML5离线储存

​ HTML5提出了两大离线存储技术:localstorage与Application Cache,两者各有应用场景;传统还有离线存储技术为Cookie。

​ 而cookie只能保存一小段文本(4096字节);所以不能存储大数据,这是cookie与上述缓存技术的差异之一,而因为HTTP是无状态的,服务器为了区分请求是否来源于同一个服务器,需要一个标识字符串,而这个任务就是cookie完成的,这一段文本每次都会在服务器与浏览器之间传递,以验证用户的权限。

​ Application Cache带来的三个优势是:

​ ① 离线浏览

​ ② 提升页面载入速度

​ ③ 降低服务器压力

​ 11.Doctype作用是什么?

		<!DOCTYPE>声明叫做文件类型定义(DTD),声明的作用为了告诉浏览器该文件的类型。让浏览器解析器知道应该用哪个规范来解析文档。<!DOCTYPE>声明必须在 HTML 文档的第一行,这并不是一个 HTML 标签。

二 CSS篇

​ 1.ie盒模型算上border、padding及自身(不算margin),标准的只算上自身窗体的大小 css设置方法以

标准/W3C盒子模型的范围包括 margin border padding content 并且content不包含其他部分。

IE盒子模型的范围也包括marginborderpaddingcontent,不同于标准盒子的是,IE盒子的content包含了paddingborder部分

​ 2.拓展各种获得宽高的方式 :

​ 获取屏幕的高度和宽度(屏幕分辨率): window.screen.height/width ​ 获取屏幕工作区域的高度和宽度(去掉状态栏): window.screen.availHeight/availWidth ​ 网页全文的高度和宽度: document.body.scrollHeight/Width ​ 滚动条卷上去的高度和向右卷的宽度: document.body.scrollTop/scrollLeft ​ 网页可见区域的高度和宽度(不加边线): document.body.clientHeight/clientWidth

​ 网页可见区域的高度和宽度(加边线): document.body.offsetHeight/offsetWidth

​ 3.BFC与边距重叠详解

BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

​ 哪些元素会生成BFC?

1. 根元素 <html>
2. float属性不为none
3. position为absolute或fixed
4. display为inline-block, table-cell, table-caption, flex, inline-flex
5. overflow不为visible

​ margin collapse(边距坍塌&边距重叠)

​ 4.css reset和normalize.css有什么区别:

​ Normalize 相对「平和」,注重通用的方案,重置掉该重置的样式,保留有用的 user agent 样式,同时进行一些 bug 的修复,这点是 reset 所缺乏的。

​ Reset 相对「暴力」,不管你有没有用,统统重置成一样的效果,且影响的范围很大,讲求跨浏览器的一致性。

​ 5.css 居中方法:

​ 块级元素 margin: 0 auto

​ 行内元素:text-align:center

​ 绝对居中:

1、兼容性不错的主流css绝对定位居中的用法:
    .conter{
    width:600px;height:400px;
    position:absolute;left:50%;top:50%;
    margin-top:-200px;/*高度的一半*/
    margin-left:-300px;/*宽度的一半*/
    }
    //css3 transform
    .conter{
    width:600px;height:400px;
    position:absolute;left:50%;top:50%;
    transform:translate(-50%,-50%);/*50%为自身尺寸的一半*/
    }
    使用css3盒模型:flex布局实现css绝对定位居中。

​ 6.css样式优先级

​ 通用选择器(*) < 元素(类型)选择器 < 类选择器 < 属性选择器 < 伪类 < ID 选择器 < 内联样式

​ 7.css清除浮动

​ 浮动产生负作用=》 背景不能显示 =》边框不能撑开 =》margin padding设置值不能正确显示

​ css解决浮动,清除浮动方法 1.父级设置高度 2.clear:both 3.父级定义 父级div定义 overflow:hidden

8..link@import导入css

**link语法结构**
<link href="CSSurl路径" rel="stylesheet" type="text/css" />
此标签是引入CSS文件link标签,只要设置好路径即可。
@import语法结构
@import + 空格+ url(CSS文件路径地址);

9. css优化方案

1、缩写css代码。 2、排列css代码。 3、同属性提取共用css选择器。 4、分离网页颜色和背景设置样式(较大站点需要注意)。 5、条理化css代码。

  1. display:none和visibility:hidden的区别

    1. 如果给一个元素设置了display: none,那么该元素以及它的所有后代元素都会隐藏
    2. 给元素设置visibility: hidden也可以隐藏这个元素,但是隐藏元素仍需占用与未隐藏时一样的空间,也就是说虽然元素不可见了,但是仍然会影响页面布局。
  2. CSS的盒子模型

    1. 一个盒子中主要的属性就5个:width、height、padding、border、margin。

三 JavaScript篇

​ 优点:极高的扩展性和可用性

​ 1.数据持久性

​ 2.不需要任何服务器资源。Cookie 存储在客户端并在发送后由服务器读取。

​ 3.可配置到期规则。 控制 cookie 的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的 cookie 。

​ 4.简单性。 基于文本的轻量结构。

​ 5.通过良好的编程,控制保存在cookie中的session对象的大小。

​ 6.通过加密和安全传输技术(SSL),减少cookie被破解的可能性。

​ 7.只在cookie中存放不敏感数据,即使被盗也不会有重大损失。

​ 缺点:

​ 1.Cookie`数量和长度的限制

​ 2.数量:每个domain的 cookie 总数有限。

​ 3.长度:每个 cookie 长度不超过 4KB ( 4096B ),否则会被截掉

​ 4.潜在的安全风险 。Cookie 可能被拦截、篡改。如果 cookie 被拦截,就有可能取得所有的 session 信息。

​ 5.用户配置为禁用 。有些用户禁用了浏览器或客户端设备接受 cookie 的能力,因此限制了这一功能。

​ 6.有些状态不可能保存在客户端。

​ 7.cookie在每次发送http请求时,都会被发送到服务器,一些不必要的信息也会被发送过去,造成不必要的浪费

2.JavaScript中的Array.prototype.slice.call()

​ JavaScript中的Array.prototype.slice.call(arguments)能将有length属性的对象转换为数组(特别注意: 这个对象一定要有length属性). 但有一个例外,IE下的节点集合它不能转换

3.简单说一下浏览器本地存储是怎样的

​ html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage。

​ sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。

​ 而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

3.构造函数、原型与实例之间的关系

​ 每创建一个函数,该函数就会自动带有一个 prototype 属性。该属性是个指针,指向了一个对象,我们称之为 原型对象

​ 原型链:每个对象都有一个__proto__对象,对向了该构造函数的原型对象,js万物皆对象,所以通过递归的方式去查找一个对象属性,会从当前对象一直查到最顶级(null)。__proto__会指向上一层的原型对象,而上一层的结构依然类似,那么就利用__proto__一直指向Object的原型对象上!Object.prototype.proto = null;表示到达最顶端。如此形成了原型链继承。

4.执行上下文

​ 当代码运行时,会产生一个对应的执行环境,在这个环境中,所有变量会被事先提出来(变量提升),有的直接赋值,有的为默认值 undefined,代码从上往下开始执行,就叫做执行上下文。

​ 1.单线程,在主进程上运行

  2.同步执行,从上往下按顺序执行

  3.全局上下文只有一个,浏览器关闭时会被弹出栈

  4.函数的执行上下文没有数目限制

  5.函数每被调用一次,都会产生一个新的执行上下文环境

  1. 闭包

    由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

    闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

    闭包的使用场景 1.setTimeout 2.函数防抖 3.封装私有变量

    6.对象的拷贝

    ​ 1.json方法 JSON对象的深度克隆。方法是先JSON.stringify() 转为json字符串, 再JSON.parse() 转为json数组

    ​ 缺点:a. 如果你的对象里有函数, 函数无法被拷贝下来 b. 无法拷贝copyObj对象原型链上的属性和方法

    ​ 2.Object.create()方法 复制对象存在于Object原型prototype中

    ​ 3.for循环遍历方法

    7.new运算符的执行过程

    ​ 1.创建一个空对象

    ​ 2.让Person中的this指向obj,并执行Person的函数体

    ​ 3.设置原型链,将obj的__proto__成员指向了Person函数对象的prototype成员对象

    ​ 4.判断Person的返回值类型,如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。

    8.instanceof原理

    一、作用:

    ​ 用于判断某个实例是否属于某构造函数

    ​ 在继承关系中用来判断一个实例是否属于它的父类型或者祖先类型的实例

    9.js 继承

    想要继承就必须提供父类

    //父类
    function Person(name) {
    	this.name = name;
    	this.sum = function() {
    		console.log(this.name)
    	}
    }
    Person.prototype.age = 10
    

    ​ 一、原型链继承

    ​ 让新实例的原型等于父类的实例。

    function Per() {
    	this.name = 'Ker'
    }
    Per.prototype = new Person()
    var per1 = new Per()
    console.log(per1.age)  //10
    

    ​ 1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)

    ​ 缺点:1、新实例无法向父类构造函数传参。        2、继承单一。        3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)

    二、借用构造函数继承

    function Con() {
    	Person.call(this,'jer')
    	this.age = 12
    }
    var con1 = new Con()
    console.log(con1.name)  //jer
    

    重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))

    特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。        2、解决了原型链继承缺点1、2、3。        3、可以继承多个构造函数属性(call多个)。        4、在子实例中可向父实例传参。     缺点:1、只能继承父类构造函数的属性。        2、无法实现构造函数的复用。(每次用每次都要重新调用)        3、每个新实例都有父类构造函数的副本,臃肿。

    ​ 三、组合继承

    function SubType(name) {
    	Person.call(this, name)
    }
    SubType.prototype = new Person()
    var sub = new SubType('gar')
    console.log(sub.name) //gar
    

    重点:结合了两种模式的优点,传参和复用     特点:1、可以继承父类原型上的属性,可以传参,可复用。        2、每个新实例引入的构造函数属性是私有的。     缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。

    四、原型继承

function content(obj){
	function F(){}
	F.prototype = obj; 继承了传入的参数
	return new F() //返回构造函数对象
}

重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。     特点:类似于复制一个对象,用函数来包装。     缺点:1、所有实例都会继承原型上的属性。        2、无法实现复用。(新实例属性都是后面添加的)

​ 五、寄生式继承

function content(obj){
	function F(){}
	F.prototype = obj;//继承传入的参数
	return new F()//返回函数对象
}
var sup = new Person() //拿到父类的实例
function subobject(obj){
var sub = content(obj)
sub.name = 'gar'
return sub
}
var sup2 = subobject(sup)
console.log(typeof subobject) //function

重点:就是给原型式继承外面套了个壳子。     优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。     缺点:没用到原型,无法复用。

六、寄生组合式继承

​ 寄生:在函数内返回对象然后调用   组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参 

​ 重点:修复了组合继承的问题

function content(obj) {
function F(){}
F.prototype = obj
reutrn new F()
}
var con = content(Person.prototype)
function Sub() {
	Person.call(this)
}
Sub.prototype = con
con.constructor = SUb
var sub1 = new Sub()
console.log(sub1.age) // 10

七。JS强制类型转换和隐式类型转换

​ 1.隐式类型转换 运算符 +-*/ ++ -- > < !

​ 2.强制类型转换

​ 使用Number()函数将参数转换为一个数字

​ 使用parseInt()函数将参数转换为一个整数

​ 使用parseFloat()函数将参数转换为一个浮点数

八、1: typeof

​ 返回数据类型,包含这7种: number、boolean、symbol、string、object、undefined、function。

​ typeof null 返回类型错误,返回object

​ 引用类型,除了function返回function类型外,其他均返回object。

2.toString 这个是最完美的

​ toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

3.constructor

​ constructor是原型prototype的一个属性,当函数被定义时候,js引擎会为函数添加原型prototype,并且这个prototype中constructor属性指向函数引用, 因此重写prototype会丢失原来的constructor。

4.instanceof

​ instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型

九、js模块化

​ 模块化开发是一种管理方式,是一种生产方式,一种解决问题的方案,一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块,但是模块开发需要遵循一定的规范,否则就都乱套了,因此,才有了后来大家熟悉的AMD规范,CMD规范

十、js防抖和节流

​ 在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。

十一、js this

​ call()和apply()

​ 这两个方法都是函数对象的方法,需要通过函数对象来调用

-当对函数调用call()和apply()都会调用函数执行

-在调用call()和apply()可以将一个对象指定为第一个参数此时这个对象将会成为函数执行时的this

此时这个对象将会成为函数执行时的this

-可以用来指定函数的上下文对象

-call()方法可以将实参在对象之后依次传递

-apply()方法需要将实参封装到一个数组中统一传递

this的情况:

1.以函数形式调用时,this永远都是window

2.以方法的形式调用时,this是调用方法的对象

3.以构造函数的形式调用时,this是新创建的那个对象

4.使用call和apply调用时,this是指定的那个对象

bind和call()、apply()的区别

​ bind返回的是一个函数的调用,是永久改变,call和apply是一次性的调用

​ 第一个参数都是this的指向对象,call的参数是直接放进去的,第二个和第n个用,区分

​ bind的参数和call一样,apply第二个参数是一个数组

十二、ES6常用新特性

  • let && const
  • iterable类型
  • 解构赋值
  • =>函数
  • ...操作符

十三、babel的工作原理

babel是一个转译器,感觉相对于编译器compiler,叫转译器transpiler更准确,因为它只是把同种语言的高版本规则翻译成低版本规则,而不像编译器那样,输出的是另一种更低级的语言代码。 但是和编译器类似,babel的转译过程也分为三个阶段:parsing、transforming、generating,以ES6代码转译为ES5代码为例 ES6=》babylon进行解析=》得到AST

pulgin用babel-traverse对AST进行遍历转义,得到新的AST

用babel-generator通过AST树生产ES5代码

十四、函数科里化

​ 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

十五、什么是事件流

​ 事件流描述的是从页面中接收事件的顺序

1、DOM事件流

“DOM2级事件”规定的事件流包括三个阶段:

① 事件捕获阶段;

② 处于目标阶段;

③ 事件冒泡阶段

十六、事件委托

1.减少事件注册,节省内存,例如 在table上代理所有td的click事件. 在ul上代理所有li的click事件.

2.简化了dom节点更新时,相应事件的更新 不用在新添加的li上绑定click事件. 当删除某个li时,不用移解绑上面的click事件.

十七、懒加载和预加载

​ 懒加载也叫延迟加载

第一种是纯粹的延迟加载,使用setTimeOut或setInterval进行加载延迟.

第二种是条件加载,符合某些条件,或触发了某些事件才开始异步下载。

第三种是可视区加载,即仅加载用户可以看到的区域,这个主要由监控滚动条来实现,一般会在距用户看到某图片前一定距离遍开始加载,这样能保证用户拉下时正好能看到图片。

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

预加载可以说是牺牲服务器前端性能,换取更好的用户体验,这样可以使用户的操作得到最快的反映。实现预载的方法非常多,可以用CSS(background)、JS(Image)、HTML()都可以。常用的是new Image();设置其src来实现预载,再使用onload方法回调预载完成事件。

十八、mouseover和mouseenter的区别

​ avascript中mouseover和mouseenter的区别主要在于监听对象的子元素是否触发事件。mouseover:鼠标移入监听对象中,或者从监听对象的一个子元素移入另一个子元素中时触发该事件。mouseenter:鼠标移入监听对象时触发,在监听对象内移动不会触发。

十九、ajax中浏览器的缓存问题解决方法

ajax能提高页面载入的速度主要原因是通过ajax减少了重复数据的载入,也就是说在载入数据的同时将数据缓存到内存中,一旦数据被加载其中,只要我们没有刷新页面,这些数据就会一直被缓存在内存中,当我们提交的URL与历史的URL一致时,就不需要提交给服务器,也就是不需要从服务器上面获取数据,虽然这样降低了服务器的负载提高了用户的体验,但是我们不能获取最新的数据。为了保证我们读取的信息都是最新的,我们就需要禁止他的缓存功能。

二十、JS中的垃圾回收机制

JavaScript 中的内存管理是自动执行的,而且是不可见的。

在js中,垃圾回收器每隔一段时间就会找出那些不再使用的数据,并释放其所占用的内存空间。

以全局变量和局部变量来说,函数中的局部变量在函数执行结束后这些变量已经不再被需要,所以垃圾回收器会识别并释放它们。而对于全局变量,垃圾回收器很难判断这些变量什么时候才不被需要,所以尽量少使用全局变量。

那么垃圾回收器是如何检测变量是否需要的呢,大体上分为两种检测手段,引用计数与标记清除。

引用计数的判断原理很简单,就是看一份数据是否还有指向它的引用,如果没有任何对象再指向它,那么垃圾回收器就会回收

标记清除的概念也好理解,从根部出发看是否能达到某个对象,如果能达到则认定这个对象还被需要,如果无法达到,则释放它