2020面试题总结

130 阅读15分钟

链接:juejin.cn/post/684490…

1.如何理解html标签语义化?

合理的标签做合理的事情, 能让浏览器更好的读取页面结构, 便于团队开发和维护, 有利于SEO, 常用的语义化标签包括:

<header></header>头部
<nav></nav>导航栏
<section></section>区块(有语义化的div)
<main></main>主要区域
<article></article>主要内容
<aside></aside>侧边栏
<footer></footer>底部

2.css权重是什么?

设置节点样式的方式有很多种,不同的方式它们的权重并不相同,当它们给一个节点设置同一个样式时,谁的权重高谁就生效。

  • important:无限高
  • 行内样式:权重值为1000
  • id选择器:权重值为100
  • 类、伪类、属性选择器:权重值为10
  • 标签选择器:权重值为1

3.盒模型有几种,它们区别是什么?

content、padding、border、margin

  • 标准盒模型(box-sizing:content-box)
  • ie怪异盒模型(box-sizing:border-box)
  • flex弹性伸缩盒模型
  • column多列布局(栅格化布局 基本不用)
  • 注:怪异盒模型的好处,固定到border控制宽高,不用重新计算padding和border

4. 什么是BFC?

块级格式上下文,一句话来说就是让块级元素有块级元素该有的样子,触发BFC可以清除浮动、让margin不重叠。

  • float的值不为none。(left、right)
  • position的值不为static或relative中的任何一个。(absolute、fixed)
  • overflow的值不为visible。(hidden、auto、scroll)
  • display的值为table-cell、table-caption和inline-block之一。

5. px、em、rem、vw/vh的区别?

  • px:物理屏幕上能显示出的最小的一个点。
  • em:如果父级有设置字体大小,1em就是父级的大小,没有1em等于自身默认的字体大小。
  • rem:相对于html标签的字体大小。
  • vw/vh:相对于视口的高度和宽度,1vh 等于1/100的视口高度,1vw 等于1/100的视口宽度。

6. 不使用border属性画一条1px的线?

<div style='height: 1px; background: #666; overflow: hidden;'></div>

<hr size='1'></hr>

7. 移动端1px问题的解决办法

链接:juejin.cn/post/684490…

8. 定位的方式有哪几种,它们的区别是什么?

  • relative:相较于自身定位,设置的位置相对于自己进行位移。不脱离文档流。
  • absolute:相较于最近有定位的父节点定位,设置的位置相较于父节点。会脱离文档流,导致父节点高度塌陷。
  • fixed:相较于当前窗口进行定位,设置的位置相较于窗口。脱离文档流。
  • static:默认值。没有定位,元素出现在正常的流中。
  • sticky:生成粘性定位的元素,容器的位置根据正常文档流计算得出。
  • 粘性定位:www.jianshu.com/p/e25a9eb8a…

9. 垂直水平居中的实现方式有哪些?

  • 父级设置text-align: center和line-height等同高度。
  • 子节点绝对定位,设置position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);
  • 子节点绝对定位,需要设置宽度和高度。设置position: absolute;top:0;left:0;right:0;bottom:0;margin:auto;
  • 父级设置display: table; 子节点设置display:table-cell;text-align:center;vertical-align:middle;
  • 父级设置display: flex;justify-content:center;align-items:center;
  • 父节点设置display: grid; 子节点设置:align-self:center;justify-self: center;

10.你知道的左右宽度固定,中间自适应的三栏布局方案有哪些?

浮动:
.parent {overflow: hidden;}
.left {float: left; width: 100px;}
.right: {float: right; width: 100px;}
<div class='parent'>
  <div class='left'></div>
  <div class='right'></div>
  <div class='center'></div>
</div>

定位1:
.parent {position: relative};
.left {position: absolute; left: 0; width: 100px};
.right {position: absolute; right: 0; width: 100px};
.center {postion: absolute; left: 100px; right: 100px};

定位2:
.parent {position: relative};
.left {position: absolute; left: 0; width: 100px};
.right {position: absolute; right: 0; top: 0; width: 100px};
.center {margin: 0 100px 0 100px};

表格:
.parent {dispaly: table; width: 100%;}
.left {display: table-cell; width: 100px;}
.center {display: table-cell;}
.right {display: table-cell; width: 100px;}

