2019 前端面试押题卷(1)【高级】

733 阅读7分钟

一、选择题 (5道 * 5)

1. 表达式 [0, 1, 2].map(parseInt) 的结果为?

A. [0, 1, 2]

B. [0, 1, NaN]

C. [NaN, NaN, NaN]

D. [0, NaN, NaN]


2. 标签中设置图片加载失败的替换文本的属性名称是?

A. alt

B. title

C. text

D. content


3. 以下哪一个 CSS 样式会创建块格式化上下文(BFC)?

A. float: none;

B. position: relative;

C. display: inline-flex;

D. overflow: visible;


4. 以下 CSS代码中设置的 标签的最终颜色是?

div { color: red; }

.test { color: green; }

[class="test"] { color: blue; }

html div { color: yellow; }

A. red

B. green

C. blue

D. yellow


5. 在跨域资源共享(CORS)中,浏览器会使用什么方法发起预检请求?

A. HEAD

B. OPTIONS

C. GET

D. POST


二、简答题 (3道 * 15)

1. 考查JS运行时的理解,下列代码的运行结果是?


if (!("a" in window)) {
    var a = 1;
}
alert(a);


2. 理解宏任务和微任务,在Node.js运行环境中输出结果是?

process.nextTick(() => {
  console.log('nextTick')
})
Promise.resolve()
  .then(() => {
    console.log('then')
  })
setImmediate(() => {
  console.log('setImmediate')
})
console.log('end')


3. 防抖函数的作用是什么?请实现一个防抖函数


三、编程题 (2道 * 15)

1. 使用 Promise封装一个 ajax


var getJSON = function (url) {
    var promise = new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open("GET", url);
        client.onreadystatechange = handler;
        client.responseType = "json";
        client.setRequestHeader("Accept", "application/json");
        client.send();

        function handler() {
            if (this.readyState !== 4) {
                return;
            }
            if (this.status === 200) {
                resolve(this.response);
            } else {
                reject(new Error(this.statusText));
            }
        };
    });

    return promise;
};

getJSON("http://songfens.club:3000/goods/list?page=1&pageSize=8&sort=1&priceLevel=all").then(function (json) {
    console.log('Contents: ' + JSON.stringify(json));
    return json.result;
}, function (error) {
    console.error('出错了', error);
})
    .then(x=> console.log(x.count));


2. 请实现一个 uniq 函数,实现数组去重

例如:

uniq([7, 7, 2, 0, 8, 3, 6, 1, 2]);//[0, 1, 2, 3, 6, 7, 8]

法 1: 利用 ES6 新增数据类型 Set

Set类似于数组,但是成员的值都是唯一的,没有重复的值。

function uniq(arry) {
    return [...new Set(arry)];
}

法 2: 利用 indexOf

function uniq(arry) {
    var result = [];
    for (var i = 0; i < arry.length; i++) {
        if (result.indexOf(arry[i]) === -1) {
            // 如 result 中没有 arry[i], 则添加到数组中
            result.push(arry[i])
        }
    }
    return result;
}

法 3: 利用 includes

function uniq(arry) {
    var result = [];
    for (var i = 0; i < arry.length; i++) {
        if (!result.includes(arry[i])) {
            // 如 result 中没有 arry[i], 则添加到数组中
            result.push(arry[i])
        }
    }
    return result;
}

法 4:利用 reduce

function uniq(arry) {
    return arry.reduce((prev, cur) => prev.includes(cur) ? prev : [...prev, cur], []);
}

法 5:利用 Map

function uniq(arry) {
    let map = new Map();
    let result = new Array();
    for (let i = 0; i < arry.length; i++) {
        if (map.has(arry[i])) {
            map.set(arry[i], true);
        } else {
            map.set(arry[i], false);
            result.push(arry[i]);
        }
    }
    return result;
}



答案解析:

一、选择题答案及解析

1、

考点:对 Array.prototype.map() 以及 parseInt() 方法的理解程度。

答案:D

解析:Array.prototype.map((value, index) => {})方法会将数组的值(value)和索引(index)传给 parseInt() 方法并生成一个新数组,因此,上面的表达式也就相当于:

[

parseInt(0, 0), // 0

parseInt(1, 1), // NaN

parseInt(2, 2), // NaN

]

这里顺便问一下 Array.prototype.filter() 以及 Array.prototype.reduce() 的用法。

参考文档:[Array.prototype.map()]、[parseInt()]


2、

考点:DOM 标签的基本属性。

答案:A

解析:title 属性是当用户鼠标移动到标签上面时,作为提示信息展示给用户看的文本。

参考文档:[img 标签]


3、

考点:块格式化上下文(BFC)。

答案:C

解析:A 和 D 应该没有争议。注意 B 选项 position 为 absolute 或 fixed 才会创建 BFC,relative 是不会创建 BFC 的。这里可以深入问一下双 margin 合并的问题。

