目录
7. 解释一下异步 JavaScript,什么是 Promises?
1. JavaScript 中的提升
提升是 JavaScript 中的默认行为,在编译阶段,变量和函数的声明会被移至各自作用域的顶部。这确保了无论变量和函数在作用域内声明的位置如何,它们都可以在整个作用域内访问。
console.log (message); //输出:undefined(变量被提升,但未赋值)
var message = "你好!" ;
function sayHi ( )
{
console.log( " 你好!" );
}
sayHi (); // 有效,因为函数声明被提升
2. this关键词
在JavaScript 中,this关键字是指代码正在执行的当前上下文或范围。其值由函数的调用方式决定,并且可以根据调用上下文动态更改。
this关键字根据其使用方式引用不同的对象:
- 当在对象的方法中使用时,this指向该对象。
- 单独使用时,this指向全局对象。
- 在函数内,this通常指向全局对象。
- 在严格模式下的函数中,this变为未定义。
- 在事件发生期间,this指向触发该事件的元素。
- call()、apply()和等方法bind()可以重新分配this给任何所需的对象。
const person = {
name : ' 张三' ,
greet : function ( ) { console.log ( ` 你好, ${ this.name } ` ); }
};
person.greet ( );
//输出 :你好,张三
3. JavaScript 中创建对象
JavaScript 是一种语法灵活的面向对象语言。JavaScript 中有4 种不同的方法来实例化对象。
- 使用构造函数创建对象
- 使用对象字面量
- Object.create()使用方法创建对象
- 使用 es6 类
(1)使用构造函数创建对象
实例化对象的最简单方法之一是使用 JavaScript。构造函数只不过是一个函数,借助 new 关键字,构造函数可以创建多个相同类型的对象,如下所示:
function Person(name, age) {
this.name= name;
this.age = age;
this.greet = function() {
return `你好, 我是 ${this.name} ,我今年 ${this.age}岁.`;
};
}
var person1 = new Person("张三", 25);
//你好,我是张三,我今年25岁
(2)使用对象字面量
字面量是定义对象的更小更简单的方法。我们只需在花括号内定义属性和值,{}如下所示。
var person = {
fullName: "张三",
age: 25
};
console.log(person.fullName) // 张三
console.log(person['fullName']) // 张三
(3)用Object.create()方法创建对象
Object.create() 方法创建一个新对象,并使用现有对象作为新创建对象的原型。
// 步骤 1:定义原型对象
const animalPrototype = {
speak: function() {
return `${this.name} 发出声音.`;
}
};
// 步骤 2:使用 Object.create() 创建新对象
const dog = Object.create(animalPrototype, {
name: {
value: '小黑',
writable: true,
enumerable: true,
configurable: true
},
breed: {
value: '金毛',
writable: true,
enumerable: true,
configurable: true
}
});
const cat = Object.create(animalPrototype, {
name: {
value: '咪咪',
writable: true,
enumerable: true,
configurable: true
},
breed: {
value: '橘花猫',
writable: false,
enumerable: true,
configurable: true
}
});
// 步骤 3:访问继承和自己的属性
console.log(dog.speak()); // 输出: 小黑发出声音.
console.log(dog.name); // 输出: 小黑
console.log(dog.breed); // 输出: 金毛
console.log(cat.speak()); // 输出: 咪咪发出声音.
console.log(cat.name); // 输出: 咪咪
console.log(cat.breed); // 输出: 橘花猫
// 修改属性的附加示例
dog.name = '大花';
console.log(dog.name);
// 输出: 大花(名称已更改,因为它是可写的)
// 尝试改变猫的品种
cat.breed = '波斯猫';
console.log(cat.breed);
// 输出: 橘花猫 (品种未改变,因为它不可写)
(4)使用 es6 类
与旧版基于原型的方法相比,在 JavaScript 中使用 ES6 类提供了一种更结构化、语法更佳的方式来处理对象创建和继承。ES6 类通过引入更简单的创建对象和处理继承的语法,简化了基于原型的面向对象编程模型。
class Employee extends Person {
constructor(name, age, jobTitle) {
super(name, age); // 调用父类构造函数
this.jobTitle = jobTitle;
}
describe() {
return `${super.greet()} 我的职业是 ${this.jobTitle}.`;
}
}
const employee1 = new Employee("张三", 28, "软件开发工程师");
console.log(employee1.greet());
// 输出:你好, 我是张三,我今年28岁.
console.log(employee1.describe());
// 输出: 你好, 我是张三,我今年28岁.
// 我的职业是软件开发工程师.
4. JavaScript 中的原型
JavaScript 是一种基于原型的语言,因此,每当我们使用 JavaScript 创建一个函数时,JavaScript 引擎都会在函数内部添加一个原型属性,原型属性基本上是一个对象(也称为原型对象),我们可以在原型对象中附加方法和属性,这使得所有其他对象都可以继承这些方法和属性。
function Car ( make, model, year ) {
this.make = make;
this.model = model;
this.year = year;
}
// 向原型添加方法
Car.prototype.drive = function() {
console.log( "驾驶
" + this.make +
" " + this.model
) ; } ; const myCar = new Car ( "本田" , "思域" , 2022 ) ;
console.log ( Object.getPrototypeOf ( myCar ) ) ;
//输出:Car { drive : function ( ) ... } (原型对象)
myCar.drive ( ) ; //输出:“驾驶本田思域”(继承方法)
5. JavaScript 中的typeof运算符是什么?
typeof是一个 JavaScript 关键字,调用它时将返回变量的类型。您可以使用它来验证函数参数或检查变量是否已定义。还有其他用途。
该typeof运算符很有用,因为它是一种检查代码中变量类型的简单方法。这很重要,因为 JavaScript 是一种动态类型语言。这意味着您在创建变量时无需为其分配类型。由于变量不受这种方式的限制,因此其类型可以在程序运行时发生变化。
const num = 42;
const message = "Hello, world!";
let uninitializedVar;
const myArray = [1, 2, 3];
const myFunction = function() {};
console.log(typeof num); // 输出: "number"
console.log(typeof message); // 输出: "string"
console.log(typeof uninitializedVar); // 输出: "undefined"
console.log(typeof myArray); // 输出: "object"
console.log(typeof myFunction); // 输出: "function"
console.log(typeof null); // 输出: "object" (**特殊情况** )
6.什么是箭头函数?
箭头函数const a = () => {} 是一种简洁的 JavaScript 函数编写方式。箭头函数是在 ES6 版本中引入的。它们使我们的代码更加结构化和可读性。
箭头函数是匿名函数,即没有名称的函数,但它们通常被分配给任何变量。它们也称为Lambda 函数。
const sayHello = ( ) => { console.log
( " Hello !" );
};
sayHello (); // 输出: Hello!
7.解释一下异步 JavaScript,什么是 Promises?
异步 JavaScript: JavaScript 是一种单线程语言,这意味着它一次只能执行一项任务。但是,现代 Web 应用程序通常依赖于需要时间才能完成的操作,例如从服务器获取数据或从文件读取数据。这就是异步编程的用武之地。
异步编程允许 JavaScript 执行这些耗时的操作而不会阻塞主线程。这意味着您的应用程序可以继续响应用户输入并在等待结果时保持交互。
Promises: Promises 是表示异步操作最终完成(或失败)的对象。与传统回调相比,它们提供了一种以更结构化、更易读的方式处理这些操作结果的方法。
function fetchData(url) {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('网络响应不正常 ' + response.statusText);
}
return response.json();
});
}
const apiUrl = 'https://api.example.com/data';
fetchData(apiUrl)
.then(data => {
console.log("数据获取成功:", data);
})
.catch(error => {
console.error("获取数据时出错:", error);
});
8. JavaScript 中的事件循环
在 JavaScript 中,事件循环是一种实现代码异步执行的基本机制。它是 JavaScript 运行时环境的重要组成部分,允许语言有效地处理非阻塞操作。事件循环负责管理代码的执行、处理事件和维护控制流。
事件循环如何工作?
- 调用堆栈:JavaScript 使用调用堆栈来跟踪当前正在执行的函数(程序执行的位置)。
- 回调队列:异步操作,比如 I/O 操作或者定时器,由浏览器或者 Node.js 运行时处理。当这些操作完成后,相应的函数(回调)会被放入回调队列中。
- 事件循环:事件循环不断检查调用堆栈和回调队列。如果调用堆栈为空,它会从回调队列中取出第一个函数并将其推送到调用堆栈上执行。
- 执行:执行调用堆栈顶部的函数。如果此函数包含异步代码,则可能会启动进一步的异步操作。
- 回调执行:当异步操作完成时,其回调会被放入回调队列中。
- 重复:事件循环继续此过程,确保在从回调队列中获取下一个函数之前,调用堆栈始终为空。
执行顺序:
- 首先执行所有同步代码。这些代码被放入调用堆栈并立即执行。
- 检查微任务队列并在那里执行任务,直到它为空。
- 仅当调用堆栈为空且所有微任务处理完毕后,才处理任务队列中的任务
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
}).then(() => {
console.log('Promise 2');
});
console.log('End');
/*输出:开始结束Promise 1 Promise 2 Timeout 1 * /
9.扩展运算符
扩展运算符是(...) ES6 引入的 JavaScript 功能,可让您访问可迭代对象的内部。“可迭代对象”是可以逐项迭代的任何对象,例如数组、对象文字和字符串。这些类型的 JavaScript 类型可以按某种顺序遍历。例如,您可以for在数组上使用循环,或者对于 JavaScript 对象,您可以使用for...in循环。
const numbers = [4, 5, 1, 8];
const max = Math.max(...numbers);
console.log(max); // 输出: 8
10.如何处理JavaScript代码中的错误?
JavaScript 中的错误处理是检测和处理程序执行期间发生的错误的过程。错误可以是语法、运行时或逻辑错误。程序执行期间发生的错误称为运行时错误或异常。
在 JavaScript 中,错误可能由于编程错误、用户输入错误等原因而发生。错误可能会破坏代码执行并导致糟糕的用户体验。有效的错误和异常处理对于构建健壮、可靠且用户友好的 JavaScript 应用程序至关重要。
JavaScript 提供了多种机制来捕获和管理程序执行期间可能发生的错误。这些机制包括使用 try-catch 块、抛出自定义错误以及处理被拒绝的 Promise。
1. 使用 Try-Catch 处理同步代码
该try-catch
语句是处理同步 JavaScript 代码中的错误的基本方法。它允许您定义一个代码块来尝试并指定在抛出异常时应采取的响应。
try {
// 可能抛出异常的代码
const result = someFunctionThatMightThrow();
console.log(result);
} catch (error) {
// 处理异常的代码
console.error('遇到错误:', error);
}
2. 抛出自定义事件。
您可以使用语句抛出自定义错误throw
。当您想要创建自定义错误处理逻辑或根据特定条件抛出特定类型的错误时,这很有用。
function checkAge(age) {
if (age < 18) {
throw new Error('访问被拒绝!');
} else {
console.log('允许访问');
}
}
try {
checkAge(15);
} catch (error) {
console.error(error.message);
}
3. Finally
该finally
块在 try 和 catch 块完成并处理完所有错误后执行。无论是否引发错误,它都会运行,这使其可用于清理资源或其他最终操作。
try {
//可能抛出的代码
} catch (error) {
//处理错误
} finally {
// 无论 try / catch 结果如何都会运行的代码console.log
console.log('这总是会执行');
}
4. 使用 Promises 进行错误处理
Promises 是异步 JavaScript 的重要组成部分。它们使用方法内置错误处理.catch()
,可以捕获在 Promise 执行期间发生的任何错误。
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('无法获取数据:', error));
5. Async/Await 错误处理
使用 async/await 时,可以使用 try-catch 块处理错误,类似于同步代码。这使得异步代码中的错误处理更加直接和易读。
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Failed to fetch data:', error);
}
}
fetchData();