弹性:
.parent {display: flex;}
.left {width: 100px;}
.center {flex: 1;}
.right {width: 100px;}

网格:
.parent {
  display: grid; 
  width: 100%; 
  grid-template-rows: 100px; 
  grid-template-columns: 100px auto 100px;
}

11.实现三个圆形的水平自适应布局?

难点在于高度的自适应
.parent {
  display: table;
  width: 100%;
}
.child {
  display: table-cell;
  padding-top: 33.33%;
  background: red;
  border-radius: 50%;
}

.parent {
  overflow: hidden;
}
.child {
  float: left;
  width: 33.33%;
  padding-top: 33.33%;
  border-radius: 50%;
  background: red;
}

.parent {
  display: flex;
}
.child {
  flex: 1;
  padding-top: 33.33%;
  border-radius: 50%;
  background: red;
}

12.介绍下flex布局?

主轴方向:水平排列(默认) | 水平反向排列 | 垂直排列 | 垂直反向排列
flex-direction: row | row-reverse | column | column-reverse;

换行:不换行(默认) | 换行 | 反向换行(第一行在最后面)
flex-wrap: nowrap | wrap | wrap-reverse;

flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
flex-flow: <flex-direction> || <flex-wrap>;

主轴对齐方式:起点对齐(默认) | 终点对齐 | 居中对齐 | 两端对齐 | 分散对齐
justify-content: flex-start | flex-end | center | space-between | space-around;

交叉轴对齐方式:拉伸对齐(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 第一行文字的基线对齐
align-items: stretch | flex-start | flex-end | center | baseline;

多根轴线对齐方式:拉伸对齐(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 两端对齐 | 分散对齐
align-content: stretch | flex-start | flex-end | center | space-between | space-around;

13.JavaScript的变量有哪些类型?

分为两种:基础类型和引用类型。

  • 基础类型:boolean、null、undefined、number、string、symbol(创建唯一值的)。
  • 引用类型:Array、Object、Function。

14.基础类型和引用的区别?

  • 它们在内存中存储的方式不同。基础类型存储的是值,而引用类型存储的是指向内存中某个空间的指针;
  • 基础类型赋值就是把值赋给另外一个变量,而引用类型的赋值是赋值的原来变量的指针,所以当引用类型发生改变时,只要是指向同一个指针的变量的都会发生改变。

15.函数参数是对象时会发生什么问题?

  • 函数参数是对象时,相当于是将对象的指针传递给了函数,如果在函数的内部改变了对象的值,外面对象的值也会发生改变,数组也是如此。

16.typeof和instanceof判断变量类型的区别?

  • typeof对于基础类型除了null以外都可以显示正确的类型,对于数组和对象都会显示object,对于函数会显示function。
  • instanceof主要是用来判断引用类型,它的原理是根据原型链来查找。

17.有没有更好的判断变量类型的方法?

  • 可以使用Object.prototype.toString.call(var),可以更加准确的判断某个变量的类型。

18.类数组转为数组的方式有哪些?

[].slice.call(arguments)
Array.from(arguments)
[...arguments]

19.如何判断一个变量是否是数组?

arr instanceof Array
Array.prototype.isPrototypeOf(arr)
Array.isArray(arr)
Object.prototype.toString.call(arr) === '[object Array]'
arr.constructor === Array

20.将多维数组扁平化?

function flatten(arr) {
  return [].concat(...arr.map(v => {
    return Array.isArray(v) ? flatten(v) : v;
  }))
}

function flatten(arr) {
  return arr.reduce((pre, cur) => {
    return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
  }, [])
}

function flatten(arr) {
  return arr.flat(Infinity);
}

function flatten(arr) {  // 纯数字
  return arr.toString().split(',').map(Number);
}

function flatten(arr) {
  const ret = [];
  while (arr.length) {
    const item = arr.shift();
    if (Array.isArray(item)) {
      arr.unshift(...item);
    } else {
      ret.push(item);
    }
  }
  return ret;
}

21.数组去重?

  • 一、利用ES6 Set去重(ES6中最常用)
function unique (arr) {
  return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
 //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
这种去重的方法代码最少,但是无法去掉“{}”空对象

  • 二、利用for嵌套for,然后splice去重(ES5中最常用)
function unique(arr){            
        for(var i=0; i<arr.length; i++){
            for(var j=i+1; j<arr.length; j++){
                if(arr[i]==arr[j]){         //第一个等同于第二个,splice方法删除第二个
                    arr.splice(j,1);
                    j--;
                }
            }
        }
    return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}]     //NaN和{}没有去重,两个null直接消失了
注:双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。
  • 三、利用indexOf去重:新建一个空的结果数组,for循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。
function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    var array = [];
    for (var i = 0; i < arr.length; i++) {
        if (array .indexOf(arr[i]) === -1) {
            array .push(arr[i])
        }
    }
    return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}]  //NaN、{}没有去重
  • 四、利用sort(),根据排序后的结果进行遍历及相邻元素比对。
