一、选择题 (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。因为从上到下执行下去,
语句中的条件应该为
,因为"a"的确是没有定义啊。 随后,顺理成章地进入
,最后,alert出来就应该是1。
而事实上,从JavaScript内部工作原理去看,在变量对象中讲过, JavaScript处理上下文分为两个阶段:
- 进入执行上下文
- 执行代码
可以理解为,第一个阶段是静态处理阶段,第二个阶段为动态处理阶段【这里指上下文执行过程】。
而在静态处理阶段,就会创建
,并且将变量申明作为属性进行填充。
到了执行阶段,才会根据执行情况,来对变量对象中属性(就是申明的变量)的值进行更新。
针对这个问题,其实际过程如下:
- 进入执行上下文: 创建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
setImmediate3、
答案:
防抖函数的作用
防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着 N 秒内函数只会被执行一次,如果 N 秒内再次被触发,则 重新 计算延迟时间。
举例说明: 小思最近在减肥,但是她非常吃吃零食。为此,与其男朋友约定好,如果 10 天不吃零食,就可以购买一个包 (不要问为什么是包,因为 包治百病)。但是如果中间吃了一次零食,那么就要重新计算时间,直到小思坚持 10 天没有吃零食,才能购买一个包。所以,管不住嘴的小思,没有机会买包 (悲伤的故事)... 这就是 防抖。
防抖函数实现
- 事件第一次触发时,timeout 是 null,调用 later(),若 immediate 为true,那么立即调用 func.apply(this, params);如果 immediate 为 false,那么过 wait 之后,调用 func.apply(this, params)。
- 事件第二次触发时,如果 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 时,表示函数在每个等待时延的结束被调用。
防抖的应用场景
- 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
- 表单验证。
- 按钮提交事件。
- 浏览器窗口缩放,resize 事件 (如窗口停止改变大小之后重新计算布局) 等。