code
+ 解释 quote + 补充 quoteXMLHttpRequest
是浏览器原生提供的 API,它允许我们在不刷新页面的情况下向服务器发送请求和获取数据。
ajax
:ajax
是一种基于原生 JavaScript 的异步请求技术。它使用 XMLHttpRequest
对象来发送请求和接收响应。
axios
:axios
是一个基于 Promise 的 HTTP 客户端,可以在浏览器和 Node.js 中使用。它提供了更高级别的封装,使发送请求和处理响应更加简单和灵活。
fetch
:fetch
是浏览器内置的 API,用于发送网络请求。它提供了一种现代化、基于 Promise 的方式来进行网络通信。用法和axios
类似,但相比于 axios
,它的功能和封装级别更为简单。
// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 创建请求
xhr.open('GET', 'https://api.example.com/data', true);
// 发送请求
xhr.send();
// 处理响应
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
// 处理返回的数据
var data = JSON.parse(xhr.responseText);
// 更新页面内容
document.getElementById('result').innerHTML = data.message;
} else {
console.log('Error: ' + xhr.status);
}
}
};
DOM 事件委托是一种常见的前端开发技术,其原理是利用事件冒泡机制,将事件处理程序添加到父元素上,通过判断事件目标来执行对应的操作。事件委托的优缺点如下:
优点:
缺点:
总的来说,事件委托是一种常用且有效的优化技术,特别适用于大量相似子元素的情况,能够提升性能并简化代码逻辑。然而,在使用事件委托时需要注意正确识别事件目标,避免误操作,并根据具体情况权衡使用。
JavaScript 事件流模型描述了在页面中接收和处理事件的方式。事件流模型包括三个阶段:捕获阶段、目标阶段和冒泡阶段。当事件发生时,它会沿着这三个阶段在 DOM 树上进行传播。
捕获阶段(Capturing Phase): 事件从最外层的元素开始向目标元素进行传播。在这个阶段,事件从 Document 对象一直向下传播到目标元素。
目标阶段(Target Phase): 事件达到目标元素本身,触发在目标元素上绑定的事件处理程序。
冒泡阶段(Bubbling Phase): 事件从目标元素开始向上冒泡,传播回最外层的元素。在这个阶段,如果目标元素上的事件处理程序未阻止事件冒泡,事件将继续向上传播。
在事件流模型中,事件首先经历捕获阶段,然后到达目标元素,最后冒泡回最外层元素。JavaScript 中的事件处理程序可以在捕获阶段、目标阶段或冒泡阶段进行绑定,以响应特定阶段的事件。
在 DOM 标准中规定了事件流模型,但是并非所有事件都会经历完整的捕获、目标、冒泡三个阶段,有些事件可能只涉及其中的某一个阶段。通常情况下,大多数事件会在目标阶段触发事件处理程序,然后根据情况冒泡或者不冒泡。
了解 JavaScript 事件流模型有助于开发者理解事件处理的机制,合理地管理事件处理程序的绑定和触发顺序,提高页面交互的效果和性能。
split() 方法用于将一个字符串拆分成字符串数组,根据指定的分隔符将字符串分割成多个子串,并返回这些子串组成的数组。例如:
const str = 'Hello, World!';
const arr = str.split(', '); // 将字符串以逗号和空格为分隔符拆分成数组
console.log(arr); // 输出: ['Hello', 'World!']
而 join() 方法则是将数组中的所有元素连接成一个字符串,并返回连接后的字符串。它使用指定的分隔符将数组元素拼接在一起。例如:
const arr = ['Hello', 'World!'];
const str = arr.join(', '); // 将数组元素用逗号和空格连接成字符串
console.log(str); // 输出: 'Hello, World!'
当截取字符串时,substr()
方法使用起始索引和长度作为参数,substring()
和 slice()
方法使用起始索引和结束索引作为参数。
substr(startIndex, length)
: 使用起始位置和长度来截取字符串。substring(startIndex, endIndex)
: 使用起始位置和结束位置(不包括)来截取字符串。slice(startIndex, endIndex)
: 也使用起始位置和结束位置(不包括)来截取字符串。主要区别:
substr()
的第二个参数是截取的长度,而 substring()
和 slice()
的第二个参数是截取结束的位置。substring()
不接受负数作为参数,会将负数参数自动转换为 0,而 slice()
和 substr()
可以接受负数作为参数。event.stopPropagation()
:阻止事件向上冒泡
event.preventDefault()
:阻止事件的默认行为
Object.prototype.toString.call()
(推荐使用)let myVariable = "Hello, world!";
if (Object.prototype.toString.call(myVariable) === '[object String]') {
console.log('myVariable 是一个字符串');
} else {
console.log('myVariable 不是一个字符串');
}
typeof
let myVariable = "Hello, world!";
if (typeof myVariable === 'string') {
console.log('myVariable 是一个字符串');
} else {
console.log('myVariable 不是一个字符串');
}
instanceof
let myString = "Hello, world!";
if (myString instanceof String) {
console.log('myString 是一个字符串对象');
} else {
console.log('myString 不是一个字符串对象');
}
constructor
(不建议使用)原型链继承:当对象通过原型链继承属性和方法时,它可能没有自己的 constructor 属性,而是从原型链上继承过来的。这种情况下,直接访问对象的 constructor 属性可能会导致不准确的结果。
属性被重写:如果对象的 constructor 属性被手动更改或重写,那么它指向的构造函数可能与实际创建对象的构造函数不同。
使用 Object.create() 创建对象:通过 Object.create() 方法创建的对象可能会没有 constructor 属性,因为它是通过指定原型对象来创建的。
对象序列化和反序列化:在将对象序列化为 JSON 字符串后再反序列化成对象时,新创建的对象可能会丢失原始对象的 constructor 属性。
A. null instanceof Object
B. null === undefined
C. null == undefined
D. NaN == NaN
解释:
因此,选择 C. null == undefined 是结果为真的表达式。
通过isNaN()判断
答案摘自大佬博客
JavaScript 中的变量提升和块级作用域是两个重要的概念,它们在理解 JavaScript 中变量和作用域时非常关键。
变量提升(Hoisting):
function example() {
console.log(a); // 输出:undefined
var a = 10;
}
块级作用域:
function example() {
if (true) {
let a = 10; // 在 if 代码块内声明的变量 a 只在此代码块内有效
console.log(a); // 输出:10
}
console.log(a); // 报错:a is not defined
}
foo
的值为真值(truthy),则表达式的结果为 foo
。foo
的值为假值(falsy),则表达式的结果为 bar
。原因:
foo
已经有一个真值,那么它的值将不会被改变;如果 foo
是一个假值,那么它将被赋值为 bar
。foo = foo || bar
可以确保 foo
至少有一个默认值,避免了这种错误。需要注意的是,在使用 foo = foo || bar
时,要确保 bar
的值是我们希望作为默认值的值,并且在该行代码之前已经定义了 bar
变量。
function greet(name) {
name = name || 'Guest'; // 如果name为假值,则将其赋值为'Guest'
console.log('Welcome, ' + name + '!');
}
greet('Alice'); // 输出:Welcome, Alice!
greet(); // 输出:Welcome, Guest!
target
表示事件最初发生的元素,而 currentTarget
表示事件当前正在被处理的元素。
DOCTYPE html>
<html>
<head>
<title>1title>
<style>
style>
head>
<body>
<div id="container">
<button id="button">Click me!button>
div>
<script>
document.getElementById('container').addEventListener('click', function(event) {
console.log('target:', event.target); // 输出
console.log('currentTarget:', event.currentTarget); // 输出...
});
script>
body>
html>
target
属性:
target
属性表示事件最初被触发的那个元素,即事件的实际目标。- 对于事件冒泡(bubbling)来说,
target
会随着事件的冒泡过程而改变,指向最开始触发事件的那个元素。- 例如,当用户点击了一个按钮,
target
就会指向这个按钮元素。
currentTarget
属性:
currentTarget
属性表示事件当前正在被处理的那个元素,即事件的当前目标。- 对于事件冒泡(bubbling)来说,
currentTarget
始终指向添加了事件监听器的那个元素。- 例如,当用户点击了一个按钮,假设按钮内部嵌套了一个
div
元素,并且你在div
上添加了点击事件监听器,那么在点击div
元素时,currentTarget
将指向div
元素,而target
则会指向最初触发事件的按钮元素。
这题答案用黑马程序员的一张图解释比打字解释的更清楚
每个对象都有一个原型对象,原型对象又有自己的原型,形成了一条原型链。
new
操作符是在 JavaScript 中用于创建对象的关键字。当使用 new
操作符来创建一个对象时,它会经历以下几个步骤:
创建一个空对象:new
操作符创建一个新的空对象,作为要实例化的对象。
设置原型链:新对象的 __proto__
属性会被设置为构造函数的 prototype
属性,从而建立起原型链。这样新对象就可以访问到构造函数原型(prototype)上的属性和方法。
绑定 this 指向:将构造函数中的 this
关键字绑定到新创建的对象上,使构造函数中的代码能够操作该对象。
返回新对象:如果构造函数没有显式返回其他对象,则 new
操作符返回新创建的对象。如果构造函数返回一个非对象类型的值(如字符串、数字等),则返回新创建的对象。
IIFE 指的是立即调用的函数表达式(Immediately Invoked Function Expression)。它是一种 JavaScript 中常用的函数定义和立即执行的模式。
IIFE 的基本语法如下:
(function() {
// 在这里编写需要立即执行的代码
})();
在这个例子中,函数被包裹在括号中,然后紧接着另外一个括号 ()
调用了该函数。这样定义的函数会立即执行,并且不会污染全局作用域。
IIFE 主要有以下几个特点和用途:
不污染全局作用域: 通过将代码放在 IIFE 中,可以避免变量和函数的命名冲突,因为其中定义的变量和函数只在 IIFE 内部可见。
数据封装: 可以将一些私有变量和函数封装在 IIFE 中,从而实现模块化的代码结构。
立即执行: 由于 IIFE 是立即执行的,它可以用于执行一些初始化操作或者在运行时立即执行一段代码。
浅拷贝是指将一个对象的属性值复制到另一个对象中,
如果属性值是基本类型(数字、字符串、布尔值等),则直接复制该属性值;
如果属性值是引用类型(数组、对象、函数等),则复制该引用类型的引用。
这意味着原始对象和拷贝对象会共享引用类型的属性,因此修改其中一个对象的属性值也会影响另一个对象。
可以使用以下方法来实现浅拷贝:
Object.assign(target, ...sources)
方法可以将一个或多个源对象的属性复制到目标对象中,并返回目标对象。该方法会忽略源对象中值为 null
或 undefined
的属性,但不会拷贝对象原型链上的属性。
var source = { name: "Alice", age: 25 };
var target = {};
Object.assign(target, source);
console.log(target); // 输出 { name: "Alice", age: 25 }
ES6 的扩展运算符可以将一个对象展开成多个参数,从而可以用于浅拷贝。
var source = { name: "Alice", age: 25 };
var target = { ...source };
console.log(target); // 输出 { name: "Alice", age: 25 }
略
深拷贝是指将一个对象及其所有嵌套的引用类型属性都复制到另一个对象中,这样原始对象和拷贝对象就不会共享任何属性了。这意味着修改其中一个对象的属性值不会影响另一个对象。
可以使用以下方法来实现深拷贝:
可以使用 JSON.parse(JSON.stringify(obj))
来实现简单的深拷贝,但该方法有一些限制:
var source = { name: "Alice", age: 25, hobbies: ["reading", "swimming"] };
var target = JSON.parse(JSON.stringify(source));
console.log(target); // 输出 { name: "Alice", age: 25, hobbies: ["reading", "swimming"] }
target.hobbies.push("running");
console.log(source.hobbies); // 输出 ["reading", "swimming"]
console.log(target.hobbies); // 输出 ["reading", "swimming", "running"]
略
例子:
// 调整函数 sum
function sum(num1, num2) {
return num1 + num2
}
// 改写为 可以实现如下效果
console.log(sum(1)(2))//
核心步骤:
sum
改为接收一个参数,返回一个新函数function sum(num1) {
return function (num2) {
return num1 + num2
}
}
for in
和for of
的区别?for...in
语句以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。
for...of
语句在可迭代对象(包括 Array
,Map
,Set
,String
,TypedArray
,arguments 对象等等)上创建一个迭代循环
Object.prototype.objFunc = function () { }
Array.prototype.arrFunc = 'arrFunc'
const foods = ['西瓜', '西葫芦', '西兰花']
for (const key in foods) {
console.log('for-in:key', key) // 0 1 2
}
for (const iterator of foods) {
console.log('for-of:iterator', iterator) // xx xxx xxx
}
全局执行环境中,指向全局对象(非严格模式、严格模式)
如何开启严格模式:
// 为整个脚本开启严格模式
'use strict'
function func() {
// 为函数开启严格模式
'use strict'
}
函数内部,取决于函数被调用的方式
直接调用的this值:
对象方法调用时的this值为调用者