2020常见面试题

269 阅读14分钟

css

1. 水平,垂直居中的方式,各4种?

  • 水平居中 

text-align:center;(行内元素)   

 margin: 0 auto;(块级元素) 

position:absolute;  left: 50%; margin-left: -xxpx;       transform:translateX(-50%)

display:flex;justify-content:center;

  •   垂直居中

line-height = height

position: absolute; top: 50%; margin-top: -xxpx;    transform: translateY(-50%)

display: flex; align-items: center;

2.     1rem  1em  1vh  1px 各自代表的含义?

rem

rem大小相对于<html>根元素,通常是给根元素设置一个大小,其它元素长度就为rem

em

子元素大小的em是相对于父元素字体的大小

vw/vh

视窗的宽度和高度  1vw/vh相当于屏幕宽度/高度的1%

ps: 处理宽度百分比合适,处理高度vh

px

相对长度单位,像素px是相对于显示器屏幕分辨率而言的


3. 画一条0.5px的边?

height: 1px;

transform: scale(0.5);


4. 盒模型?

盒模型的组成,由里向外content,padding,border,margin.

在IE盒子模型中,width表示content+padding+border这三个部分的宽度

在标准的盒子模型中,width指content部分的宽度

box-sizing: border-box; 是IE盒模型
box-sizing: content-box; 是标准盒模型


5. 画一个三角形?

.xx {
    width: 0;
    height: 0;
    border-width: 100px;
    border-style: solid;
    border-color: #000 transparent transparent transparent;
    // transform: rotate(90deg)
}

6. 伪类选择器?




7. 清除浮动有哪些方法?

  • 给父元素设置宽高,或者给父元素设置 overflow:hidden
  • <div style="clear: both"></div>
  • .clear:after{
        content: '';
        display: block;
        clear:both;
    }


8.  css实现图片自适应宽高

img {
    max-width: 100%;
    max-height: 100%;
}


9. flex? 常见属性及作用

弹性布局,用来为盒状模型提供最大的灵活性

设为Flex布局以后,子元素的float、clear和vertical-align属性将失效

巴拉巴拉



html

1. <label>标签的用法

方便鼠标点击使用,扩大可点击的范围,增强操作体验


2.  遍历A节点的父节点下的所有子节点

<script>
    var b = document.getElementById('b').parentNode.children
    consoel.log(b)
</script>

3. 页面渲染html的过程 ?



4. 行内元素与块元素有什么区别?

  • 行内元素会在同一行上水平排列(默认宽度只与内容有关)
  • 块级元素各占一行
  • 块级元素可以包含行内元素和块级元素。行内元素不能包含块级元素,只能包含文本或者其它行内元素
  • 行内元素与块级元素属性不同,主要是盒模型属性上:行内元素设置 width/height 无效(可以设置 line-height),margin 上下无效,padding 上下无效


5. link 和 @import 的区别

link是html的标签,@import是css的语法规则;

加载页面时,link是同时加载的,@import是页面加载完后才加载

link没有兼容性的问题,@import只在较高版本的浏览器才可以识别

link可以通过js插入操作dom,@import 不可以




js

1. 事件代理?

事件委托是指将事件绑定到目标元素的父元素上,利用冒泡机制触发该事件

<div id='div' onclick='alert("div");'>
    <ul onclick='alert("ul");'>
        <li onclick='alert("li");'>test</li>
    </ul>
</div>

单击test时,会依次触发alert(“li”),alert(“ul”),alert(“div”),这就是事件冒泡。

阻止冒泡:

window.event? window.event.cancelBubble = true : e.stopPropagation();

2. target、currentTarget的区别?

currentTarget当前所绑定事件的元素

target当前被点击的元素

两者在没有冒泡的情袭况下,是一样的值,但在用了事件委托的情况下,就不一样了:

<ul id="ulT">    
    <li class="item1">fsda</li>   
    <li class="item2">ewre</li>    
    <li class="item3">qewe</li>   
    <li class="item4">xvc</li>   
    <li class="item5">134</li>
</ul>

<script type="text/javascript">    
    document.getElementById("ulT").onclick = function  (event) {        
        console.log(event.target);        
        console.log(event.currentTarget);    
    } 
</script>

event.target返回的是点击的元素节点

3. 继承




4. 闭包

闭包的实质是因为函数嵌套而形成的作用域链

函数 A内部有一个函数B,函数B可以访问到函数 A 中的变量,那么函数B就是闭包

function a() {     var i = 0;     function b() {         alert(++i);     }     return b; } var c = a(); c(); 

函数b嵌套在函数a内部;
函数a返回函数b。

这样在执行完var c=a()后,变量c实际上是指向了函数b,b中用到了变量i,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。

当函数a的内部函数b被a外的一个变量引用时,就创建了一个“闭包”。