参考文档:[块格式化上下文(BFC)]、[外边距合并]


4、

考点:CSS 选择器的优先级判断。

答案:C

解析:规范中 CSS 选择器的优先级分别是(从低到高):

1. 类型选择器(<div>)、伪元素(::before)。

2. 类选择(.class)、属性选择器([type="button"])、伪类(:hover)。

3. ID 选择器(#id)。

当优先级相同的情况,按照 CSS 样式的执行顺序确定最终的优先级。

上面的代码中 A 和 D 都是类型选择器,因此小于 B 和 C 的类选择器和属性选择器。并且由于 C 在B 后面执行,所以最终的颜色是 C(blue)。

参考文档:[CSS 优先级]


5、

考点:跨域资源共享(CORS)的一些常识的掌握程度。

答案:B

解析:这里可以顺便问一下服务器应该如何响应预检请求、以及JSONP 相关的知识点。

Access-Control-Allow-Origin: *

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Allow-Headers: Content-Type

Access-Control-Max-Age: 86400

参考文档:[HTTP访问控制(CORS)]


二、简答题

1、

答案:

  • 正确答案: undefined

解释:

这个问题,初一看感觉答案很自然是1。因为从上到下执行下去,

if

语句中的条件应该为

true

,因为"a"的确是没有定义啊。 随后,顺理成章地进入

var a = 1;

,最后,alert出来就应该是1。

而事实上,从JavaScript内部工作原理去看,在变量对象中讲过, JavaScript处理上下文分为两个阶段:

  • 进入执行上下文
  • 执行代码

可以理解为,第一个阶段是静态处理阶段,第二个阶段为动态处理阶段【这里指上下文执行过程】。

而在静态处理阶段,就会创建

变量对象(variable object)

,并且将变量申明作为属性进行填充。

到了执行阶段,才会根据执行情况,来对变量对象中属性(就是申明的变量)的值进行更新。

针对这个问题,其实际过程如下:

  • 进入执行上下文: 创建VO,并填充变量申明
    a
    ,VO如下所示:
VO(global) = {
    a: undefined
}

所以,这个时候,a其实已经存在了。

  • 执行代码: 进入
    if
    语句,发现条件判断
    “a” in window
    true。于是就不会进入if代码块,直接执行alert语句,因此,最终为undefined


2、

答案:

同步代码->微任务(process.nextTick 优先级大于 Promise.then)-> 宏任务(setImmediate)

end
nextTick
then
setImmediate

3、

答案:

防抖函数的作用

防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着 N 秒内函数只会被执行一次,如果 N 秒内再次被触发,则 重新 计算延迟时间。

举例说明: 小思最近在减肥,但是她非常吃吃零食。为此,与其男朋友约定好,如果 10 天不吃零食,就可以购买一个包 (不要问为什么是包,因为 包治百病)。但是如果中间吃了一次零食,那么就要重新计算时间,直到小思坚持 10 天没有吃零食,才能购买一个包。所以,管不住嘴的小思,没有机会买包 (悲伤的故事)... 这就是 防抖

防抖函数实现

  1. 事件第一次触发时,timeout 是 null,调用 later(),若 immediate 为true,那么立即调用 func.apply(this, params);如果 immediate 为 false,那么过 wait 之后,调用 func.apply(this, params)。
  2. 事件第二次触发时,如果 timeout 已经重置为 null(即 setTimeout 的倒计时结束),那么流程与第一次触发时一样,若 timeout 不为 null(即 setTimeout 的倒计时未结束),那么清空定时器,重新开始计时。
function debounce(func, wait, immediate = true) {
    let timeout, result;
    // 延迟执行函数
    const later = (context, args) => setTimeout(() => {
        timeout = null;// 倒计时结束
        if (!immediate) {
            // 执行回调
            result = func.apply(context, args);
            context = args = null;
        }
    }, wait);
    let debounced = function (...params) {
        if (!timeout) {
            timeout = later(this, params);
            if (immediate) {
                // 立即执行
                result = func.apply(this, params);
            }
        } else {
            clearTimeout(timeout);
            // 函数在每个等待时延的结束被调用
            timeout = later(this, params);
        }
        return result;
    }
    // 提供在外部清空定时器的方法
    debounced.cancel = function () {
        clearTimeout(timeout);
        timeout = null;
    };
    return debounced;
};

immediate 为 true 时,表示函数在每个等待时延的开始被调用。immediate 为 false 时,表示函数在每个等待时延的结束被调用。

防抖的应用场景

  1. 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
  2. 表单验证。
  3. 按钮提交事件。
  4. 浏览器窗口缩放,resize 事件 (如窗口停止改变大小之后重新计算布局) 等。