前段面试笔记
HTML面试题篇
如何理解HTML语义化标签?
- 是什么:语义化标签是一种写HTML标签的方法论/方式
- 怎么做:实现方法是遇到标题就用h1到h6,遇到段落用p,遇到文章用article,主要内容用main,边栏用aside,导航用nav
- 解决了什么问题:明确了HTML的书写规范
- 优点是:1、适合搜索引擎搜索,2、适合人类阅读,利于团队维护
总结:是什么、怎么做、解决了什么问题,优点是、缺点是、怎么解决缺点。
HTML新增了那些标签?
- 文章相关:header(标题)、main(主要的)、footer(页脚)、nav、section(部分)、article(文章)、figure(图形)、mark(标记)
- 媒体相关:video(视频)、audio(音频)、svg、cannas
- 表单相关:type=email type=tel
总结:MDN把所有标签都列在这里
Canvas和svg的区别是什么?
答题思路为:先说一,在说二,在说相同点,最后说不同点
- Canvas主要是用笔刷绘制2D图形的
- SVG主要使用标签来绘制不规则的矢量图
- 相同点:都是主要用来画2D图形的
- 不同点:Canvas画的是位图,SVG画的是矢量图
- 不同点:SVG节点过多是渲染慢,Canvas性能更好一点,但是写起来更复杂。
- 不同点:SVG支持分层和事件,Canvas不支持,但是可以用库实现
总结:位图、矢量图、渲染性能、石峰支持分层和事件
Css面试题篇
BFC 是什么?
- 是什么:BFCs是块级格式化上下文
- 怎么做:背通BFC触发条件,MDN的BFC触发条件文章,记录几个触发条件
- 浮动元素(元素的float不是none)
- 绝对定位元素(元素的position为absolute或fixed)
- 行内块inline block元素
- overflow值不为visible的块元素
- 弹性元素(display为flex或inline-flex元素的直接子元素)
解决了什么问题?
- 清除浮动
- 防止margin合并
- 某些古老的布局方式会用到(已过时)
优点:无
缺点:有副作用
怎样解决缺点:使用最新的 disp.ay:flow-root来触发BFC就没有副作用
如何实现垂直居中?
如果 .parent 的 height 不写,你只需要 padding: 10px 0; 就能将 .child 垂直居中;
如果 .parent 的 height 写死了,就很难把 .child 居中,以下是垂直居中的方法。
忠告:能不写 height 就千万别写 height。
七种方式实现垂直居中
- table自带功能(table表格中td自动垂直居中)
- 100% 高度的 afrer before 加上 inline block 这个方法还有一个优化版本
- div 装成 table
- margin-top -50%
- absolute margin auto
- flex( justify-content: center; align-items: center;)
得分点:flex 方案、grid 方案、transform 方案……
CSS选择器优先级如何确定?
比较详细的博客文章
简单的总结记住三句话
- 选择器越具体,其优先级越高
- 相同优先级,出现在后面的,覆盖前面的
- 属性后面加 !important 的优先级最高,但是要少用
如何清除浮动?
方法一,给父元素加上 .clearfix
.clearfix:after{
content: '';
display: block; /*或者 table*/
clear: both;
}
方法二,给父元素加上 overflow:hidden。
两种盒模型(box-sizing)的区别?
第一种盒模型是 content-box,即 width 指定的是 content 区域宽度,而不是实际宽度,公式为
实际宽度 = width + padding + border
第二种盒模型是 border-box,即 width 指定的是左右边框外侧的距离,公式为
实际宽度 = width
相同点是都是用来指定宽度的,不同点是 border-box 更好用。
JS面试题篇
JS 的数据类型有哪些?
字符串、数字、布尔、undefined、null、大整数、符号、对象
string、number、boolean、undefined、null、bigint、symbol、object
提了就零分的答案有:数组、函数、日期。这些是类 class,不是类型 type
原型链是什么?
举例说明
假设我们有一个普通对象 x={} ,这个 x 会有一个隐藏属性,叫做 ????? ,这 个属性会指向 Object.prototype ,即
x.__?????__ === Object.prototype // 原型
此时,我们说 x 的原型 是 Object.prototype,或者说 Object.prototype 是 x 的原 型。 而这个 ????? 属性的唯一作用就是用来指向 x 的原型的。 如果没有 ????? 属性,x 就不知道自己的原型是谁了。
为什么我用问号来表示?因为这样你不容易晕。
接下来我来说说原型链,我还是举例说明吧。
假设我们有一个数组对象 a=[] ,这个 a 也会有一个隐藏属性,叫做 ????? , 这个属性会指向 Array.prototype ,即
a.__?????__ === Array.prototype
此时,我们说 a 的原型是 Array.prototype ,跟上面的 x 一样。但又有一点不一样, 那就是 Array.prototype 也有一个隐藏属性 ????? ,指向 Object.prototype , 即
// 用 x 表示 Array.prototype
x.__?????__ === Object.prototype
这样一来,a 就有两层原型:
- a 的原型是 Array.prototype
- a 的原型的原型是 Object.prototype
于是就通过隐藏属性 ????? 形成了一个链条:
a ===> Array.prototype ===> Object.prototype
这就是原型链.
怎么做
看起来只要改写 x 的隐藏属性 ????? 就可以改变 x 的原型(链)
x.__?????__ = 原型
但是这不是标准推荐的写法,为了设置 x.?????_ ,推荐的写法是
const x = Object.create(原型)
// 或
const x = new 构造函数() // 会导致 x.__?????__ === 构造函数.prototype
解决了什么问题:
在没有 Class 的情况下实现「继承」。以 a ===> Array.prototype ===> Object.prototype 为例,我们说:
- a 是 Array 的实例,a 拥有 Array.prototype 里的属性
- Array 继承了 Object(注意专业术语的使用)
- a 是 Object 的间接实例,a 拥有 Object.prototype 里的属性 这样一来,a 就既拥有 Array.prototype 里的属性,又拥有 Object.prototype 里的属性。
优点:简单、优雅。
缺点:跟 class 相比,不支持私有属性。
怎么解决缺点:使用 class 呗。但 class 是 ES6 引入的,不被旧 IE 浏览器支持。建议熟读这篇文章
这段代码中的 this 是多少?
把判断依据背下来才能全对
var length = 4;
function callback() {
console.log(this.length); // => 打印出什么?
}
const obj = {
length: 5,
method(callback) {
callback();
}
};
obj.method(callback, 1, 2);
JS 的 new 做了什么?
- 创建临时对象/新对象
- 绑定原型
- 指定 this = 临时对象
- 执行构造函数
- 返回临时对象
JS 的立即执行函数是什么?
是什么*:声明一个匿名函数,然后立即执行它。这种做法就是立即执行函数。 怎么做:
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () // 用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
var x = function(){return '我是匿名函数'}()
上面每一行代码都是一个立即执行函数。(举例法) 解决了什么问题:在 ES6 之前,只能通过它来「创建局部作用域」。 优点:兼容性好。
缺点:丑。为什么这么丑?看视频分析。 怎么解决缺点:使用 ES6 的 block + let 语法,即
{
let a = '我是局部变量啦'
console.log(a) // 能读取 a
}
console.log(a) // 找不到 a
JS 的闭包是什么?怎么用?
是什么:闭包是 JS 的一种语法特性。
闭包 = 函数 + 自由变量
对于一个函数来说,变量分为:全局变量、本地变量、自由变量 怎么做:
let count
function add (){ // 访问了外部变量的函数
count += 1
}
把上面代码放在「非全局环境」里,就是闭包。
注意,闭包不是 count,闭包也不是 add,闭包是 count + add 组成的整体。
怎么制造一个「非全局环境」呢?答案是立即执行函数:
const x = function (){
var count
function add (){ // 访问了外部变量的函数
count += 1
}
}()
但是这个代码什么用也没有,所以我们需要 return add ,即:
const add2 = function (){
var count
return function add (){ // 访问了外部变量的函数
count += 1
}
}()
此时 add2 其实就是 add,我们可以调用 add2
add2()
// 相当于
add()
// 相当于
count += 1
至此,我们就实现了一个完整的「闭包的应用」。
注意:闭包 ≠ 闭包的应用,但面试官问你「闭包」的时候,你一定要答「闭包 的应用」,这是规矩。
解决了什么问题:
- 避免污染全局环境。(因为用的是局部变量)
- 提供对局部变量的间接访问。(因为只能 count += 1 不能 count -= 1)
- 维持变量,使其不被垃圾回收。
优点:简单,好用。 缺点:闭包使用不当可能造成内存泄露。
注意,重点是「使用不当」,不是闭包。 「闭包造成内存泄露」这句话以讹传讹很多年了,曾经旧版本 IE 的 bug 导致的问 题,居然被传成这样了。
举例说明:
function test() {
var x = {name: 'x'};
var y = {name: 'y', content: "-----这里很长,有一万三千五百个字符那么长----" }
return function fn() {
return x;
};
}
const myFn = test() // myFn 就是 fn 了
const myX = myFn() // myX 就是 x 了
// 请问,y 会消失吗?
对于一个正常的浏览器来说,y 会在一段时间后自动消失(被垃圾回收器给回收 掉)。 但旧版本的 IE 并不是正常的浏览器,所以是 IE 的问题。 当然,你可以说
君子不立于危墙之下,我们应该尽量少用闭包,因为有些浏览器对闭包的支持不够好
但你不可以说「闭包造成内存泄露」。对吗?
怎么解决缺点:慎用,少用,不用。(我偏要用)
JS 如何实现类?
方法一:使用原型
function Dog(name){
this.name = name
this.legsNumber = 4
}
Dog.prototype.kind = '狗'
Dog.prototype.say = function(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
Dog.prototype.run = function(){
console.log(`${this.legsNumber}条腿跑起来。`)
}
const d1 = new Dog('啸天') // Dog 函数就是一个类
d1.say()
请试着实现一个 Chicken 类,没 name 会 say 会 fly。 方法二:使用 class
class Dog {
kind = '狗' // 等价于在 constructor 里写 this.kind = '狗'
constructor(name) {
this.name = name
this.legsNumber = 4
// 思考:kind 放在哪,放在哪都无法实现上面的一样的效果
}
say(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
run(){
console.log(`${this.legsNumber}条腿跑起来。`)
}
}
const d1 = new Dog('啸天')
d1.say(
请试着实现一个 Chicken 类,没 name 会 say 会 fly
JS 如何实现继承?
方法一:使用原型链
function Animal(legsNumber){
this.legsNumber = legsNumber
}
Animal.prototype.kind = '动物'
function Dog(name){
this.name = name
Animal.call(this, 4) // 关键代码1
}
Dog.prototype.__proto__ = Animal.prototype // 关键代码2,但这句代码被禁用了,怎
Dog.prototype.kind = '狗'
Dog.prototype.say = function(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
const d1 = new Dog('啸天') // Dog 函数就是一个类
console.dir(d1)
如果面试官问被 ban 的代码如何替换,就说下面三句:
var f = function(){ }
f.prototype = Animal.prototype
Dog.prototype = new f()
方法二:使用 class
class Animal{
constructor(legsNumber){
this.legsNumber = legsNumber
}
run(){}
}
class Dog extends Animal{
constructor(name) {
super(4)
this.name = name
}
say(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
}