闭包的作用和效果?

闭包的作用就是在a执行完并返回后,闭包使得js的垃圾回收机制不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。

在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。

通过保护变量的安全,实现JS私有属性和私有方法(不能被外部访问)



5.export和export default的区别

export default XXX
import XXX from 'a.js'

export xxx
import {xxx} from 'b.js


6. 数组去重

var arr=['12','32','89','12','12','78','12','32'];

// 最easy
function unique1(array) {
    var temp = [];
    for(var i = 0; i< array.length; i++) {
        if(temp.indexOf(array[i]) === -1) {
            temp.push(array[i])
        }
    }
}
arr = unique1(arr)

function dedupe(array) {
  return Array.from(new Set(array));       //Array.from()能把set结构转换为数组
}
arr = depude(arr)


7. get、post的区别

get传参方式是url传递,可以看到传递参数,通过?连接,&分割参数,安全性低;

post将参数存放在http的包体内,安全性高;

get对传递的数据长度有大小限制,post没有长度限制;

get后退不会有影响,post后退会重新提交;

get请求的记录会留在历史记录中,post不会留在历史记录;

get只支持ASCII字符,post没有字符类型限制;


8. http的响应码及含义

1xx (临时响应)

2xx (成功)

     200:正确的请求返回正确的结果

     202:请求是正确的,但是结果正在处理中,这时客户端可以通过轮询等机制继续请求

3xx 已重定向

4xx 请求错误(客户端类)

     400:请求出现错误,eg: 请求头不对

     401:没有提供认证信息。eg:  请求的时候没有带上 Token

     403:请求的资源不允许访问。就是说没有权限。

     404:请求的内容不存在。

5xx 服务器错误(服务器端类)


9. 同步与异步的区别

同步: 按照任务的顺序执行任务,后一个任务要等待前一个任务执行结束

异步:执行顺序不确定,异步处理可以同时执行多个

同步执行效率低,耗时间,但有利于流程控制;

异步效率高,节省时间,但是会占用更多的资源,不利于进程控制


10. 什么是变量提升

先来两个例子:

var v='hello';
(function(){
    alert(v);
})()         // hello
var v='Hello World';
(function(){
    alert(v);
    var v='I love you';
})()        // undefined

变量提升,很简单,就是把变量提升提到函数的top的地方。变量提升, 只是提升变量的声明,并不会把赋值也提升上来。

我们定义三个变量:

(function(){
    var a='One';
    var b='Two';
    var c='Three';
})()

实际上这样的:

(function(){
    var a,b,c;
    a='One';
    b='Two';
    c='Three';
})()

补充:函数提升

函数提升是把整个函数都提到前面去。

在我们写js 的时候,有两种写法,一种是函数表达式,另一种是函数声明方式。要注意的是,只有函数声明形式才能被提升。

函数声明方式提升【成功】

function myTest(){
    foo();
    function foo(){
        alert("我来自 foo");
    }
}
myTest();       // 我来自 foo
函数表达式方式提升【失败】

function myTest(){
    foo();
    var foo =function foo(){
        alert("我来自 foo");
    }
}
myTest();       // typeError: foo is not a function




11. call,apply,bind的用法与区别

call,apply,bind这三个方法其实都是继承自Function.prototype中的,属于实例方法。

1     console.log(Function.prototype.hasOwnProperty('call')) //true
2     console.log(Function.prototype.hasOwnProperty('apply')) //true
3     console.log(Function.prototype.hasOwnProperty('bind')) //true

普通的对象,函数,数组都继承了Function.prototype对象中的三个方法,所以这三个方法都可以在对象,数组,函数中使用

1.  Function.prototype.call()                   改变this指向

函数实例的call方法,可以指定该函数内部this的指向,然后在所指定的作用域中,调用该函数。并且会立即执行该函数

     var keith = {
         rascal: 123
     };

     var rascal = 456;

     function a() {
         console.log(this.rascal);
     }

     a(); //456
     a.call(); //456
     a.call(null); //456
     a.call(undefined); //456
     a.call(this); //456
     a.call(keith); //123

call()方法可以传递两个参数。

第一个参数是指定函数内部中this的指向(也就是函数执行时所在的作用域),

第二个参数是函数调用时需要传递的参数。

    function keith(a, b) {
        console.log(a + b);
     } 

    keith.call(null, 1, 2); //3

第一个参数是必须的,可以是null,undefined,this,但是不能为空。设置为null,undefined,this表明函数keith此时处于全局作用域。第二个参数中必须一个个添加。而在apply中必须以数组的形式添加。


2.Function.prototype.apply()

和call一样,唯一区别是第二个参数接收一个数组

    function keith(a, b) {
        console.log(a + b);
     } 

    keith.apply(null, [1, 2]); //3

