你的 JavaScript 水平如何?您是摇滚明星 JavaScript 开发人员还是新手?让我们通过这 50 个 JavaScript 面试问题来测试你的知识。每个问题都有一个答案,但我鼓励你们在查看答案之前尽力而为。
什么是JavaScript?
JavaScript 是一种动态类型、解释型脚本语言。它支持不同的范例,例如函数式、OOP 和过程式。它是唯一在浏览器上执行的语言,这就是为什么它也被称为网络语言的原因。
动态类型 - 意味着变量在其整个生命周期中可以包含多种类型
复制
复制
COPY
COPY
let someVarName = "JavaScript" // JavaScript
someVarName = 12 // 12
someVarName = {name: "JavaScript"} // {name: "JavaScript"}
someVarName = false // false
someVarName = [1,2,3] // [1,2,3]
解释 - 意味着 JavaScript 中的代码不是像 C、C++ 和 Java 等语言那样被编译然后执行,而是以从上到下的逐行方式执行
JavaScript 中的原始类型和引用类型有什么区别?
原始类型
原始类型只能包含一个值,而非原始类型可以有多个。
JavaScript 原始类型
复制
复制
COPY
COPY
""
false
1
null
undefined
123n
Symbol("symbol")
非原始类型或引用类型
非原始类型一次可以包含原始的多个值
复制
复制
COPY
COPY
const hobbies = ["Reading", "Calisthenics", "Swimming"]
const person = {
name: "Jaxongir",
age: 27,
country: "Uzbekistan"
hobbies
}
== 和 === 有什么区别?
\== - 比较运算符只比较值而不是它们的类型,如果比较不同类型的两个相同值,则会发生类型转换。这是一种类型转换为另一种类型。
复制
复制
COPY
COPY
console.log(1 == "1") // true
console.log(false == "0") // true
\=== * - 严格相等比较运算符首先比较值的数据类型。如果它们是同一类型,则比较值,否则它们不是同一类型,无论值是否相同都返回 false
复制
复制
COPY
COPY
console.log(1 === "1") // false
console.log(false === "0") // false
什么是高阶函数?
**HOF(高阶函数)- 是将另一个函数作为参数并在其主体内调用它或将函数作为值返回的函数
HOF 的示例有:map、filter、for each、reduce 等...
复制
复制
COPY
COPY
const nums = [1,2,3,4]
const multiplyNum = nums.map(num => num * 2)
console.log(multiplyNum) // [2,4,6,8]
const greet = (greeting)=> name => `${greeting} ${name}!`
const func = greet("Hello")
func("Jaxongir") // Hello Jaxongir!
func("Lola") // Hello Lola!
什么是纯函数?
纯函数- 是没有任何副作用的函数,它从不改变参数并返回与参数相同类型的副本。
复制
复制
COPY
COPY
// Impure function
const add = (num1, num2)=> {
num1 = 10
return num1 + num2
}
// Pure function
const add = (num1, num2)=> num1 + num2
函数柯里化是什么?
Currying - 是将具有多个参数的函数转换为具有单个参数的多个函数的函数式编程技术
复制
复制
COPY
COPY
const curry = (f) => (a) => (b) => f(a, b);
const product = (num1, num2) => num1 * num2;
const curriedProduct = curry(product);
console.log(curriedProduct(20)(5)) // 100
console.log(curriedProduct(1)(10)) // 10
console.log(curriedProduct(0)(100)) // 0
var、let 和 const 之间有什么区别?
让和常量
let 和 const 是 2015 年引入的 ES6 特性
用 let 或 const 声明的变量是作用域 {} 这意味着它们在定义它们的 {} 之外是不可见的
用它们贴标的变量没有被提升,这意味着我们不能在它们定义的变量之前访问
var 是 ES5 特性并且
如果变量在函数中使用 var 关键字声明,那么它在该函数内的范围内,这意味着它不能在它定义的函数体之外访问
在所有其他情况下,用 var 关键字声明的变量是全局范围的
复制
复制
COPY
COPY
if(10 > 0){
var test = "right"
let test2 = "test"
}
console.log(test) // right
console.log(test2) // ReferenceError: test2 is not defined
全局作用域和局部作用域有什么区别?
全局作用域* - 当变量和函数可以全局访问时。因此,当您在任何 {} 之外声明 let 和 const 变量时,它们是全局范围的。当用 var 外部函数声明的变量是全局作用域时
**局部作用域- 只要用 let 和 const 声明的长变量在 {} 内,它们就是局部作用域到该 {} 的主体并向内
复制
复制
COPY
COPY
// global scope variable
const name = "Jaxongir"
// global scoped function
const func = ()=>{
// local scoped variable
let age = 25
}
func()
console.log(name) // Jaxongir
console.log(age) // ReferenceError: age is not defined
什么是暂时死区?
临时死区- 是指无法访问使用 let 或 const 声明的变量。发生这种情况是因为它们没有被吊起。或者更简单的是,它们是不可见的或在时间死区中,从它们在 {} 范围内到为它们分配内存
复制
复制
COPY
COPY
const fuc = () => {
console.log(name);
console.log(age);
var age = 27;
let name = "Jaxongir";
};
fuc() // ReferenceError: Cannot access 'name' before initialization
什么是吊装?
提升- 是指用 var 声明的变量和函数声明在执行之前移动到当前作用域的顶部,因此在声明之前可以访问它们。
复制
复制
COPY
COPY
greeting("Jaxongir")
function greeting(name) {
console.log("Hello " + name) // Hello Jaxongir
console.log(age) // undefined
var age = 26;
}
什么是关闭?
闭包- 基本上是当函数始终访问它的周围范围时,即使在周围范围已经执行之后也是如此。每次创建函数时都会创建闭包。每次创建函数时,该函数都可以访问在其周围范围内定义的变量、函数和对象
复制
复制
COPY
COPY
let name = "Jaxongir";
const fun = () => {
console.log(name) // Jaxongir
};
fun()
const outerFunc = (message)=>{
let test = "string"
const innerFunc = (text)=>{
console.log(message, test, text)
}
}
const test = outerFunc("Hello")
test("JavaScript")
如何比较两个对象?
为了深入解释,看看这个优秀的堆栈溢出
复制
复制
COPY
COPY
const obj1 = {name: "Lola"}
const obj2 = {name: "Lola"}
JSON.stringify(obj1) === JSON.stringify(obj2) // true
在 JavaScript 中创建对象的所有可能方法有哪些?
复制
复制
COPY
COPY
// object literals
const person = {name: "Jaxongir}
// Object constructor
const person = new Object();
console.log(person);
// Object create method
const person = Object.create({});
console.log(person);
// singleton pattern
const person = new (function () {
this.name = "Jaxongir";
})();
// Constructor function
function Person(name) {
this.name = name;
}
const person = new Person("Jaxongir");
// ES6 Class
class Person {
constructor(name) {
this.name = name;
}
}
const person = new Person("Jaxongir");
console.log(person);
什么是原型链?
原型链- 当对象从它的原型对象继承它的属性和方法时
,每个其他类型在 JavaScript 中继承的根构造函数是 Object
复制
复制
COPY
COPY
const company = {
companyName: "UZS",
};
const teacher = {
fullname: "Jaxongir Rahimov",
__proto__: company,
};
console.log(teacher.companyName) // UZS
console.log(teacher.fullname) // Jaxongir Rahimov
调用、应用和绑定之间有什么区别?
虽然它们之间的使用方式有所不同,但它们之间的共同点是在函数体内为 this 关键字提供上下文并传入参数
注意:它们只能在函数声明中调用,不能在箭头函数中调用。因为箭头函数没有绑定 this 关键字
call - 使用提供的 this 值和附加参数调用函数。第一个参数总是 this 或 object 的上下文,它可以有 n 个参数
复制
复制
COPY
COPY
const person1 = {
name: "Jaxongir",
age: 27,
country: "Uzbekistan",
gender: "male",
hobbies: ["Reading", "Calisthenics", "Swimming"],
};
const person2 = {
name: "Lola",
age: 21,
country: "Russia",
gender: "female",
hobbies: ["Reading", "Knitting", "Swimming", "Badminton"],
};
function printBio(greeting) {
console.log(
`${greeting} ${this.gender === "male" ? "His name is" : "Her name is"} ${
this.name
} and is ${this.age} years old and is from ${
this.country
} and has following hobbies ${this.hobbies.join(", ")}`
);
}
printBio.call(person1, "Hello") // Hello His name is Jaxongir and is 27 years old and is from Uzbekistan
printBio.call(person2, "Hello") // Hello Her name is Lola and is 21 years old and is from Russia
apply - 调用提供此值上下文的函数并传递参数数组
复制
复制
COPY
COPY
function printBio(greeting) {
console.log(
`${greeting} ${this.gender === "male" ? "His name is" : "Her name is"} ${
this.name
} and is ${this.age} years old and is from ${this.country}`
);
}
printBio.apply(person1, ["Hello"]);
printBio.apply(person2, ["Hello"]);
bind - 返回可以存储变量的新函数,当调用该函数时,将其设置为提供的对象和传递的值
复制
复制
COPY
COPY
function printBio(greeting) {
console.log(
`${greeting} ${this.gender === "male" ? "His name is" : "Her name is"} ${
this.name
} and is ${this.age} years old and is from ${this.country}`
);
}
printBio.bind(person1)("Hello");
printBio.bind(person2)("Hello");
什么是 JSON 及其常用操作?
JSON代表用于在网络上发送数据的 JavaScript 对象表示法。甚至 Douglas Crockford,前 Atari 员工和创造并推广术语“JSON”的人,也表示他“发现”了 JSON 而不是“发明”
它主要有两个操作
解析- 从文本转换为原始数据
复制
复制
COPY
COPY
JSON.parse("{name: "Jaxongir"}") // {name: "Jaxongir"}
Stringification - 将有效数据转换为字符串格式
复制
复制
COPY
COPY
JSON.stringify({name: "Jaxongir"}) // "{name: "Jaxongir"}"
数组切片方法的目的是什么?
数组切片方法用于复制字符串和数组的一部分,这样我们就可以使用数组的副本而不是修改它。它用于防止突变。这是切片的链接
复制
复制
COPY
COPY
let fullname = "Jaxongir Rahimov"
console.log(fullname.slice(0, 10))
const people = ["Lola", "Jol", "Mat", Jaxongir"]
conosle.log(people.slice(0,2))
数组拼接法的目的是什么?
数组拼接方法用于删除给定索引中的指定项或在给定索引中添加单个或多个项。链接到拼接
复制
复制
COPY
COPY
const people = ["Lola", "Jaxongir", "Test", "Horum"];
// Deleting single item in the given index
console.log(people); // ["Lola", "Jaxongir", "Test", "Horum"]
people.splice(2, 1);
console.log(people); // ["Lola", "Jaxongir", "Horum"]
// Adding multiple items in the given index
people.splice(2, 0, "Madina", "Nodira");
console.log(people); // ["Lola", "Jaxongir", "Madina", "Nodira", "Horum"]
切片和拼接有什么区别?
slice - 返回数组的副本并且它不会改变数组
复制
复制
COPY
COPY
const people = ["Lola", "Jaxongir", "Test", "Horum"];
console.log(people.slice(0,2)) // ["Lola", "Jaxongir")
console.log(peopl) // ["Lola", "Jaxongir", "Test", "Horum"]
拼接- 删除单个或多个项目或添加单个或多个项目,并就地进行这些更改
复制
复制
COPY
COPY
const people = ["Lola", "Jaxongir", "Test", "Horum"];
people.splice(2, 1);
console.log(people); // ["Lola", "Jaxongir", "Horum"]
什么是 lambda 函数或箭头函数?
arrow function - 是 ES6 特性,与普通函数声明有一些不同
箭头函数没有 this 关键字,但它在其周围范围内使用 this 的任何值
由于上述原因,箭头函数不能用于创建构造函数
箭头函数没有超级参数
复制
复制
COPY
COPY
const person = {
name: "Jaxongir",
test: () => {
console.log(arguments) // ReferenceError: arguments is not defined
console.log(this) // references to window object
},
test2() {
console.log(arguments) // [2, 13, 321, 2]
console.log(this) // {name: 'Jaxongir', test: ƒ, test2: ƒ}
},
};
person.test();
person.test2(2, 13, 321, 2);
什么是IIFE(立即调用函数表达式)?
IIFE - 顾名思义就是函数,声明后立即执行。主要用于创建Module设计模式,Singleton设计模式,
复制
复制
COPY
COPY
const person = (() => {
let name = "Jaxongir";
let age = 27;
return {
name,
age,
};
})();
console.log(person) // {name: "Jaxongir", age: 27}
如何在 JavaScript 中对 URL 进行解码或编码?
encodeURI - 将一串 url 作为参数并对它进行编码并返回编码后的 URI
decodeURI - 采用 encodedURI 并返回解码后的 url
复制
复制
COPY
COPY
const uri = "https://mozilla.org/?x=шеллы";
const encoded = encodeURI(uri);
console.log(encoded); // https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B
console.log(decodeURI(encoded)) // https://mozilla.org/?x=шеллы
什么是记忆?
记忆- 是一种编程技术,它通过缓存昂贵的函数调用的结果并在发生相同输入时返回缓存的数据来优化应用程序的性能。并且仅在给出不同输入时执行相同的昂贵函数计算
复制
复制
COPY
COPY
const fib = (num, memo = []) => {
if (memo[num]) return memo[num];
if (num <= 2) return 1;
const res = fib(num - 1, memo) + fib(num - 2, memo);
memo[num] = res;
return res;
};
console.log(fib(5));
ES6 中的类是什么?
ES6 - 类允许像 Java 或其他 OOP 语言一样以 OOP 风格编写 JavaScript 程序。虽然在幕后,ES6 类转换为构造函数和原型继承开始发挥作用,但编写 OOP 风格的代码仍然更容易,特别是对于那些来自 OOP 语言的人。
复制
复制
COPY
COPY
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
eat(food) {
console.log(`${this.name} eats ${food}`);
}
sleep(time) {
console.log(`${this.name} sleeps at ${time}`);
}
wakeup(time) {
console.log(`${this.name} wakesup at ${time}`);
}
}
class Teacher extends Person {
constructor(name, age, role, salary, hobbies) {
super(name, age);
this.role = role;
this.salary = salary;
this.hobbies = hobbies;
}
printBio() {
console.log(
`${this.name} is ${this.age} years old. And he is ${
this.role
} with the salary of $${
this.salary
}. His hobbies are: ${this.hobbies.join(", ")}`
);
}
}
const jaxongir = new Teacher("Jaxongir", 27, "Full-Stack mentor", 1500, [
"Reading",
"Calisthenics",
"Swmming",
]);
jaxongir.eat("Caviar") // Jaxongir eats Caviar
jaxongir.sleep("23:00 pm") // Jaxongir sleeps at 23:00 pm
jaxongir.wakeup("09:00 am") // Jaxongir wakesup at 09:00 am
jaxongir.printBio() // Jaxongir is 27 years old. And he is Full-Stack mentor with the salary of $1500. His hobbies are: Reading, Calisthenics, Swmming
什么是模块?
模块- 是相关可重用代码的容器,可以导入多个文件。
为什么需要模块?
模块非常适合代码的数据隐私、模块化、可维护性、命名空间和可重用性。基本上,它们允许孤立地考虑软件,这减少了大脑的负担,并使考虑程序的整体结构变得容易。
什么是承诺
Promise - 指示异步操作结果的对象,可能是失败(拒绝)或成功(完成)。
复制
复制
COPY
COPY
const promise = new Promise(function (resolve, reject) {
// promise description
});
const promise = new Promise(
(resolve) => {
setTimeout(() => {
resolve("I'm a Promise!");
}, 5000);
},
(reject) => {}
);
promise.then((value) => console.log(value));
应许的三种状态是什么?
Promise的3种状态描述如下:
Fulfilled - 当异步请求成功完成并给出响应时
Rejected - 当异步请求不成功并且没有给出响应时,可能是由于网络错误,身份验证或授权错误等
Pending - 在请求发送和响应返回之间
什么是回调函数?
回调- 是作为参数传递给不同函数的函数,然后在该函数体内调用
复制
复制
COPY
COPY
const nums = [1, 2, 3, 4, 5];
const myMap = (callbackFunc, nums) => {
newNums = [];
for (const num of nums) {
newNums.push(callbackFunc(num));
}
return newNums;
};
const modifiedNums = myMap((num) => num * num, nums);
console.log(modifiedNums) // [1, 4, 9, 16, 25]
为什么我们需要回调?
回调函数非常有用,尤其是在异步操作中,例如:当获取数据或失败时调用回调以指示请求是成功还是失败。或者在用户单击按钮的事件中,触发回调以在回调主体中执行代码。
复制
复制
COPY
COPY
const generateReportBtn = document.querySelector(".generate-report");
const generateReport = ()=>{
// do something
}
generateReportBtn.addEventListener("click", generateReport)
const populatePeople = ()=>{
// do something
}
setTimeout(populatePeople, 2000)
什么是回调地狱以及如何避免它?
回调地狱- 这个术语用于描述回调函数何时相互嵌套太深,这使得调试此代码变得更加困难,因为即使是此代码的作者也很难阅读。解决方案是使用异步等待或承诺链接。
回调地狱的例子。这让我在梦中做噩梦
复制
复制
COPY
COPY
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
什么是承诺链?
Promise Chaining - 是我们在上面看到的回调地狱的解决方案。我们不是将一个回调嵌套在另一个回调中,而是使用先前已完成的承诺的结果,并为链中的下一个承诺返回已完成的承诺。
复制
复制
COPY
COPY
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
什么是 promise.all?
Promise.all - 是一个静态方法,它将 arraf 个可迭代的承诺作为输入并返回一个单一的 Promise,它是数组中已实现的承诺的值。已实现的承诺与它们的可迭代承诺的顺序相同。如果任何一个承诺被拒绝,整个操作将被拒绝。即使 promise 数组中的最后一个 promise 已实现,Promise.all() 也不会停止操作,而是等待直到每个 promise 都已实现。
复制
复制
COPY
COPY
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// Expected output: Array [3, 42, "foo"]
promise 中的 race 方法的目的是什么?
Promise.race - 是一种静态方法,它将可迭代的承诺作为输入并返回第一个已解析的承诺值。
复制
复制
COPY
COPY
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// Expected output: "two"
javascript 中的严格模式是什么?
严格模式- 在 JavaScript 中,用于将 javascript 环境设置为 sticter 模式,以避免错误,例如在没有关键字 var、let、const 的情况下声明变量。可以对整个环境或特定功能启动严格。
为什么需要严格模式?
我们需要严格模式因为:
通过将它们更改为抛出错误来消除一些 JavaScript 静默错误。
修复了导致 JavaScript 引擎难以执行优化的错误:严格模式代码有时可以比非严格模式的相同代码运行得更快。
禁止某些可能在未来版本的 ECMAScript 中定义的语法。
你如何声明严格模式?
我们可以通过在全局或特定函数中键入“use strict”来启用严格模式。
复制
复制
COPY
COPY
// Non strict mode
age = 27;
console.log(age) // 27
// Strict mode
"use strict";
age = 27;
console.log(age) // ReferenceError: age is not defined
删除运算符的目的是什么?
删除运算符- 用于删除对象的属性。如果该属性值是一个对象,则对该对象的引用将丢失
复制
复制
COPY
COPY
const person = {
name: "John",
age: 34,
country: "USA",
};
console.log(person) // {name: "John", age: 34, country: "USA"}
delete person.country;
console.log(person) // {name: "John", age: 34}
什么是 typeof 运算符?
typeof operator - 是一个函数,用于知道传递给它的表达式的类型
复制
复制
COPY
COPY
console.log(typeof 1) // number
console.log(typeof "hello") // string
console.log(typeof false) // boolean
console.log(typeof []) // object
console.log(typeof {}) // object
console.log(typeof undefined) // undefined
console.log(typeof null) // object
console.log(typeof NaN) // number
什么是未定义的?
undefined - 是原始数据类型。当声明了变量但没有给出值时,在控制台中它的结果是未定义的。
复制
复制
COPY
COPY
let name;
console.log(name) // undefined
什么是空?
null - 也是原始数据类型。它用于指示值的缺失。
复制
复制
COPY
COPY
let name = null;
console.log(name) // null
null 和 undefined 有什么区别?
*空
null 是原始数据类型,表示内存中没有为该变量分配内存
用于比较时转换为 0
typeof null 是一个对象
不明确的
undefined - 也是原始数据类型,表示为变量分配了内存并声明了它但没有分配任何值
用于比较时转换为 NaN
未定义的类型是未定义的
什么是评估?
eval - 用于将代码字符串作为 JavaScript 脚本执行的函数。代码字符串可以是表达式、函数调用等。
警告:从字符串执行 JavaScript 存在巨大的安全风险。当您使用 eval() 时,坏人很容易运行任意代码 - MDN
复制
复制
COPY
COPY
const add = (num1, num2) => num1 + num2;
console.log(eval("add(1, 9)")); // 10
窗口和文档有什么区别?
窗户
window 对象是每个页面上的根级元素
默认情况下,它在每个页面中都可用
它有确认、警报等方法
document 或 DOM 是其自身的直接子属性
文档
文档或 DOM 是窗口对象的直接子对象。它是 HTML 的表示
可以通过 document 或 window.document 引用
它让我们通过以下方法访问 DOM 元素:querySelector、getElementById、querySelectorAll 等
它让我们在 UI 上进行增删改查
你如何在javascript中访问历史记录?
我们可以通过使用 window 对象的 history 对象来分页历史记录。history 对象有 back 和 forward 方法。
复制
复制
COPY
COPY
// moves back to previous URI
window.history.back()
// moves forward to next URI
window.history.forward()
你如何检测大写锁定键是否打开?
我们可以通过使用 KeyboardEvent.getModifierState() 来检测大写锁定键是否被激活,它返回布尔值 true 表示大写锁定键被激活,false 表示未被激活。它不仅可以检测大写锁定,还可以检测 ScrollLock、NumsLock。
复制
复制
COPY
COPY
const heading = document.querySelector("h1");
document.body.addEventListener("click", (e) => {
const isCapsLockOn = e.getModifierState("CapsLock");
if (isCapsLockOn) {
heading.textContent = "CapsLock is Activated";
} else {
heading.textContent = "CapsLock is Deactivated";
}
});
什么是NaN?
isNaN - 内置函数,用于检查给定输入是否为 NaN(不是数字)
复制
复制
COPY
COPY
console.log(isNaN("1")) // false it's a number;
console.log(isNaN("st")) // true it's not a number
未声明和未定义的变量有什么区别?
未申报
变量是一个未声明或未赋值的变量,当试图访问它时,会抛出错误
没有为它们分配内存,因为它们还不存在
不明确的
变量是已声明但未分配值的变量。
内存已分配,当尝试在控制台中打印时,声明未定义
什么是全局变量?
全局变量- 是在 {} 和函数之外声明的变量,它们在任何地方都可以访问
复制
复制
COPY
COPY
// global variable
let name = "Jaxongir"
(()=>{
console.log(name) // Jaxongir
})()
全局变量有什么问题?
全局变量有很多问题,例如:
名称空间冲突
可维护性
可测试性