【面试题记录】2020前端秋招笔试面试题目记录

笔试题记录

1. 空元素 Empty Element (滴滴笔试)

空元素是HTML/SVG里的不可能存在子节点的元素。
个人理解就是:自闭和标签

HTML中的空元素:



2. (滴滴笔试)

video是闭合标签,不用必须指定宽高
类似,也是闭合标签

videoaudio都有的属性:

  • autoplay loop src controls

3. 否定伪类 :not()

伪类pseudo Class为一个元素的特定状态应用样式
伪元素pseudo Element为一个元素的特定部分应用样式

伪类:

  • :active :hover :focus :visited :enabled disabled :invalid :lang() :not() :optional :out-of-range
  • :readonly :read-write :required :root :scope :target :valid
  • :checked :default :defined :empty :first :focus-within :host :indeterminate :in-range :left :link
  • 长子first-child 嫡长子first-of-type 幼子:last-child 嫡幼子:last-of-type
  • 自定义规则:nth-child() :nth-of-type() 从后往前:nth-last-child() :nth-last-of-type()
  • 独子:only-child :only-of-type

伪元素:

  • ::after ::before ::first-letter ::first-line ::selection ::slotted

4. 状态码 (头条面试)

301 永久移动
302 临时移动
304 Not Modified
502 Bad Gateway
503 Service Unavailable

5. 获取元素?getElementByLabel()?

document.getXXX系列:

  • getElementById() // id
  • getElementsByClassName() // 类名
  • getElementsByName() // name属性
  • getElementsByTagName() // 标签名
  • getElementsByTagNameNS() // 使用命名空间的XML文档

获取元素还有Selector:

  • document.queySelector()
  • document.querySelectorAll()

6. GET和POST区别 (腾讯、头条面试)

GET - 从指定的资源请求数据
POST - 向指定资源提交要被处理的数据

GET:

  • 请求可被缓存
  • 请求保留在浏览器历史记录中
  • 可被收藏成书签
  • 不应用于敏感数据
  • 请求有长度限制
  • 只应当用于取数据
  • 请求参数只能是ASCII码,所以需要encode编码

POST:

  • 请求不会被缓存
  • 不保留在历史记录中
  • 不能被收藏成书签
  • 对数据长度无要求

7. 死锁

死锁产生的四个必要条件:

  • 互斥条件
  • .不可剥夺条件
  • 请求和保持条件
  • 循环等待条件

死锁预防:

  • 破坏“不可剥夺”:一个进程不能获得所需的全部资源便处于等待状态,等待期间他占有的资源被隐式地释放
  • 破坏“请求与保持”:一、静态分配:每个进程在开始执行时就申请他所需的全部资源。二、动态分配:每个进程在申请所需资源时它本身不占用系统资源。
  • 破坏“循环等待”:按编号顺序进行

8. CSS优先级问题(伪类+属性选择器)

    <div class="main">
        <div class="test">div>
    div>
    <style>
        .main div{
            width: 200px;
            height: 200px;
            border: 1px red solid;
        }
        .test {
            border: 1px green solid;
        }
    style>

.main div要比.test优先级高
ICE(Id > Class > Element)

伪类

    <div class="text">
        <p>伪类与类的优先级相等p>
        <p>所以后者起作用p>
    div>
    <style>
        .text p{
            color: red;
        }
        p:first-child{
            color: green;
        }
    style>

类和伪类优先级一致;元素和伪元素优先级一致

    <div>
        <p class="text" id="zpj">属性选择器p>
    div>
    <style>
        p[class="text"]{
            color: green;
        }
        [id="zpj"]{
            color: blue;
        }
        .text{
            color: red;
        }
    style>

属性选择器的优先级等于类选择器

9. innerHTMLinnerText

共同点是都可以读写。
text表文本;html表格式;inner是标签内部;outer包含标签本身;value只用于input和textarea

  • innerText : 只要文本
  • innerHTML : HTML格式
  • outerText:包含标签自己
  • outerHTML :包含标签自己
  • value : input和textarea

10. 箭头函数

  1. 箭头函数更适用于那些本来需要匿名函数的地方
  2. 箭头函数不能用作构造函数
  3. 没有自己的this、arguments、super和new.target
  • 箭头函数不会创建自己的this,只能从自己的作用域链上一层继承this
  • 使用剩余参数相较于使用arguments是更好的选择
  • 箭头函数不要用作对象方法,this指向问题
  • 箭头函数没有prototype属性
  • 箭头函数不能使用yield关键字,不能用作生成器

高级用法:

