【JavaScript + ES6】前端八股文面试题

JavaScript 、 ES6 部分

整理不易,家人们不想开通 VIP ,可以私我,有偿(2 yuan 购入PDF版)有更新都会踢。
【狗头保命,小的认真总结的,大部分都是我面试遇到的,感谢理解】

更新日志

2024年8月29日更新 —— ES6新特性有哪些?
2024年8月30日更新——xmlhttpRequest的解释
2024年8月31日更新——

  • 防抖和节流的应用场景?
  • 在开发过程中,原型链的应用场景?
  • 箭头函数的作用
  • 在JS中,怎么样实现面向对象的编程

1. =====的区别

JavaScript 中, ===== 都是用于比较操作的运算符。

但它们在比较规则上有明显的区别:

  • == (相等运算符):在进行比较时会进行类型转换,然后比较值是否相等。

例如: ‘5’ == 5 会返回 true ,因为会将字符串 ‘5’ 转换为数字 5 进行比较。

  • === (严格相等运算符):不仅比较值,还比较类型。只有值和类型都相同时,才返回 true 。

例如: ‘5’ === 5 会返回 false ,因为类型不同,一个是字符串,一个是数字。

[]===[] //false
{
   }==={
   } //false
null ===null  // true
{
   }=={
   } // false
以下是一些 JavaScript 中关于比较判断的经典例题:
 
例题 1let num1 = 5;
let num2 = '5';

console.log(num1 == num2);  //true
console.log(num1 === num2);  //false
 
此题主要考察  =====  在面对不同数据类型时的比较结果。
 
例题 2let obj1 = {
    name: 'John' };
let obj2 = {
    name: 'John' };

console.log(obj1 == obj2);  //false
console.log(obj1 === obj2);  //false
 
此例考查对象的比较,由于对象是引用类型,即使属性相同,两个不同的对象引用也不会相等。
 
例题 3let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];

console.log(arr1 == arr2); //false
console.log(arr1 === arr2); //false

此例针对数组的比较,与对象类似,即使元素相同,不同的数组引用也不相等。
 
例题 4let num = null;
console.log(num == undefined);  //true
console.log(num === undefined);  //false
 
此例涉及  nullundefined  的比较。
 
例题 5let str1 = 'hello';
let str2 = new String('hello');

console.log(str1 == str2);  //true
console.log(str1 === str2);  //false
 
此例考察字符串直接量和通过  String  构造函数创建的字符串对象的比较。

2. for 循环 var 定义和多个变量执行的次数

  • for 循环中使用 var 定义变量时,会存在变量提升的问题,即变量会在函数作用域的顶部声明。
  • 多个变量的执行次数取决于循环的条件。
例如,以下代码中:
for (var i = 0; i < 10; i++) {
   
  for (var j = 0; j < 6; j++) {
   
    // 循环体中的代码
  }
}

外层循环会执行 10 次,内层循环会在外层循环的每一次迭代中执行 6 次。因此,总的执行次数为 10 * 6 = 60 次。

【注意】由于 var 定义的变量在整个函数作用域内都是可见的,可能会导致一些意外的结果。
ES6 中,推荐使用 letconst 来定义变量,它们具有块级作用域,可以避免这些问题。

3.什么是闭包?

JavaScript 中,闭包(Closure)是指有权访问另一个函数作用域中的变量的函数。

1)形成闭包的条件
  • 存在一个内层函数。
  • 内层函数引用了外层函数的变量。
  • 外层函数将内层函数作为返回值或者传递给其他地方进行调用。
2)示例解释

以下是一个简单的闭包示例:

function outerFunction() {
   
  const outerVariable = "I am from outer function";
  function innerFunction() {
   
    console.log(outerVariable);
  }
  return innerFunction;
}

const closureFunction = outerFunction();
closureFunction(); // 输出:I am from outer function

在这个例子中:

  • outerFunction是外层函数,它定义了一个变量outerVariable
  • innerFunction是内层函数,它引用了outerVariable
  • outerFunction返回了innerFunction,当把这个返回值赋给closureFunction并调用closureFunction时,innerFunction仍然能够访问到outerVariable,这就形成了闭包。
3)闭包的作用
  • 数据封装和隐藏:可以创建私有变量,避免全局命名空间的污染。例如:
   function createCounter() {
   
     let count = 0;
     return {
   
       increment() {
   
         count++;
         return count;
       },
       decrement() {
   
         count--;
         return count;
       },
     };
   }

   const counter = createCounter();
   console.log(counter.increment()); // 1
   console.log(counter.increment()); // 2

在这个例子中,count变量只能通过incrementdecrement方法访问,外部无法直接修改count,实现了数据的封装和隐藏。

  • 模拟私有方法:在面向对象编程中,可以使用闭包来模拟私有方法。例如:
    const myObject = (function () {
         
      let privateVariable = "private value";
      function privateMethod() {
         
        console.log(privateVariable);
      }
      return {
         
        publicMethod() {
         
          privateMethod();
        },
      };
    })();
    
    myObject.publicMethod(); // 输出:private value
    

privateVariableprivateMethod只能在创建myObject的立即执行函数内部访问,外部无法直接访问,模拟了私有变量和私有方法。

  • 函数记忆化:闭包可以用于缓存函数的结果,避免重复计算。例如:
    function memoizedAddTo80() {
         
      let cache = {
         };
      return function (n) {
         
        if (n in cache) {
         
          return cache[n];
        } else {
         
          console.log("long time");
          cache[n] = n + 80;
          return cache[n];
        }
      };
    }
    
    const memoized = memoizedAddTo80();
    console.log(memoized(5)); // long time,输出:85
    console.log(memoized(5)); // 输出:85(直接从缓存中获取结果)
    

