解析面试题二

283 阅读11分钟

解析面试题二

这是我的面试环节,糟糕透了。脑子空白。话不多说,解决答案

1.问垂直居中的方案

以下几种:
方法一:flex布局实现

<!-- html部分 -->
    <div class="center">
        <div>垂直居中</div>
    </div>
 /* css部分 */
       .center{
           width: 300px;
           height: 200px;
           display: flex;
           align-items: center;
           border: 2px solid blue;
        }

方法二:单行文本垂直居中

<!-- html部分方案一 -->
    <div class="center">
        123
    </div>
/* css部分方案一 */
       .center{
            padding-top:50px;
            padding-bottom:50px;
            background: indianred;
        }
 <!-- html部分方案二 -->
    <div class="center">
        123
    </div>
/* css部分方案二 */
       .center{
           width: 300px;
           height: 200px;
           line-height: 200px;
            background: indianred;
        }

方案三:多行文本垂直居中
通过设置父元素table,子元素table-cell和vertical-align
vertical-align:middle的意思是把元素放在父元素的中部

<!-- html部分 -->
    <div class="center">
        <div class="table-div">多行文本垂直居中</div>
    </div>
 /* css部分 */
       .center{
           width: 300px;
           height: 200px;
           display: table;
            border: 2px solid blue;
        }
        .table-div{
            display: table-cell;
            vertical-align: middle;
            border: 1px solid red;
        }

方案四:利用position和top/bottom和margin:auto(注意不是margin:0 auto)
1.position:absolute/relative/fixed
2.top/bottom:0
3.margin:auto

<!-- html部分 -->
    <div class="parent">
        <div class="child">已知高度垂直居中</div>
    </div>
 /* css部分 */
       .parent{
           position: relative;
           width: 200px;
           height: 200px;
           border: 1px solid blue;
        }
        .child{
            position: absolute;
            height: 100px;
            width: 150px;
            top: 0;
            bottom: 0;
            margin: auto;
            line-height: 100px;
            background-color: red;
        }

方案五:利用position和top和transform
 transform中的translate偏移的百分比就是相对元素自身的尺寸而言的。
 transform方法,可用于未知元素大小的居中

<!-- html部分 -->
    <div class="parent">
        <div class="child">已知高度垂直居中</div>
    </div>
 /* css部分 */
       .parent{
           position: relative;
           width: 200px;
           height: 200px;
           border: 1px solid blue;
        }
        /* 不知道被居中元素的尺寸 */
        .child{
            position: absolute;
            top: 50%;
            transform: translate(0,-50%);
            line-height: 100px;
            background-color: red;
        }

顺便把垂直水平居中的再复习一下
方案一:绝对定位+margin:auto

<!-- html部分 -->
   <div></div>
/* css部分 */
    div{
        width: 200px;
        height: 200px;
        background: green;
        position:absolute;
        left:0;
        top: 0;
        bottom: 0;
        right: 0;
        margin: auto;
    }

方案二:绝对定位+负margin

<!-- html部分 -->
   <div></div>
 /* css部分 */
   div{
        width:200px;
        height: 200px;
        background:green;
        position: absolute;
        left:50%;
        top:50%;
        margin-left:-100px;
        margin-top:-100px;
    }
        

方案三:绝对定位+transform

<!-- html部分 -->
    <div></div>
/* css部分 */
        div {
            width: 200px;
            height: 200px;
            background: green;
            position: absolute;
            left: 50%;
            /* 定位父级的50%*/
            top: 50%;
            transform: translate(-50%,-50%);/*自己的50%*/
        }

方案四:flex布局

<!-- html部分 -->
    <div class="box">
        <div></div>
    </div>
/* css部分 */
         .box{
             height: 600px;
             display: flex;
             justify-content: center;
             align-items: center;
         }
         .box>div{
            background: indianred;
            width: 200px;
            height: 200px;
         }

方案五:设置table-cell来实现居中
  设置  display:table-cell;
           text-align:center;
          vertical-align: middle;

<!-- html部分 -->
    <div class="parent">
        <div>123</div>
    </div>
/* css部分 */
         .parent{
             height: 200px;
             width: 200px;
             display: table-cell;
             text-align: center;
             border: 1px solid #ccc;
             vertical-align: middle;
         }

2.rgba()和opacity的透明效果有什么不同?

