blog
blog copied to clipboard
前端工程师面试题合集
Table of Contents generated with DocToc
-
前端工程师面试题合集
-
HTML
-
如何理解
HTML
语义化 - 块状元素 & 内联元素
-
如何理解
-
CSS
-
什么是盒模型,请根据盒模型计算下面
div1
的offsetWidth
-
下面代码中
AAA
元素与BBB
元素之间的距离是多少? -
margin
属性设置负值会有什么影响? - BFC的理解和应用
- float布局
- 手写 clearfix
- 使用 flex 画三点骰子
- relative 和 absolute 定位
- 居中对齐的实现方式
- line-height 继承的问题
- rem是什么? 如何利用它来做响应式
-
什么是盒模型,请根据盒模型计算下面
-
JavaScript
- 值类型和引用类型
- typeof 能判断哪些类型
- 类型转换
- 何时使用 ===, 何时使用 ==
- 值类型和引用类型的区别
- 手写深拷贝
-
HTML
前端工程师面试题合集
HTML
如何理解HTML
语义化
-
让人更容易读懂(增加代码可读性)
-
让搜索引擎更容易读懂(SEO)
块状元素 & 内联元素
-
块状元素:
display: block
或者display: table
,有div
、h1
、h2
、table
、ul
、ol
、p
等, 它们都会在浏览器中独占一行 -
内敛元素:
display: inline
或者display: inline-block
,有span
、img
、input
、button
等,它们不会独占一行,根据其宽度依次排列,直到换行
CSS
什么是盒模型,请根据盒模型计算下面 div1
的 offsetWidth
<!-- 如下代码,请问 div1 的 offsetWidth 是多大? -->
<style>
#div1 {
width: 100px;
padding: 10px;
border: 1px solid #ccc;
margin: 10px;
}
</style>
<div id="div1"></div>
CSS
盒子模型(Box Model
) 所有 HTML
元素可以看作盒子,在 CSS
中,"box model"这一术语是用来设计和布局时使用。 CSS
盒模型本质上是一个盒子,封装周围的 HTML
元素,它包括:边距,边框,填充,和实际内容。
offsetWidth
= (内容宽度 + 内边距 + 边框), 无外边距,因此答案是 122px
如果为此元素增加 box-sizing
属性,并设置其值为: border-box
,则其宽度为 100px
#div1 {
width: 100px;
padding: 10px;
border: 1px solid #ccc;
margin: 10px;
box-sizing: boder-box;
}
下面代码中 AAA
元素与 BBB
元素之间的距离是多少?
<!-- 如下代码,AAA 和 BBB 之间的距离是多少 -->
<style>
p {
font-size: 16px;
line-height: 1;
margin-top: 10px;
margin-bottom: 15px;
}
</style>
<p>AAA</p>
<p></p>
<p></p>
<p></p>
<p>BBB</p>
-
相邻元素的
margin-top
和margin-bottom
会发生重叠 -
空白内容的
<p></p>
也会发生重叠
所以答案是 15px
margin
属性设置负值会有什么影响?
-
margin-top
和margin-left
负值,元素向上、向左移动 -
margin-right
负值,右侧元素左移,自身不受影响 -
margin-bottom
负值,下方元素上移,自身不受影响
BFC的理解和应用
BFC
全称为 Block Format Context
,块级格式化上下文,它是一块独立渲染的区域,内部元素的渲染不会影响边界以外的元素
形成 BFC
的常见条件如下:
-
float
不是none
-
position
是absolute
或fixed
-
overflow
不是visible
-
display
是flex
或inline-block
BFC
常见的用于清除浮动,下面是一个例子
<style>
.container {
background-color: #f1f1f1;
}
.left {
float: left;
}
</style>
<div clas="container">
<img src="http://img.xxx.com/logo.png" class="left" />
<p>这里是一段文字...</p>
</div>
上面代码展示的效果是图片脱离的文档流,p
标签占满一行,很难看,这时我们只需要设置 BFC
,这里我们增加一个 css
属性 overflow
, 并在容器中增加即可解决
<style>
.container {
background-color: #f1f1f1;
}
.left {
float: left;
}
.bfc {
overflow: hidden; /* 启用 BFC */
}
</style>
<div clas="container bfc">
<img src="http://img.xxx.com/logo.png" class="left" />
<p class="bfc">这里是一段文字...</p>
</div>
float布局
圣杯布局和双飞翼布局的目的:
-
三栏布局,中间一栏最先加载和渲染(内容最重要)
-
两侧内容固定,中间内容随着宽度自适应
-
一般用于PC网页
圣杯布局和双飞翼布局的技术总结:
-
使用
float
布局 -
两侧使用
margin
负值,以便和中间内容横向重叠 -
防止中间内容被两侧覆盖,一个用
padding
,一个用margin
圣杯布局演示代码如下:
<style>
body {
min-width: 550px;
}
#header {
text-align: center;
background-color: #f1f1f1;
}
#center {
background-color: #ccc;
width: 100%;
}
#left {
position: relative; /* 浮动基于自身 */
background-color: yellow;
width: 200px;
margin-left: -100%; /* 使用负值设定左边区域距离边界100% */
right: 200px;
}
#right {
background-color: red;
width: 150px;
margin-right: -150px; /* 使用负值 */
}
#footer {
text-align: center;
background-color: #f1f1f1;
clear: both; /* 清除浮动 */
}
#container {
/* 设定中间内容区域距离左右的padding */
padding-left: 200px;
padding-right: 150px;
}
#container .column {
float: left; /* 所有结构元素浮动 */
}
</style>
<body>
<div id="header">this is header</div>
<div id="container">
<div id="center" class="column">this is center</div>
<div id="left" class="column">this is left</div>
<div id="right" class="column">this is right</div>
</div>
<div id="footer">this is footer</div>
</body>
双飞翼布局代码如下:
<style type="text/css">
body {
min-width: 550px;
}
.col {
float: left;
}
#main {
width: 100%;
height: 200px;
background-color: #ccc;
}
#main-wrap {
margin: 0 190px 0 190px;
}
#left {
width: 190px;
height: 200px;
background-color: #0000FF;
margin-left: -100%;
}
#right {
width: 190px;
height: 200px;
background-color: #FF0000;
margin-left: -190px;
}
</style>
<body>
<div id="main" class="col">
<div id="main-wrap">
this is main
</div>
</div>
<div id="left" class="col">
this is left
</div>
<div id="right" class="col">
this is right
</div>
</body>
手写 clearfix
/* 手写 clearfix */
.clearfix:after {
content: '';
display: table;
clear: both;
}
使用 flex 画三点骰子
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>flex 画骰子</title>
<style type="text/css">
.box {
width: 200px;
height: 200px;
border: 2px solid #ccc;
border-radius: 10px;
padding: 20px;
display: flex; /* 设置为flex */
justify-content: space-between; /* 两端对齐 */
}
.item {
display: block;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #666;
}
.item:nth-child(2) {
align-self: center; /* 中间的点上下左右居中 */
}
.item:nth-child(3) {
align-self: flex-end; /* 右边的点纵向尾对齐 */
}
</style>
</head>
<body>
<div class="box">
<span class="item"></span>
<span class="item"></span>
<span class="item"></span>
</div>
</body>
</html>
relative 和 absolute 定位
-
relative
依据自身定位 -
absolute
依据最近一层的定位元素定位,定位元素就是aboslute
、relative
、fixed
或body
居中对齐的实现方式
水平居中:
-
inline
元素:text-align: center
-
block
元素:margin: auto
-
absolute
元素:left: 50%
+margin-left
负值
垂直居中:
-
inline
元素: 设置line-height
的值等于height
的值 -
absolute
元素:top: 50%
+margin-top
负值,此方法必须要知道子元素的宽高 -
absolute
元素:transform(-50%, -50%)
-
absolute
元素: 设置top
、left
、bottom
、right
为0, 然后设置margin: auto
line-height 继承的问题
如果一个元素的父元素设置了 line-height
属性,则其子元素都会继承这个属性,它有如下情况:
-
写具体的数值,如:
30px
,则直接继承该值 -
写比例, 如:
2 / 1.5
,则继承该比例 -
写百分比,如:
200%
,则继承计算出来的值(考点)
<style type="text/css">
body {
font-size: 20px;
/* line-height: 50px; 下面的子元素p的line-height为50px */
/* line-height: 1.5; 下面的子元素p的line-height为24px 16 * 1.5 */
line-height: 200%; /* 下面的p标签的line-height为40px,直接在父元素上计算后继承到p标签 20px * 200% */
}
p {
background-color: #ccc;
font-size: 16px;
}
</style>
rem是什么? 如何利用它来做响应式
rem
是一个长度单位
-
px
,绝对长度单位,最常用 -
em
,相对长度单位,相对于父元素,不常用 -
rem
,相对长度单位,相对于根元素,常用于响应式
如果使用 rem
来做响应式?
我们可以利用 css3
属性 media-query
, 根据不同的屏幕宽度设置根元素的 font-size
属性,然后再使用 rem
基于根元素的相对单位来定义元素尺寸
<style type="text/css">
@media only screen and (max-width: 374px) {
/* iphone5 或者更小的尺寸,以 iphone5 的宽度(320px)比例设置 font-size */
html {
font-size: 86px;
}
}
@media only screen and (min-width: 375px) and (max-width: 413px) {
/* iphone6/7/8 和 iphone x */
html {
font-size: 100px;
}
}
@media only screen and (min-width: 414px) {
/* iphone6p 或者更大的尺寸,以 iphone6p 的宽度(414px)比例设置 font-size */
html {
font-size: 110px;
}
}
body {
font-size: 0.16rem;
}
#div1 {
width: 1rem;
background-color: #ccc;
}
</style>
JavaScript
类型
值类型和引用类型
-
值类型:
undefined
、string
、number
、boolean
、symbol
-
引用类型:
object
、array
、null
、function
typeof 能判断哪些类型
- 能识别所有的值类型
let a;
const str = 'abc';
const n = 100;
const b = true;
const s = Symbol('s');
typeof a; // undefined
typeof str; // string
typeof n; // number
typeof b; // boolean
typeof s; // symbol
- 识别函数
typeof console.log // function
typeof function() {} // function
- 判断是否是引用类型(无法进行下一步细分判断)
typeof null // object
typeof ['a', 'b'] // object
typeof { x: 100 } // object
类型转换
const a = 100 + 10 // 110
const b = 100 + '10' // 10010
const c = true + 10 // true10
在使用 ==
进行计算时也会发生类型转换
// 下面使用 == ,发生错误的情况
100 == '100' // true
0 == '' // true
0 == false // true
false == '' // true
null == undefined // true
何时使用 ===, 何时使用 ==
除了 == null
之外,其他情况一律使用 ===
, 例如:
const obj = { x: 100 }
if (obj.a == null) {
// ...
}
// 相当于:
// if (obj.a === null || obj.a === undefined) {}
值类型和引用类型的区别
const obj1 = { x: 100, y: 200 }
const obj2 = obj1
let x1 = obj1.x // 干扰部分..
obj2.x = 101
x1 = 102 // 干扰部分..
console.log(obj1) // { x: 101, y: 200 }
手写深拷贝
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// 保证 key 不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用!!!
result[key] = deepClone(obj[key])
}
}
// 返回结果
return result
}
原型和原型链
在 ES6
之前的 ES3
、ES5
都是基于构造函数来实现继承的,而构造函数具有原型属性,目前 ES6
已普及,故这里使用 ES6
的 class
语法糖来理解 JavaScript
中的原型和原型链
在面向对象编程模型中, class
是一个非常重要的概念,我们可以把它理解成某种事物的模板,在这个模板中我们可以定义属性和方法
-
constructor
构造函数,在实例化对象时执行 -
属性
-
方法
但 Javascript
中的 class
并不是 Java
、C++
这些编译型语言中的 class
,它只是一个语法糖,本质上,它还是一个函数,这样我们理解起来容易,下面是例子:
// 声明学生类
class Student {
// 构造函数
constructor(name, number) {
this.name = name;
this.number = number;
}
// 方法
sayHi() {
console.log(`姓名: ${this.name}, 学号: ${this.number}`)
}
}
// 实例化
const xialuo = new Student('夏洛', 100);
console.log(xiaoluo.name); // 夏洛
console.log(xiaoluo.number); // 100
xiaoluo.sayHi() // 姓名: 夏洛, 学号: 100
ES6
通过 extends
关键字实现继承,子类中需要使用 super
方法来执行父类的构造方法,然后就可以扩展或重写方法
// 声明父类
class People {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} eat something`)
}
}
// 子类 学生
class Student extends People {
constructor(name, number) {
super(name);
this.number = number;
}
sayHi() {
console.log(`姓名: ${this.name}, 学号: ${this.number}`);
}
}
// 子类 老师
class Teacher extends People {
constructor(name, major) {
super(name);
this.major = major;
}
teach() {
console.log(`${this.name} 教授 ${this.major}`)
}
}
// 实例化学生
const xialuo = new Student('夏洛', 100);
console.log(xiaoluo.name); // 夏洛
console.log(xiaoluo.number); // 100
xiaoluo.eat(); // 夏洛 eat something
xiaoluo.sayHi(); // 姓名: 夏洛, 学号: 100
// 实例化老师
const wanglaoshi = new Teacher('王老师', '语文');
console.log(wanglaoshi.name); // 王老师
console.log(wanglaoshi.number); // 语文
wanglaoshi.eat(); // 王老师 eat something
wanglaoshi.teach(); // 王老师 教授 语文
通过 instanceof
关键字判断实例,实际上就是通过原型来判断
xialuo instanceof Student; // true
xialuo instanceof People; // true
xialuo instanceof Object; // true 所有类都是 Object 的子类
[] instanceof Array; // true
[] instanceof Object; // true
{} instanceof Object; // true
class
实际上就是函数,是一个语法糖
typeof People; // 'function'
typeof Student; // 'function'
每一个构造函数(class
)在创建时都会有一个显式原型,每一个实例都有一个隐式原型,而实例的隐式原型都指向创建它的类(class
)的显式原型
xialuo.__proto__ // 隐式原型
Student.prototype // 显式原型
xialuo.__proto__ === Student.prototype // true
原型的关系如下:
-
每个
class
都有显式原型prototype
-
每个实例都有隐式原型
__proto__
-
实例的隐式原型
__proto__
对应其class
的显式原型prototype
如何判断一个变量是数组
a instanceof Array
(原型链原理)