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 中关于比较判断的经典例题:
例题 1:
let num1 = 5;
let num2 = '5';
console.log(num1 == num2); //true
console.log(num1 === num2); //false
此题主要考察 == 和 === 在面对不同数据类型时的比较结果。
例题 2:
let obj1 = {
name: 'John' };
let obj2 = {
name: 'John' };
console.log(obj1 == obj2); //false
console.log(obj1 === obj2); //false
此例考查对象的比较,由于对象是引用类型,即使属性相同,两个不同的对象引用也不会相等。
例题 3:
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
console.log(arr1 == arr2); //false
console.log(arr1 === arr2); //false
此例针对数组的比较,与对象类似,即使元素相同,不同的数组引用也不相等。
例题 4:
let num = null;
console.log(num == undefined); //true
console.log(num === undefined); //false
此例涉及 null 和 undefined 的比较。
例题 5:
let 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
中,推荐使用let
或const
来定义变量,它们具有块级作用域,可以避免这些问题。
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
变量只能通过increment
和decrement
方法访问,外部无法直接修改count
,实现了数据的封装和隐藏。
- 模拟私有方法:在面向对象编程中,可以使用闭包来模拟私有方法。例如:
const myObject = (function () { let privateVariable = "private value"; function privateMethod() { console.log(privateVariable); } return { publicMethod() { privateMethod(); }, }; })(); myObject.publicMethod(); // 输出:private value
privateVariable
和privateMethod
只能在创建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.设置事件时,最后参数true
和false
,冒泡和捕获的触发顺序是怎样的?
在设置事件处理程序时, true
表示使用捕获阶段, false
(默认值)表示使用冒泡阶段。
事件传播的顺序如下:
1)捕获阶段:
从最外层的祖先元素开始,向目标元素(触发事件的元素)传播。
2)目标阶段:
到达实际触发事件的目标元素。
3)冒泡阶段:
从目标元素开始,向其祖先元素传播。
如果将最后一个参数设置为
true
(捕获阶段),事件会先从最外层的祖先元素触发,然后依次向内传播,直到到达目标元素。
如果将最后一个参数设置为
false
(冒泡阶段),事件会先在目标元素触发,然后依次向其祖先元素传播。
9.逻辑或 和 逻辑与
- “逻辑或”
||
:- 当两个操作数中至少有一个为真(即非零、非空、非
false
等)时,整个表达式为真。 - 只有当两个操作数都为假时,表达式才为假。
- 当两个操作数中至少有一个为真(即非零、非空、非
例如:
true || false
的结果为true
,false || false
的结果为false
。
- “逻辑与”
&&
:- 只有当两个操作数都为真时,整个表达式才为真。
- 如果其中至少有一个为假,表达式就为假。
例如:
true && true
的结果为true
,true && false
的结果为false
。
10.在 JavaScript 中,可以使用哪几种方法来判断数据类型是否相等?
1)typeof
操作符:可以返回一个表示数据类型的字符串。
但对于某些类型(如 null
和 object
类型的数组、对象)的判断不够精确。
2)instanceof
操作符:用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
但对于基本数据类型(如 Number
、 String
、 Boolean
等)不适用。
3)Object.prototype.toString.call()
方法:这是一种比较准确和全面的判断数据类型的方法。
它会返回一个形如 [object Type]
的字符串,其中 Type
表示具体的数据类型。
例如:
console.log(Object.prototype.toString.call(5)); // "[object Number]"
console.log(Object.prototype.toString.call('hello'))