function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return;
    }
    arr = arr.sort()
    var arrry= [arr[0]];
    for (var i = 1; i < arr.length; i++) {
        if (arr[i] !== arr[i-1]) {
            arrry.push(arr[i]);
        }
    }
    return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined]      //NaN、{}没有去重
  • 五、利用includes()
function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    var array =[];
    for(var i = 0; i < arr.length; i++) {
        if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
            array.push(arr[i]);
        }
    }
    return array
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]     //{}没有去重
  • 六、利用reduce+includes
function unique(arr){
    return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]
  • 七、利用hasOwnProperty:判断是否存在对象属性
function unique(arr) {
    var obj = {};
    return arr.filter(function(item, index, arr){
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}]   //所有的都去重了
  • 八、利用filter
function unique(arr) {
  return arr.filter(function(item, index, arr) {
    //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
    return arr.indexOf(item, 0) === index;
  });
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]
  • 九、利用递归去重
function unique(arr) {
    var array= arr;
    var len = array.length;
    array.sort(function(a,b){   //排序后更加方便去重
        return a - b;
    })
    function loop(index){
        if(index >= 1){
            if(array[index] === array[index-1]){
                array.splice(index,1);
            }
            loop(index - 1);    //递归loop,然后数组去重
        }
    }
    loop(len-1);
    return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]
  • 十、利用Map数据结构去重:创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。
function arrayNonRepeatfy(arr) {
  let map = new Map();
  let array = new Array();  // 数组用于返回结果
  for (let i = 0; i < arr.length; i++) {
    if(map .has(arr[i])) {  // 如果有该key值
      map .set(arr[i], true); 
    } else { 
      map .set(arr[i], false);   // 如果没有该key值
      array .push(arr[i]);
    }
  } 
  return array ;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]

22.字符串的test、match、search它们之间的区别?

`test`是检测字符串是否匹配某个正则,返回布尔值;
/[a-z]/.test(1);  // false

`match`是返回检测字符匹配正则的数组结果集合,没有返回`null`;
'1AbC2d'.match(/[a-z]/ig);  // ['A', 'b', 'C', 'd']

`search`是返回正则匹配到的下标,没有返回`-1`。
'1AbC2d'.search(/[a-z]/);  // 2

23.字符串的slice、substring、substr它们之间的区别?

`slice`是返回字符串开始至结束下标减去开始下标个数的新字符串,下标是负数为倒数;
'abcdefg'.slice(2,3);  // c  // 3 - 2
'abcdefg'.slice(3,2);  // ''  // 2 - 3
'abcdefg'.slice(-2,-1);  // f  // -1 - -2

`substring`和`slice`正常截取字符串时相同,负数为0,且下标值小的为开始下标;
'abcdefg'.substring(2,3);  //c  // 3 - 2
'abcdefg'.substring(3,2);  // c  // 3 - 2 
'abcdefg'.substring(3,-3);  // abc  // 3 - 0

`substr`返回开始下标开始加第二个参数(不能为负数)个数的新字符串。
'abcdefg'.substr(2, 3);  // cde
'abcdefg'.substr(3, 2);  // de
'abcdefg'.substr(-3, 2); // ef

24.Number('123')和new Number('123')有什么区别?

Number('123')是一个转换函数,会尝试把参数转为整数类型;而new Number('123')则不同,这是一个构造函数,它的结果是实例化出来一个对象。 同样的情况也适用用String和new String;Boolean和new Boolean的情况。

typeof Number('123') // number
typeof new Number('123') // object

25.==和===的区别?

===会判断两边变量的类型和值是否全部相等,==会存在变量类型转换的问题,所以并不推荐使用,只用一种情况会被使用,var == null是var === undefined || var === null的简写,其余情况一律使用===。

26.是否===就完全靠谱?

  • 也是不一定的,例如0 === -0就为true,NaN === NaN为false,判断两个变量是否完全相等可以使用ES6新增的API,Object.is(0, -0),Object.is(NaN, NaN)就可以准确区分。

27.在类型转换中哪些值会被转为true?

  • 除了undefined、null、false、NaN、''、0、-0以外的值都会被转为true,包括所有引用类型,即使是空的。

28.什么是基本包装类型?

  • 基本类型:Undefined,Null,Boolean,Number,String
  • 基本包装类型:Boolean,Number,String
  • 在基本类型中,有三个比较特殊的存在就是:String Number Boolean,这三个基本类型都有自己对应的包装对象。包装对象,其实就是对象,有相应的属性和方法。调用方法的过程,是在后台偷偷发生的。
  • 字符串、整数、布尔值,首先会使用各自的构造函数创建对应的实例,这样调用这些方法时就可以正常使用,不过再方法调用结束后,就会将实例给销毁掉,从而又是基本类型。
//我们平常写程序的过程:
var str = 'hello'; //string 基本类型
var s2 = str.charAt(0); //在执行到这一句的时候 后台会自动完成以下动作 :
( 
 var _str = new String('hello'); // 1 找到对应的包装对象类型,然后通过包装对象创建出一个和基本类型值相同的对象
 var s2 = _str.chaAt(0); // 2 然后这个对象就可以调用包装对象下的方法,并且返回结给s2.
 _str = null;  //    3 之后这个临时创建的对象就被销毁了, str =null; 
 ) 
alert(s2);//h 
alert(str);//hello

29.toString()和valueOf的区别?

  • null和undefined没有以上两个方法。
  • toString:值类型时返回自身的字符串形式;当是引用类型时,无论是一维或多维数组,将他们拍平成一个字符串,里面的null和undefined转为空字符串'',对象转为[object Object],函数的原样返回字符串形式。
  • valueOf无论是值类型还是引用类型,大部分情况下都是原样返回,当是Date类型时,返回时间戳。
  • 在进行字符串强转的时候,toString会优先于valueOf;在进行数值运算时,valueOf会优先于toString。
  • 当执行toString的变量是一个整数类型时,支持传参,表示需要转为多少进制的字符串。
  • www.cnblogs.com/chorkiu/p/1…

30.谈谈对this的理解?

调用的上下文环境包括全局和局部。

  • 全局环境:在script标签里面,这里的this始终指向的是window对象。
<script>
    console.log(<strong>this</strong>);//指向window对象
</script>
  • 局部环境
  • 1)在全局作用域下直接调用函数,this指向window