rgba()和opcity都能实现透明效果,但是最大的不同是opacity作用于元素,以及元素内的所有内容的透明度,
    而rgba()只作用于元素的颜色或其背景色。(设置rgba透明的元素的子元素不会继承透明效果)

3.闭包原理 具体请看以下链接(www.ruanyifeng.com/blog/2009/0…


闭包就是能够读取其他函数内部变量的函数。 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。 

4.面向对象编程的思想

基本思想是使用对象,类,继承,封装等基本概念来进行程序设计
优点:易维护,采用面向对象思想设计的结构,可读性更高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。易扩展:开发工作的重用性、继承性高,降低重复工作量。缩短开发周期。

5.let var const的区别

var声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的
由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明;
let是更完美的var,不是全局变量,具有块级函数作用域,大多数情况不会发生变量提升。

  1. let声明的变量具有块级作用域
  2. let声明的变量不能通过window.变量名访问
  3. 形如for(let x...)的循环是每次迭代都为x创建新的绑定
  4. let约束了变量提升
  5. let不允许在相同作用域内重复声明同一个变量名,var是允许的

const定义的常量值,不能够重新赋值,如果值是一个对象,可以改变对象里边的属性值。const变量声明的时候必须初始化。

6.判断对象数组的方法

1.instanceof

//检测数组
let arr = []
console.log(arr instanceof Array) // true
//检测对象
console.log(arr instanceof Object) // true

2.constructor

let arr = [];
console.log(arr.constructor === Array) // true
console.log(arr.constructor === Object) // false

7.jsonp原理

jsonp的原理就是利用script标签没有跨域限制,通过script标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。

 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.localhost.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);

    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>
服务端返回数据
handleCallback({"success": true, "user": "admin"})

8.跨域解决方案:

1.解决方案jsonp实现如7所示。
2.document.domain+iframe跨域

