前端面试 -- 原生JS面试精题
原生JS面试精题
在前端面试专栏的前几篇文章中,我们了解到了JS和页面布局相关的一些面试重点考察内容,本篇文章将继续讲述面试中经常遇到的一些原生JS面试精题。废话不多说,一起来看看吧!
1-手动实现一个bind方法
// 手动实现一个bind方法
Function.prototype.bind = function(target) {
// this指代调用bind的函数,
var fn = this;
return function() { // 此处利用闭包
fn.apply(target, arguments);
}
}
function fn() {
console.log(this); // {x: 100}
}
var newAlert = fn.bind({x: 100});
newAlert();
2-普通函数与箭头函数的this
- 普通函数有自己的this,箭头函数没有自己的this,所以在确定箭头函数中的this指向时,可以当箭头函数不存在,去父级作用域中找this
// 普通函数
let test1 = function() {
}
// 箭头函数:去掉function,加入一个箭头
let test2 = () => {
}
var id = 100;
let obj = {
id: 99,
hello: () => {
console.log(this); // this指向window 当箭头函数不存在,去父级作用域找this
console.log(this.id); // 100
},
print: function() {
// setTimeout里面的函数都是由window调用的
setTimeout(function() {
console.log(this); // this指向window obj调用的是print函数,并不是setTimeout里面的匿名函数
console.log(this.id); // 100
}, 300);
setTimeout(() => {
console.log(this.id); // 99
}, 300);
}
}
obj.hello();
obj.print();
3-eval函数
- 在严格模式下,eval有单独的作用域
// "use strict"; // 必须在首句
var b = 100;
function test() {
eval('var b = 20; alert(b);'); // 等价于 var b = 20;
eval('var c = 30');
console.log(c); // // 30
console.log(b); // 在严格模式下,eval有单独的作用域,输出100,非严格模式下,输出20
}
test();
// console.log(c); // 报错,因为c是在函数作用域里
4-函数防抖与函数节流
区别: 函数防抖是删除前一个,函数节流是不执行下一个
4-1 函数防抖
- 实现原理:使用延迟器,让本该立即调用的函数延迟调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>函数防抖</title>
</head>
<body>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<script>
function debounce(callback, delay = 300) {
var t = null;
return function(e) {
clearTimeout(t);
t = setTimeout(() => {
callback.call(e);
}, delay);
}
}
// 会出现抖动现象
// window.onscroll = function() {
// console.log('调用了1次');
// }
// 函数防抖
window.onscroll = debounce(function() {
console.log('调用了1次');
}, 500);
</script>
</body>
</html>
4-2 函数节流
- 实现原理:控制函数执行的频率,在规定时间段内只能执行一次
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>函数节流</title>
</head>
<body>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<script>
// 函数节流: 控制函数执行的频率,在duration时间段内只能执行一次
function throttle(callback, duration) {
// var lasttime = 0;
var lasttime = new Date().getTime();
return function() {
var now = new Date().getTime();
if(now - lasttime > 500) {
callback();
lasttime = now;
}
}
}
window.onscroll = throttle(function() {
console.log('调用了1次');
}, 500);
</script>
</body>
</html>
5-柯里化
- 含义:函数的多参变成单参
- 实现原理:利用闭包
// 多参
function fn1(a, b, c) {
return a * b * c;
}
// 单参
function fn2(a) {
return function(b) {
return function(c) {
return a * b * c;
}
}
}
// 多参调用
console.log(fn1(1, 3, 4));
console.log(fn1(1, 5, 6));
console.log(fn1(1, 3, 9));
console.log(fn1(1, 2, 4));
// 单参调用
let ft = fn2(1);
console.log(ft(3)(4));
console.log(ft(5)(6));
console.log(ft(3)(9));
console.log(ft(2)(4));
6-垃圾回收(GC)机制
1-引用计数法
- 特点:标记引用次数,引用次数为0即被清理
- 缺点:产生很多碎片,需要整理
- 浏览器常用
2-标记清除法
- 特点:每隔一段时间清理一次
- 缺点:产生很多碎片,需要整理
- 这种方法不常见
3-标记整理法
- 特点:每隔一段时间清理一次,并重新排序
- 浏览器常用
4-复制整理法
- 特点:复制的时候进行清理,并重新排序
- 缺点:内存一分为二,有一半内存无法使用
- Java使用这个方法