// 加括号的函数体返回对象字面量
() => ({name: 'zpj'});
// 支持剩余参数和默认参数
(a =1,b =true,...rest) => {};
// 支持参数列表解构
([a,b]=[1,2], {name: c} ={name: a+b}) => a+b+c;

说到this,提一下setTimeout

setTimeout调用的代码运行在与所在函数完全分离的执行环境上。这会导致代码中的this指向window

bind改变this指向,只改变一次

new.target :在普通函数调用中,指向undefined; 在类的构造方法中,指向被new执行的构造函数

// 1. 使用new.target来保证构造函数正确使用
function Foo(){
	if(!new.target) throw "Foo() must be called with new";
	// construction
}

// 2. 使用instanceof & new操作符干了什么(作业帮面试)
function User(name, pw){
	var self = this instanceof User ? this : Object.create(User.prototype);
	self.name = name;
	self.password = pw;
	return self;
}

11. 能冒泡的事件

先说onaddEventListener/attachEvent的区别

  • on+事件,只能绑定一个事件,后面的会覆盖前面的
  • addEventListener(eventName, function, useCapture)可以绑定多个事件
  • 移除事件有removeEventListener/detachEvent()

事件模型一般分为capture -> target -> bubble 的过程
注意到useCapturetrue是在捕获阶段处理事件,默认false是在冒泡阶段处理事件

有的事件没有冒泡过程。每个event都有一个event.bubles属性,可以知道他是否可以冒泡。

不冒泡的事件有:

  • abort blur error focus load mouseenter mouseleave resize unload

12. 组合选择器 (美团面试)

  • A,B 任意选择器, 所有A or B
  • A B 后代选择器, A后代中的B
  • A>B 子选择器,A的第一代B
  • A+B 毗邻选择器,弟弟选择器,next-sibling,A后的第一个B

13. 标签的type类型 (头条面试)

  • button checkbox color date datetime datetime-local email file hidden
  • image month number password radio range reset search submit
  • tel text ime url week

注意: 没有textarea是独立的一个标签

14. Array.from() Object.keys() (京东面试)

一、 Array.from(arrayLike, mapFunc, thisArg)

  • 字符串、set、map、arguments
Array.from('foo');
// ['f', 'o', 'o']
let s = new Set(['foo', window]);
Array.from(s);
// ["foo", Window]
let m = new Map([[1,2],[3,4],[5,6]]);
Array.from(m);
// [[1, 2], [2, 4], [4, 8]]
function f(){
	return Array.from(arguments);
}
f(1,2,3);
// [1,2,3]

如何将arguments转化成真正的数组:

  1. Array.from(arguments)
  2. Array.prototype.slice.call(arguments)

说到arguments,讲一下arguments和函数形参的联系

在非严格模式下,arguments指向的是形参的引用地址,一个改变,另一个跟着改变;
严格模式下,arguments是静态副本,二者互相独立。

function add(a,b){
	console.log(a,b); // 1 2
	console.log(arguments); // 1 2
	arguments[0] = 10;
	console.log(a,b); // 10 2
	console.log(arguments); // 10 2
	return a+b;
}
add(1,2); // 12

// 严格模式
'use strict'
function add(a,b){
	console.log(a,b); // 1 2
	console.log(arguments); // 1 2
	arguments[0] = 10;
	console.log(a,b); // 1 2
	console.log(arguments); // 10 2
	return a+b;
}
add(1,2); // 3

二、Object.keys(obj)

  • 遍历自身的可枚举属性,顺序和for-in一致,区别在于for-in会遍历原型链上的可枚举属性
// simple Array
Object.keys([1,2,3]); // ['0', '1', '2']
// array like object
Object.keys({0: 1, 1: 2, 2: 3}); // ["0", "1", "2"]
// array like object with random key ordering
Object.keys({100: 'a', 2: 'b', 7: 'c'}); // ["2", "7", "100"]

【注意】:想要拿到不可枚举属性,使用getOenPropertyNames()

也就是说,遍历对象属性的三种方法

  1. for-in:遍历自身和原型链上的可枚举属性,一般配合hasOwnProperty()使用
  2. Object.keys():遍历自身的可枚举属性
  3. Object.getOwnPropertyNames():遍历自身的所有属性,包括不可枚举属性

15. instanceof运算符 typeof操作符 (京东面试)

一、 instanceof 测试构造函数的prototype属性是否出现在对象的原型链中的任何位置

object instanceof constructor检测constructor.prototype是否存在于object的原型链上
实际上就是在问:constructor.prototype.isPrototypeOf(object);

function Car(){};
var c = new Car();
c instanceof Car;
c instanceof Object; // Object.prototype.isPrototypeOf(c);

二、 typeof 返回操作数的类型