function func(){
  console.log(this) ;//this指向的还是window对象
}
func()
  • 2)对象函数调用,哪个对象调用就指向哪个对象
<input type="button"id="btnOK" value="OK">
<script>
  varbtnOK=document.getElementById("btnOK");
  btnOK.οnclick=function(){
    console.log(this);//this指向的是btnOK对象
  }
</script>
  • 3)使用 new 实例化对象,在构造函数中的this指向实例化对象。
var Show=function(){
    this.myName="Mr.Cao";   //这里的this指向的是obj对象
}
var obj=new Show();
4)使用call或apply改变this的指向
var Go=function(){
    this.address="深圳";
}
var Show=function(){
    console.log(this.address);//输出 深圳
}
var go=new Go();
Show.call(go);//改变Show方法的this指向go对象
  • 加分项
1. 用于区分全局变量和局部变量,需要使用this
var age=20;
function show(age){
   this.age=age;
}
2.返回函数当前的对象
live: function( types, data, fn ) {
        jQuery( this.context ).on( types, this.selector, data, fn );
        return this;
      }
3.将当前的对象传递到下一个函数
each: function( callback, args ) {
        return jQuery.each( this, callback, args );
      }

31.改变当前调用this的方式?

  • call:会立即执行调用call方法的函数,不过是以第一个参数为this的情况下调用,方法内可以传递不等的参数,作为调用call方法的参数。
  • apply:运行方式和call是一致的,只是接受的参数不同,不能是不定参数,得是一个数组。
  • bind:会改变当前的this,接受不定参数,不过不会马上执行调用bind方法的函数,而是返回一个函数作为结果,执行后才是调用函数的结果