JS面试必问问题
Js基础语法与数据类型
简述 JavaScript 中
null和undefined的区别
undefined表示变量已声明但未赋值,函数没有返回值时也会返回undefined,访问对象不存在的属性也会得到undefined。null表示一个空对象指针,是一个原始值,通常用于手动表示某个变量的值为空对象。
let a; console.log(a); // undefined let b = null; console.log(b); // null
解释一下 JavaScript 中的数据类型,以及如何判断数据类型
typeof操作符:返回一个表示数据类型的字符串,但对于null会返回object,对于Array、Date等引用类型都返回object。instanceof操作符:用于判断对象是否是某个构造函数的实例。Object.prototype.toString.call():能准确判断所有数据类型。
基本数据类型:
Number、String、Boolean、Null、Undefined、Symbol(ES6 新增)、BigInt(ES2020 新增)。引用数据类型:
Object(包括Array、Function、Date等)。判断方法:
let num = 10; console.log(typeof num); // number let arr = []; console.log(arr instanceof Array); // true let bool = true; console.log(Object.prototype.toString.call(bool)); // [object Boolean]
如何实现数组去重
// 方法一:使用 Set let arr = [1, 2, 2, 3, 4, 4]; let uniqueArr = [...new Set(arr)]; console.log(uniqueArr); // 方法二:使用 filter 和 indexOf let uniqueArr2 = arr.filter((item, index) => arr.indexOf(item) === index); console.log(uniqueArr2);
作用域、闭包和 this 指向
解释 JavaScript 中的作用域和闭包
作用域:定义了变量和函数的可访问范围,分为全局作用域和函数作用域(ES6 新增块级作用域)。变量和函数的作用域决定了它们在代码中的可见性和生命周期。
闭包:指有权访问另一个函数作用域中变量的函数。即使该函数已经执行完毕,其作用域内的变量也不会被销毁,而是会被闭包引用。
function outer() {
let num = 10;
function inner() {
console.log(num);
}
return inner;
}
let closure = outer();
closure(); // 10简述
this关键字在不同场景下的指向
全局作用域中:在浏览器环境中,
this指向window对象。函数内部:默认情况下,
this指向调用该函数的对象;如果是构造函数,this指向新创建的对象。使用
call、apply或bind方法:可以手动指定this的指向。
// 全局作用域
console.log(this === window); // true
// 函数内部
function test() {
console.log(this);
}
test(); // window
// 构造函数
function Person(name) {
this.name = name;
}
let person = new Person('John');
console.log(person.name); // John
// 使用 call 改变 this 指向
let obj = { name: 'Alice' };
function greet() {
console.log(`Hello, ${this.name}`);
}
greet.call(obj); // Hello, Alice异步编程
解释 JavaScript 中的异步编程,以及为什么需要异步编程
异步编程:允许代码在执行耗时操作(如网络请求、文件读取等)时不会阻塞后续代码的执行,而是继续执行其他任务,当耗时操作完成后再处理其结果。
原因:JavaScript 是单线程的,如果没有异步编程,在执行耗时操作时,整个程序会被阻塞,用户界面会出现卡顿,影响用户体验。
简述 Promise 的三种状态和常用方法
then():用于处理Promise成功的结果。catch():用于处理Promise失败的结果。finally():无论Promise状态如何都会执行。
pending(进行中):初始状态。fulfilled(已成功):操作成功完成。rejected(已失败):操作失败。
三种状态:
常用方法:
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success');
}, 1000);
});
promise.then(result => {
console.log(result);
}).catch(error => {
console.error(error);
}).finally(() => {
console.log('Promise completed');
});如何使用
async/await处理异步操作async/await是 ES8 引入的语法糖,用于更优雅地处理异步操作。async函数返回一个Promise对象,await只能在async函数内部使用,用于等待一个Promise完成,并返回其结果。
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched');
}, 1000);
});
}
async function getData() {
try {
let data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}
getData();面向对象编程
如何在 JavaScript 中实现继承
原型链继承:通过原型对象实现继承。
构造函数继承:在子类构造函数中调用父类构造函数。
组合继承:结合了原型链继承和构造函数继承的优点。
寄生组合继承:在组合继承的基础上进行优化。
ES6 类继承:使用
class和extends关键字实现继承。
// ES6 类继承示例
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
speak() {
console.log(`${this.name} barks.`);
}
}
let dog = new Dog('Buddy');
dog.speak(); // Buddy barks.简述 JavaScript 中的原型和原型链
原型:每个对象都有一个内部属性
[[Prototype]](在浏览器中可以通过__proto__访问),它指向该对象的原型对象。原型对象也是一个对象,它也有自己的原型,以此类推,直到最顶层的原型对象Object.prototype。原型链:当访问一个对象的属性或方法时,JavaScript 首先会在该对象本身查找,如果找不到,就会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(
Object.prototype)。
性能优化和错误处理
如何优化 JavaScript 代码的性能
减少 DOM 操作:DOM 操作是比较耗时的,尽量批量操作 DOM,减少重排和重绘。
使用事件委托:将事件处理程序绑定到父元素上,利用事件冒泡机制处理子元素的事件,减少事件处理程序的数量。
压缩和合并代码:减少 HTTP 请求和文件大小。
使用节流和防抖:对于频繁触发的事件(如滚动、输入框输入等),使用节流和防抖函数限制事件的触发频率。
// 防抖函数示例
function debounce(func, delay) {
let timer;
return function() {
let context = this;
let args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
};
}
function handleInput() {
console.log('Input event triggered');
}
let input = document.getElementById('input');
input.addEventListener('input', debounce(handleInput, 300));如何处理 JavaScript 中的错误
try...catch语句:用于捕获和处理同步代码中的错误。Promise的catch()方法:用于处理Promise中的错误。window.onerror事件:用于捕获全局未处理的错误。
try {
let result = 1 / 0;
} catch (error) {
console.error(error.message);
}
let promise = new Promise((resolve, reject) => {
reject(new Error('Promise error'));
});
promise.catch(error => {
console.error(error.message);
});
window.onerror = function(message, source, lineno, colno, error) {
console.err