类型 结果
Undefined "undefined"
Null "object"
Boolean "boolean"
Number "number"
BigInt "bigint"
String "string"
Symbol "symbol"
Function "function"
其余复杂对象(如:数组,Set, Map) "object"
typeof NaN === "number"
typeof Number(1) === "number"
typeof null === "object"
typeof /s/g === "object"

三、 Object.prototype.toString.call()

  • 判断类型最全面的方法:返回值为 "[object Type]"
Object.prototype.toString.call(1); // "[object Number]"
Object.prototype.toString.call(/s/); // "[object RegExp]"

四、Array.isArray()判断数组
五、isNaN()判断NaN

16. 严格模式

问题 严格模式 非严格模式
with 禁止with 不禁止
变量声明 变量必须声明 未声明的变量将隐式声明为全局变量
this指向 普通函数(非方法、非构造函数)中的this指向undefined this指向全局对象
this指向 callapply传入nullundefined,保持原样 会被转换成全局对象
不可扩展 给只读属性和不可扩展对象创建新成员,抛错 静默失败
eval eval中不能定义变量和函数 变量和函数定义在新的作用域中
arguments arguments拥有参数的静态副本 arguments和参数指向同一个值
delete delete不可配置属性会抛错 静默失败,返回false
对象字面量 定义多个同名属性会报错 保留最后一个
函数多个同名参数 报错 最后一个为准
八进制字面量 禁止 允许
关键字 eval arguments 不能作变量名· -

17. 语义化 (头条面试)

  • 语义化的优点:
  1. 易于阅读,样式丢失也能呈现清晰的结构
  2. SEO,搜索引起根据标签来确定上下文和各个关键字的权重
  3. 便于多设备解析
  4. 利于代码维护
  • 常见语义化标签

18. 宏任务和微任务(setTimeoutPromise 的区别)(快手面试)

  • Event Loop 事件循环有很多tick,每个tick包括一队宏任务和一队微任务
  • 传统异步(setTimeout)是事件循环(宏任务)
  • promise是任务队列(微任务)

任务队列是挂在事件循环队列的每个tick之后的一个队列。在事件循环的每个tick中,可能出现的异步动作不会导致一个完整的新事件添加到事件循环队列中,而是会生成一个微任务,挂在当前事件循环的后面。
事件循环队列类似于一个游乐园游戏:玩过了滑滑梯之后,你需要跑到队尾才能再玩一次。而任务队列等于玩过之后直接插队继续玩。

console.log(1); // 当前tick宏任务
setTimeout(function(){
	console.log(2); // 下一个tick宏任务
}, 0);
var p = new Promise(function(resolve, reject){
	console.log(3); // 当前tick宏任务
	resolve();
});
p.then(res => {
	console.log(4); // 当前tick微任务
});
console.log(5); // 当前tick宏任务
// 1 3 5 4 2

19. 强缓存和协商缓存 cache-control (头条面试)

请求设置

字段名 说明
no-cache 告知(代理)服务器,不要直接使用缓存,要求向原服务器发起请求
no-store 所有内容不会被保存
max-age=delta-seconds 客户端会缓存delta秒

响应设置

字段名称 说明
public 公开,任何情况下都缓存该资源
must-revalidate 当前资源一定是向原服务器发去验证的,请求失败返回504

20. JSON.parse() 解析数字 (360笔试)

  • 键:JSON中字段名只允许双引号包裹"name"
  • 值:数字直接写,字符串双引号
JSON.parse('{"age": 23}'); // -> {age: 23}
JSON.parse('{"age": "23"}'); // -> {age: "23"}

21. 默认inherit的css属性 (360笔试)

  • 并非所有未定义的css属性会默认inherit
  • color text-indent text-align line-height list-style-type list-style-image list-style cursor
  • direction word-spacing text-transform white-space border-collapse

22. url()的写法 (360笔试)