1.父窗口:(http://www.domain.com/a.html)
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
 <script>
    document.domain = 'domain.com';
     var user = 'admin';
</script>
2.子窗口(http://child.domain.com/b.html)
<script>
    document.domain = 'domain.com';
       // 获取父窗口中变量
        alert('get js data from parent ---> ' + window.parent.user);
 </script>
弊端:查看页面渲染优化

3.nginx代理跨域
4.nodejs中间件代理跨域
5.后端在头部信息里面设置安全域名
更多的方案请参考:(juejin.cn/post/684490…

9.rem、px、em区别

px在缩放页面时无法调整那些使用它作为单位的字体、按钮等的大小;
em的值并不是固定的,会继承父级元素的字体大小,代表倍数;

rem的值并不是固定的,始终是基于根元素 html的也代表倍数。

10.深拷贝、浅拷贝实现

1.a和b指向了同一块内存,所以修改其中任意一个值,另外一个值也会随之变化,这是浅拷贝。
2.a和b指向同一块内存,但是修改其中任意一个值,另外一个调用的变量,不会受到影响,这是深拷贝  
  深拷贝的实现

let a = {
    age: 1,
    jobs: {
        first: 'FE'
    }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
该方法也是有局限性的
会忽略undefined
不能序列化函数
不能解决循环引用的对象

浅拷贝的实现方式
1.Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

var obj = {a:{a:"iwen",b:39}};
var initalObj = Object.assign({},obj);
initalObj.a.a = "kievn";
console.log(obj.a.a);//kievn

2.Array.prototype.concat()

let arr = [1,3,{
     username:'iwen'
   }];
let arr2 = arr.concat();
arr2[2].username = 'kievn';
console.log(arr);
//修改新对象会修改到原对象。

3.Array.prototype.slice()

let arr = [1,3,{
     username:'iwen'
   }];
let arr2 = arr.slice();
arr2[2].username = 'kievn';
console.log(arr);
//同上修改新对象会修改到原对象。

11.工作中有没有用到防抖和节流

防抖
防抖(debounce) 所谓防抖,就是指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间。 防抖函数分为非立即执行版和立即执行版。
非立即执行:触发事件后函数不会立即执行,而是在n秒后执行,如果在n秒内又触发了事件,则会重新计算函数执行时间。
单独版:

function debounce(func, wait) {
        let timeout
        return function () {
            let context = this
            let args = arguments
            if (timeout) clearTimeout(timeout)
            timeout = setTimeout(() => {
                func.apply(context, args)
            }, wait)
        }
    }

完整版:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #con {
            height: 100%;
            width: 100%;
            position: absolute;
            line-height: 600px;
            text-align: center;
            color: #ff0000;
            background-color: #ffff00;
            font-size: 100px;
        }
    </style>
</head>
<body>
<div id="con">
</div>
<script>
    let num = 1
    let con = document.getElementById('con')

    function count() {
        con.innerHTML = num++
    }

    function debounce(func, wait) {
        let timeout
        return function () {
            let context = this
            let args = arguments
            if (timeout) clearTimeout(timeout)
            timeout = setTimeout(() => {
                func.apply(context, args)
            }, wait)
        }
    }

    con.onmousemove = debounce(count, 1000)
</script>
</body>
</html>

立即执行:触发事件后函数会立即执行,然后n秒后不触发事件才能继续执行函数。
单独版:

function debounce(func, wait) {
        let timeout
        return function () {
            let context = this
            let args = arguments
            if (timeout) clearTimeout(timeout)
            console.log('timeout',timeout)
            let callNow = !timeout
            timeout = setTimeout(() => {
                timeout = null
            }, wait)
            if (callNow) func.apply(context, args)
        }
    }

完整版:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #con {
            height: 100%;
            width: 100%;
            position: absolute;
            line-height: 600px;
            text-align: center;
            color: #ff0000;
            background-color: #ffff00;
            font-size: 100px;
        }
    </style>
</head>
<body>
<div id="con">
</div>
<script>
    let num = 1
    let con = document.getElementById('con')

    function count() {
        con.innerHTML = num++
    }

    function debounce(func, wait) {
        let timeout
        return function () {
            let context = this
            let args = arguments
            if (timeout) clearTimeout(timeout)
            let callNow = !timeout
            timeout = setTimeout(() => {
                timeout = null
            }, wait)
            if (callNow) func.apply(context, args)
        }
    }

    con.onmousemove = debounce(count, 1000)
</script>
</body>
</html>

节流
连续触发事件,但是在n秒中只执行一次。节流会稀释函数的执行频率。
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。 时间戳版:

function throttle(func, wait) {
        var previous = 0
        return function () {
            let now = Date.now()
            let context = this
            let args = arguments
            if (now - previous > wait) {
                func.apply(context, args)
                previous = now
            }
        }
    }

在持续触发事件过程中,函数会立即执行,并且每1秒执行一次。
当时间每过去n秒后,执行加一事件。 完整版:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #con {
            height: 100%;
            width: 100%;
            position: absolute;
            line-height: 600px;
            text-align: center;
            color: #ff0000;
            background-color: #ffff00;
            font-size: 100px;
        }
    </style>
</head>
<body>
<div id="con">
</div>
<script>
    let num = 1
    let con = document.getElementById('con')

    function count() {
        con.innerHTML = num++
    }

    function throttle(func, wait) {
        var previous = 0
        return function () {
            let now = Date.now()
            let context = this
            let args = arguments
            if (now - previous > wait) {
                func.apply(context, args)
                previous = now
            }
        }
    }

    con.onmousemove = throttle(count, 1000)
</script>
</body>
</html>

定时器版:

 function throttle(func, wait) {
        let timeout
        return function () {
            let context = this
            let args = arguments
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null
                    func.apply(context, args)
                }, wait)
            }
        }
    }

持续触发事件时,每当n秒后执行一次,timeout设为空。当为空又开始执行。
在持续触发事件的过程中,函数不会立即执行,并且每 1s 执行一次,在停止触发事件后,函数还会再执行一次。 我们应该可以很容易的发现,其实时间戳版和定时器版的节流函数的区别就是,时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #con {
            height: 100%;
            width: 100%;
            position: absolute;
            line-height: 600px;
            text-align: center;
            color: #ff0000;
            background-color: #ffff00;
            font-size: 100px;
        }
    </style>
</head>
<body>
<div id="con">
</div>
<script>
    let num = 1
    let con = document.getElementById('con')

    function count() {
        con.innerHTML = num++
    }

    function throttle(func, wait) {
        let timeout
        return function () {
            let context = this
            let args = arguments
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null
                    func.apply(context, args)
                }, wait)
            }
        }
    }

    con.onmousemove = throttle(count, 1000)
</script>
</body>
</html>

                                                                 每日一句                                              

时间能治愈一切,请给时间一点时间。