在这个例子中,闭包保存了cache对象,用于存储已经计算过的结果,下次调用相同的参数时可以直接从缓存中获取结果,提高了函数的性能。

4)注意事项
  • 闭包可能会导致内存泄漏:如果闭包引用了一个不再需要的变量,而这个变量又没有被正确地释放,就可能会导致内存泄漏。因此,在使用闭包时,要确保不再需要的变量能够被正确地垃圾回收。
  • 闭包可能会影响性能:由于闭包会保留对外部变量的引用,这可能会导致一些性能问题,特别是在处理大量闭包或复杂的闭包结构时。因此,在使用闭包时,要注意性能优化,避免不必要的闭包使用。

以下是一个示例代码,用于给大家判断哪一个是闭包:

function outer() {
   
  var outerVar = '外层变量';
  function inner() {
   
    console.log(outerVar);
  }
  return inner;
}

var closure = outer();
closure(); 

在上述代码中, inner 函数能够访问外部函数 outer 中的 outerVar 变量,因此 inner 函数是一个闭包。

4.async返回的是什么类型?

JavaScript 中, async 函数总是返回一个 Promise 对象。

  • 如果 async 函数内部的执行逻辑通过 return 语句返回了一个值,那么这个 Promise 对象最终会被解析为这个返回的值;
  • 如果函数内部抛出了异常或者发生了错误,那么这个 Promise 对象最终会被拒绝,并携带抛出的错误信息。
例如:
async function myAsyncFunction() {
   
  return 5; 
}

myAsyncFunction().then(result => console.log(result)); 
// 输出 5

在这个例子中, myAsyncFunction 函数返回的 Promise 对象最终被解析为数字 5 。

5.箭头函数能不能return

箭头函数可以返回一个值。

  • 如果函数体只有一条表达式,可以省略 {} return 关键字,表达式的值会被自动返回。
  • 如果函数体包含多条语句或需要显式返回一个值,则需要使用 {} 括起来,并使用 return 关键字。
例如:
const sum = (a, b) => a + b;  // 自动返回表达式的值

const multiply = (a, b) => {
   
  return a * b;  // 显式使用 return 返回值
};

6. map() filter() reduce() 返回值分别是什么?

1)map() 方法:创建一个新数组,其结果是对原数组中的每个元素调用提供的函数后的返回值。
const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2); 
// doubled 的结果为 [2, 4, 6]
2)filter() 方法:创建一个新数组,其中包含通过提供的函数实现的测试的所有元素。
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(num => num % 2 === 0); 
// evenNumbers 的结果为 [2, 4]
3)reduce() 方法:对数组中的每个元素执行一个提供的 reducer 函数(升序执行),将其结果汇总为单个返回值。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0); 
// sum 的结果为 15

在这些方法中, reduce() 的返回结果通常与 map()filter() 有所不同,因为它最终返回的是一个汇总的值,而不是一个新的数组。

7.阻止事件默认行为的方式有哪些?

1)在事件处理函数中返回 false
<button onclick="handleClick(); return false;">点击我</button>
<script>
  function handleClick() {
     
    // 事件处理逻辑
  }
</script>
2)使用 preventDefault() 方法:
<button id="myButton">点击我</button>
<script>
  document.getElementById('myButton').addEventListener('click', function(event) {
     
    event.preventDefault();
    // 事件处理逻辑
  });
</script>
3)对于表单提交事件,如果使用 jQuery 库,可以这样阻止:
<form id="myForm">
  <!-- 表单元素 -->
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
  $('#myForm').submit(function(event) {
     
    event.preventDefault();
    // 表单处理逻辑
  });
</script>

8.设置事件时,最后参数truefalse,冒泡和捕获的触发顺序是怎样的?

在设置事件处理程序时, true 表示使用捕获阶段, false (默认值)表示使用冒泡阶段。

事件传播的顺序如下

1)捕获阶段:

从最外层的祖先元素开始,向目标元素(触发事件的元素)传播。

2)目标阶段:

到达实际触发事件的目标元素。

3)冒泡阶段:

从目标元素开始,向其祖先元素传播。

如果将最后一个参数设置为 true (捕获阶段),事件会先从最外层的祖先元素触发,然后依次向内传播,直到到达目标元素。

如果将最后一个参数设置为 false (冒泡阶段),事件会先在目标元素触发,然后依次向其祖先元素传播。

9.逻辑或 和 逻辑与

  • “逻辑或”||
    • 当两个操作数中至少有一个为真(即非零、非空、非 false 等)时,整个表达式为真。
    • 只有当两个操作数都为假时,表达式才为假。

例如: true || false 的结果为 truefalse || false 的结果为 false

  • “逻辑与”&&
    • 只有当两个操作数都为真时,整个表达式才为真。
    • 如果其中至少有一个为假,表达式就为假。

例如: true && true 的结果为 truetrue && false 的结果为 false

10.在 JavaScript 中,可以使用哪几种方法来判断数据类型是否相等?

1)typeof 操作符:可以返回一个表示数据类型的字符串。

但对于某些类型(如 nullobject 类型的数组、对象)的判断不够精确。

2)instanceof 操作符:用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

但对于基本数据类型(如 NumberStringBoolean 等)不适用。

3)Object.prototype.toString.call() 方法:这是一种比较准确和全面的判断数据类型的方法。

它会返回一个形如 [object Type] 的字符串,其中 Type 表示具体的数据类型。

例如:
console.log(Object.prototype.toString.call(5)); // "[object Number]"
console.log(Object.prototype.toString.call('hello'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟una

客官打赏小银子,我库库出文

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值