举个应用例子:

找出数组中的最大数

var a = [2, 4, 5, 7, 8, 10];
console.log(Math.max.apply(null, a)); //10
console.log(Math.max.call(null,2, 4, 5, 7, 8, 10)); //10

Javascript中是没有提供找出数组中最大值的方法的,
结合使用继承自Function.prototype的apply和Math.max方法,就可以返回数组的最大值。
将数组的空元素变为undefined

console.log(Array.apply(null, [1, , 3])); // [1, undefined, 3]

空元素与undefined的差别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined和null。
遍历内部元素的时候,会得到不同的结果

3.Function.prototype.bind()

bind方法用于指定函数内部的this指向,然后返回一个新函数,bind方法并非立即执行一个函数。

 1     var keith = {
 2         a: 1,
 3         count: function() {
 4             console.log(this.a++);
 5         }
 6     };
 7 
 8     keith.count(); //1   this指向keith 对象
 9     keith.count(); //2
10     keith.count(); //3
1     var keith = {
2         a: 1,
3         count: function() {
4             console.log(this.a++);
5         }
6     };
7 
8     var f = keith.count;
9     f(); //NaN    // this指向window对象,window.a = undefined


     var f = keith.count.bind(keith);
     f(); //1
     f(); //2
     f(); //3

当然,this也可以绑定到其他对象上。

     var obj = {
         a: 100
     };
     var f = keith.count.bind(obj);
     f(); //100
     f(); //101
     f(); //102
     function keith(a, b) {
         return a + b;
     }
     console.log(keith.apply(null,[1,4])); //5
     console.log(keith.call(null,1,4)); //5
     console.log(keith.bind(null, 1, 4)); //keith()
     console.log(keith.bind(null, 1, 4)()); //5



12. promise 原理

回调函数: 将函数A当作参数给函数B调用,A就是回调函数

1. 具名回调
function B(fn) {
    fn('hahaha')
}

function A(str) {
    console.log(str)
}

B(A)  // hahaha


2. 匿名回调
function B(fn) {
    fn('hahaha')
}
B(function(str) {
    console.log(str)
})

promise解决问题:回调火车

