简述 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);
解释 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.error(`Global error: ${message}`); };