闭包是什么?有什么优点和缺点?
- 解释:闭包就是能够读取其他函数内部变量的函数,能够实现函数外部访问到函数内部的变量。
- 优点:可以重复利用变量,并且该变量不会污染全局;隔离作用域,保护私有变量;让函数外部可以操作(读写)函数内部的数据(变量/函数);变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期。
- 缺点:闭包较多时,会消耗内存,导致页面性能下降。如果不释放内存,会引起内存泄漏。
原型链是什么?它是如何工作的?
- 解释:原型链是JavaScript实现继承的一种机制。每个对象都有一个原型对象,对象从其原型对象继承属性和方法。如果对象自身没有某个属性或方法,就会去其原型对象上查找,直到找到或原型链的顶端(null)为止。
作用域链是什么?它在JS中起什么作用?
- 解释:作用域链是函数在查找变量时的一个路径。当函数被调用时,会创建一个执行上下文,这个上下文包含了函数可以访问的所有变量。作用域链就是这个上下文中变量对象的一个有序列表,函数会按照这个列表的顺序去查找变量。
- 作用:确保函数能够正确地访问到其所需的变量,无论是函数内部的局部变量,还是全局变量,或者是通过原型链继承的变量。
什么是防抖(Debouncing)和节流(Throttling)?
- 防抖:当事件被频繁触发时,只在最后一次事件触发后的一段时间内执行一次回调函数,避免函数被频繁调用。
- 节流:在一段时间内只允许一次函数调用,如果在这段时间内再次触发事件,就重新计时。
JavaScript中的数据类型有哪些?如何判断一个变量的类型?
- 数据类型:JavaScript中有原始类型(如字符串、数字、布尔值、null、undefined、Symbol)和对象类型(如数组、函数、对象)。
-
判断类型:可以使用
typeof
操作符来判断一个变量的类型,但对于对象和数组,typeof
都会返回“object”。对于数组,可以使用Array.isArray()
方法来判断。
如何判断一个变量是否是数组?
-
方法:可以使用
Array.isArray()
方法来判断一个变量是否是数组。
什么是事件委托?它有什么优点?
- 解释:事件委托是利用事件冒泡的原理,将事件监听器添加到父元素上,而不是直接添加到子元素上。当子元素触发事件时,事件会冒泡到父元素,父元素上的监听器会捕获并处理这个事件。
- 优点:可以减少内存消耗,因为只需要在父元素上添加一个监听器;同时,也可以方便地管理动态添加的子元素的事件。
JavaScript的事件循环(Event Loop)是什么?它是如何工作的?
- 解释:事件循环是JavaScript异步编程机制的核心。它允许JavaScript执行代码时,不会阻塞后续代码的执行。当执行到异步操作时(如网络请求、定时器),JavaScript会将这个操作交给Web APIs去处理,然后继续执行后续的代码。当异步操作完成时,会将一个回调函数放入任务队列中。事件循环会不断地检查任务队列,如果有任务,就将其取出并执行。
JavaScript的垃圾回收机制是什么?
- 解释:JavaScript使用自动垃圾回收机制来管理内存。当一个对象不再被引用时,它就会被标记为垃圾,并在后续的垃圾回收过程中被回收。常见的垃圾回收算法有标记-清除(Mark-and-Sweep)和分代回收(Generational Garbage Collection)。
var、const和let的区别是什么?
- var:是ES5及以前版本中声明变量的关键字,它声明的变量是函数作用域的,可以在声明之前使用(但会导致变量提升)。
- let:是ES6中引入的新关键字,它声明的变量是块作用域的,不能在声明之前使用。
- const:也是ES6中引入的新关键字,它用于声明常量,声明的变量必须在声明时初始化,且之后不能再次赋值。
this的指向是什么?它是如何确定的?
- 解释:this是JavaScript中的一个关键字,它指向函数执行时的上下文对象。在全局作用域中,this指向全局对象(在浏览器中是window对象)。在函数内部,this的指向取决于函数的调用方式。如果是作为对象的方法调用,this指向调用该方法的对象;如果是作为普通函数调用,this指向全局对象(或在严格模式下为undefined);如果是通过构造函数创建对象时调用,this指向新创建的对象。
new操作符是做什么用的?它是如何工作的?
- 解释:new操作符用于创建一个对象的实例。它首先创建一个空对象,然后将这个对象的原型设置为构造函数的prototype属性指向的对象。接着,执行构造函数中的代码,将this指向新创建的对象。最后,如果构造函数没有返回对象,则默认返回新创建的对象。
ES6中有哪些新特性?
- 新特性:ES6引入了许多新特性,包括块级作用域(let和const)、箭头函数、模板字符串、解构赋值、默认参数、类(class)、模块(import/export)等。
如何实现JavaScript的模块化?
- 方法:在ES6之前,可以使用CommonJS、AMD、CMD等模块规范来实现模块化。在ES6中,引入了模块(import/export)语法,可以方便地实现模块化。
JavaScript中实现继承的方式有哪些?
- 方式:JavaScript中实现继承的方式有原型链继承、借用构造函数继承、组合继承、原型式继承、寄生式继承和寄生组合式继承等。
箭头函数与普通函数的区别是什么?
- 区别:箭头函数没有自己的this、arguments、super或new.target。这些函数表达式更适合用于非方法函数,并且它们不能用作构造函数。箭头函数没有原型属性,且不能通过new操作符调用。另外,箭头函数没有自己的this绑定,它会捕获其所在上下文的this值作为自己的this值。
call、apply、bind的区别是什么?
- call:调用一个函数,其具有一个指定的this值和分别提供的参数。
- apply:调用一个函数,其具有一个指定的this值,以及以一个数组(或类数组对象)的形式提供的参数。
- bind:创建一个新的函数,当被调用时,将其this关键字设置为提供的值,在调用新函数时,可给定最初调用的参数。
for in和for of的区别是什么?
- for in:用于遍历对象的可枚举属性(包括原型链上的属性)。
- for of:用于遍历可迭代对象(如数组、字符串、Map、Set等)的值。
什么是Promise?它解决了什么问题?
- 解释:Promise是JavaScript中的一个对象,代表了一个异步操作的最终完成(或失败)及其结果值。它允许你使用链式调用的方式来处理异步操作的结果,从而避免了传统异步编程中的回调地狱问题。
async和await是什么?它们是如何工作的?
- 解释:async和await是基于Promise的异步编程语法糖。async用于声明一个异步函数,它会隐式地返回一个Promise。await用于等待一个Promise完成,并返回Promise的结果。await只能在async函数内部使用。
什么是柯里化(Currying)?
- 解释:柯里化是把接受多个参数的函数,变换为接受一个单一参数(最初函数的第一个参数)的函数,并且返回一个新的函数,这个新的函数接受余下的参数且返回结果。
如何判断元素是否出现在视口(Viewport)中?
-
方法:可以使用
Element.getBoundingClientRect()
方法获取元素的大小及其相对于视口的位置,然后判断这些位置信息是否在视口的范围内。
JavaScript中的浮点数精度问题是什么?如何解决?
- 问题:由于JavaScript采用IEEE 754双精度浮点数表示数字,因此在进行浮点数运算时可能会遇到精度问题。
- 解决:可以使用一些库(如decimal.js、bignumber.js等)来进行高精度的数值计算。
JavaScript是如何实现单线程的?它的异步机制是怎样的?
- 实现:JavaScript本身是单线程的,这意味着它一次只能执行一个任务。为了实现异步操作,JavaScript使用了事件循环和任务队列的机制。
- 异步机制:当执行到异步操作时(如网络请求、定时器),JavaScript会将这个操作交给Web APIs去处理,并继续执行后续的代码。当异步操作完成时,会将一个回调函数放入任务队列中。事件循环会不断地检查任务队列,如果有任务,就将其取出并执行。