getData1(data1 => {
    getData2(data1, data2 => {

        getData3(data2, data3 => {

           getData4(data3, data4 => {

               getData5(data4, data5 => {

                // 终于取到data5了 }) }) }) }) })

假设上面的任务,想要换一下执行顺序,代码修改起来,就比较麻烦了。如果内容复杂,阅读代码的时候跳来跳去,也让人头大。

如果用promise

getData1()
.then(getData2)
.then(getData3)
.then(getData4)
.then(getData5)
.then(data => {
  // 取到最终data了
})


promise原理: promise是一个构造函数,用来生成promise实例。

通过在函数内部return一个promise对象实例,就可以使用promise的属性和方法进行下一步操作了。

function fnA() {
    return new Promise(function(resolve, reject) {
        if (成功) {
            resolve(value)   // 异步操作成功时调用,把结果作为参数传递出去
        }else {
            reject(error)  // 异步失败时调用,把错误作为参数传递出去
        }
    })
}


  • 调用构造函数得到实例的同时,作为参数的函数会立即实行;
  • 参数函数接受两个回调函数参数resolve和reject;
  • 在参数函数被执行的过程中,如果在其内部调用resolve,会将实例的状态变成fulfilled,调用reject,会将实例的状态变成rejected;
  • 调用resolve和reject能将分别将promise实例的状态变成fulfilled和rejected,只有状态变成已完成(即fulfilled和rejected之一),才能触发状态的回调
  • 调用.then可以为实例注册两种状态,当实例的状态为fulfilled,会触发第一个函数执行,当实例p的状态为rejected,则触发第二个函数执行。

所以promise就是一种异步编程模式。

promise实例有3种状态
pending(待定)    fullfilled(已执行)     rejected(已拒绝)
  • 1个构造函数: new Promise
  • 2个实例方法:.then 和 .catch
  • 4个静态方法:Promise.all、Promise.race、Promise.resolve和Promise.reject


13.  各类排序

  • 冒泡排序      时间复杂度O(n^2)





  • 选择排序    时间复杂度O(n^2)



工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。


其余排序参考:

blog.csdn.net/xiaoxiaojie…

www.jianshu.com/p/d2cf77f78…







原型链

深度克隆

跨域

http相关

vue

react

git

cookie


vue

1. 生命周期

beforeCreate: vue元素的挂载元素el和数据都为undefined,还未初始化;

created:vue实例的数据对象data有了,el还没有;

beforeMount:vue实例的$el和data都初始化了,但还挂载在之前的虚拟dom节点上;

mounted:vue实例挂载完成。

更新前后:data变化时会触发beforeUpdate和updated方法;

销毁前后:beforeDestory和destoryed,在执行destoryed方法后,对data的改变不会触发周期函数,说明vue实例已经解除了事件监听以及dom绑定,但是dom结构依然存在;

vue生命周期的作用: 他的生命周期中有多个事件钩子,让我们控制整个vue实例的过程时更容易形成良好的逻辑

nextTick:更新数据后立即操作dom


2.  computed和watch的区别

computed   计算结果并返回,只有被计算的属性发生改变时才会触发

watch 监听某一个值,监听的值发生变化时,执行相关操作

监听简单数据类型:
data() {
    return {
        val: '2'
    }
},
watch: {
    val() {
        console.log(this.val)
    }
}


3. vue-router跳转方式

this.$router.push()

跳转到不同的url,这个方法会向history栈添加一个记录,点击后退会返回到上一个页面

this.$router.push({path: '/home/sort/detail',query:{id: 'abc'}})     
获取参数 {{this.$route.query.id}}

this.$router.push({name: 'detail',params:{id: 'abc'}})
获取参数:{{this.$route.params.id}} 

ps: query要用path来引入,params要用name来引入
query更加类似于ajax中get传参,params类似于post,前者在浏览器地址栏中显示参数,后者则不显示

1、this.$router.replace()
同样是跳转到指定的url,但是不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。
上一个记录是不存在的。
2、this.$router.go(n)
相对于当前页面向前/后跳转n个页面,类似 window.history.go(n)。n可为正数可为负数

声明式:

根据路由路径(/home/detail)跳转
<router-link :to="{path: '/home/query', query: {id: '12345'}}">跳转子页</router-link>

根据路由名称(detail)跳转
<router-link :to="{name: 'detail', params: {id: '12345'}}"></router-link>


4. vue中的data为什么是一个函数而不是属性值

js中只有函数才可以构成作用域(if(){}和对象的{}都不可构成作用域),data是一个函数时,每个组件实例都有一个自己的作用域,相互独立,互不干扰。

如果data不用函数返回,没有作用域,每个组件的data都是同一块内存地址,一个数据改变了其它数据也改变了

举个例子:

const MyComponent = function() {};
MyComponent.prototype.data = {
    a: 1,
    b: 2,
}
const component1 = new MyComponent();
const component2 = new MyComponent();

component1.data.a === component2.data.a; // true;
component1.data.b = 5;
component2.data.b // 5



const MyComponent = function() {
    this.data = this.data();
};
MyComponent.prototype.data = function() {
    return {
        a: 1,
        b: 2,
    }
};

这都是因为js本身的特性带来的,跟vue本身设计无关


5. vue 双向数据绑定怎么实现的

数据发生变化,视图跟着变化,视图变化,数据也随之发生改变。

核心是 Object.defineProperty()方法

Object.defineProperty( obj,  prop, descriptor)

obj (要定义其上属性的对象)

prop (要定义或修改的属性)

descriptor (具体的改变方法)


简单地说,就是用这个方法来定义一个值。当调用时我们使用了它的get方法,赋值时,又用到了它的set方法;

var obj = {}
Object.defineProperty(obj, 'hello', {
    get: function() {
        console.log('调用了get')
    },
    set: function(newVal) {
        console.log('调用set赋值,值是'+newVal)
    }
})
obj.hello;  // 调用了get
obj.hello = 'hi' // 调用set赋值,值是hi

实现一个简单的双向绑定

<div id="app">
    <input type="text" id="a">
    <span id="b"></span>
</div>

<script>
    vat obj = {}
    var val = '123'
    Object.defineProperty(obj, 'val', {
        get: function () {
            return val;
        },
        set: function(newVal) {
            val = newVal
            document.getElementById('a').value = val;
            document.getElementById('b').innerHTML = val;
        }
    })
    document.addEventListener('keyup', function(e) {
        obj.val = e.target.value
    })
</script>

https://www.jianshu.com/p/e7ebb1500613






http

1. http 和 https 区别

Http:超文本传输协议, 互联网上应用最广泛的一种网络协议。Http协议以明文方式发送信息,如果黑客截取了浏览器和服务器之间的传输报文,就可以直接获得其中的信息。

Https:是以安全为目标的Http通道,是Http的安全版。Https的安全基础是SSL。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。

HTTP与HTTPS的区别

1、http是超文本传输协议,信息是明文传输,https是具有安全性的SSL加密传输协议。

2、http和https使用的是完全不同的连接方式,端口也不一样。前者是80,后者是443。



https://zhuanlan.zhihu.com/p/65798950

https://www.jianshu.com/p/83e74528892c

https://www.cnblogs.com/liuhao-web/p/11589848.html

https://segmentfault.com/a/1190000021809576