资源地址可以使用单引号或双引号包起来,也可以不使用任何引号

  • url('image.gif)
  • url("image.gif")
  • url(image.gif)

使用@import

  • @import url("global.css)
  • @import url(global.css)
  • @import "global.css"

23. for-infor-of的比较 (流利说面试)

一、forEach遍历数组,无法使用returnbreak挑出循环
二、for-in 遍历普通对象

  • index是字符串,而不是数字
  • 作用于数组的for-in循环还会遍历自定义属性,以及原型链属性
  • 随机顺序遍历数组

三、for-ofIterator

  • Iterator一是为各种数据结构提供一个统一的访问接口;二是使数据结构成员能按某种次序排序
  • for-of只遍历拥有Symbol.iterator属性的对象
  • 原生具备Iterator接口的数据结构: Array Map Set String TypedArray arguments NodeList
  • 阮一峰ES6

24. animation 动画 (美团面试)

@keyframes mymovie{
	from {top: 0px;}
	to {top: 200px;}
}
div {
	animation: mymovie 2s infinite;
	position: relative;
}

两件事:1. 定义关键帧; 2. animation播放设置
animation: name duration timing-function delay iteration-count direction;

描述
animation-name keyframe
animation-duration 持续时间,带单位 2s
animation-timing-function 速度曲线 linear ease ease-in ease-out ease-in-out
animation-delay 延迟 2s
animation-iteration-count 播放次数
animation-direction normal alternate

流利说面试:这道题还牵扯出top和transform的性能问题,transform合成计算,改变偏移量会引发回流重绘。

回流重绘的浏览器优化,维护队列,操作到了一定数量或者到了一定的时间,批处理一个队列。
添加删除可见元素,元素位置改变,尺寸改变,margin、padding、border、content、width、height的改变都会回流。
回流一定重绘,重绘不一定回流。

25. 返回顶部按钮(寒武纪面试)

两种思路:1. scroll API; 2. 锚点标记

        window.onscroll = function () {
            var scrollTop = document.documentElement.scrollTop;
            if (scrollTop < 1200) {
                document.querySelector('#topbtn').style.display = 'none';
            } else {
                document.querySelector('#topbtn').style.display = 'block';
            }
        }
        // 定时器实现思路
        document.querySelector('#topbtn').onclick = function () {
            var itvId = setInterval(function () {
                var scrollTop = document.documentElement.scrollTop;
                if (scrollTop > 0) {
                    window.scrollTo(0, scrollTop - 20);
                } else {
                    clearInterval(itvId);
                }
            }, 16);
        }
		// requestAnimationFrame
        document.querySelector('#topbtn').onclick = function () {
            (function smoothscroll() {
                var currentScroll = document.documentElement.scrollTop || document.body.scrollTop;
                if (currentScroll > 0) {
                    window.requestAnimationFrame(smoothscroll);
                    window.scrollTo(0, currentScroll - 20);
                }
            })();
        }

26. margin可以百分比吗?(爱奇艺笔试)

可以,基于父元素宽度的百分比,包括margin-top margin-bottom

padding同理。为什么不是高度的百分比,会导致无限循环。

27. 堆排序,建堆过程 (寒武纪面试)

堆是一颗完全二叉树

  • 完全二叉树Complete Binary Tree:除了最后一层外每一层都被填满,最后一层保持左对齐
  • 满二叉树Perfect Binary Tree:每一层都被填满
  • 满二叉树一定是完全二叉树;完全二叉树不一定是满二叉树

堆排序按原始顺序建立完全二叉树,然后找到第一个非叶子节点,从下至上开始不断调整大小顺序。完全二叉树从零开始排列,可以用一个数组表示,结点元素完全和序列挂钩。

// 建堆注意迭代,换完父节点,注意下一层节点还需要换,知道叶子结点
function bigHeap(array, i, length){
	// 不用建树,因为完全二叉树的节点和排序一一对应,所以直接用序列号即可
	while(i <= Math.floor(length)/2 - 1){ // i代表父节点,父节点在非叶子节点范围内则迭代
		let left = 2*i+1;
		let right = 2*i+2;
		let bigChild = left; // 记录被交换的节点序号
		if(right < length){
			if(array[right] > array[bigChild]){
				bigChild = right;
			}
        } 
		if(array[bigChild] > array[i]){
			let temp = array[bigChild];
			array[bigChild] = array[i];
			array[i] = temp;
		}
		// update
		i = bigChild; // 被交换的子节点向下迭代
    }
}

var a = [1,2,3,4,5,6,7,8];
// 初始化堆
for(let i = Math.floor(a.length/2)-1; i >= 0; i--){
	bigHeap(a, i, a.length); // 从后往前依次建堆
}
console.log(a);

// 堆排序的话,每次更换堆顶点与堆尾
for(let i = a.length - 1; i > 0; i --){
	let temp = a[i];
	a[i] = a[0];
	a[0] = temp;
	bigHeap(a, 0, i); // 从后往前依次建堆
}

28. 前端性能优化(寒武纪面试)

  • 减少请求资源大小和次数
    • 打包工具,合并压缩css和js
    • 图片资源懒加载,雪碧图
    • 缓存,减少cookie
  • 代码优化
    • 动画效果用css,不用js
    • 减少DOM操作,都是为了减少回流重绘渲染的时间

你可能感兴趣的:(面试常问,面试题外传,JavaScript)