基础题
1.什么是闭包?
闭包是指函数能够访问并操作其外部函数作用域中的变量。它通过将内部函数返回或传递给其他函数来实现。
例:function outer() {
var x = 10;
function inner() { console.log(x); }
return inner;
}
var closure = outer();
closure(); // 输出 10
2.JavaScript有哪些基本数据类型?
3.如何判断一个变量的数据类型?
instanceof:可以用来检查一个对象是否属于某个特定类或其子类。它是通过检查对象的原型链来确定的,如果对象的原型链中存在指定类或其子类,则返回true,否则返回false。它可以判断引用类型的具体类型,但不能判断基本类型。
Object.prototype.toString.call():可以用来获取一个对象的内部属性[[Class]],从而判断其类型。这种方法可以判断基本类型和引用类型,返回的结果是一个字符串,格式为"[object 类型]",其中类型表示对象的具体类型。可以判断基本类型和引用类型的具体类型,但需要通过调用方法来获取类型信息。
typeof():主要用于判断基本类型,如字符串、数字、布尔值等。对于引用类型,除了函数以外,typeof()只能返回"object",无法具体判断其类型。
4.什么是事件冒泡和事件捕获?它们有什么区别?
事件冒泡是指事件从最具体的元素开始触发,然后逐级向上传播到较为不具体的元素。事件捕获则相反,它从最不具体的元素开始触发,然后逐级向下传播到较为具体的元素。区别在于触发顺序的不同。
5.如何阻止事件冒泡或默认行为?
可以使用event.stopPropagation()
方法来阻止事件冒泡,使用event.preventDefault()
方法来阻止默认行为。
6.什么是原型链?如何利用原型链实现继承?
原型链是JavaScript中对象之间的一种关系,每个对象都有一个指向其原型的链接。当访问一个对象的属性时,如果该对象本身没有该属性,JavaScript会沿着原型链向上查找。通过将一个对象的原型设置为另一个对象,可以实现继承。
7.如何遍历一个对象的属性?
for…in循环:使用for…in循环可以遍历对象的所有可枚举属性,并访问每个属性。
Object.getOwnPropertyNames():使用Object.getOwnPropertyNames()方法可以获取对象的所有属性名,并返回一个包含属性名的数组。通过遍历这个数组,可以访问对象的属性。
Reflect.ownKeys():使用Reflect.ownKeys()方法可以获取对象的所有属性名(包括Symbol类型的属性),并返回一个包含属性名的数组。通过遍历这个数组,可以访问对象的属性。
8.如何判断一个变量是否为数组?
使用Array.isArray()方法:是数组则返回true,否则false。
使用instanceof操作: 可以使用instanceof操作符来一个变量是否为数组。
3.使用Array.prototype.isPrototypeOf()方法: 可以使用Array.prototype.isPrototypeOf()方法来判断一个变量是否为数组。
4.使用Object.prototype.toString()方法: 该方法会返回一个表示变量类型的字符串,对于数组来说,返回的字符串是"[object Array]"。
9.什么是AJAX?如何使用AJAX发送请求?
AJAX(Asynchronous JavaScript and XML)是一种在后台与服务器进行数据交换的技术。可以使用XMLHttpRequest
对象或fetch
函数来发送AJAX请求。
10.ajax请求的几种方法?
XMLHttpRequest对象:XMLHttpRequest是原生的JavaScript对象,它提供了一种在后台与服务器进行数据交换的方法。通过创建一个XMLHttpRequest对象,可以发送异步请求并接收服务器返回的数据。
Fetch API:Fetch API是一种现代的Web API,它提供了一种更简洁和强大的方式来进行网络请求。它使用Promise对象来处理异步操作,并提供了更灵活的请求和响应处理方式。
jQuery.ajax()方法:如果你使用jQuery库,可以使用其提供的ajax()方法来发送异步请求。这个方法封装了XMLHttpRequest对象,并提供了简化的语法和更高级的功能,如自动处理数据格式、跨域请求等。
Axios库:Axios是一个流行的第三方库,用于发送HTTP请求。它提供了简单易用的API,并支持Promise对象和拦截器等功能。Axios可以在浏览器和Node.js环境中使用。
11.简述axios请求?
首先,需要在项目中安装axios。可以使用npm或者yarn进行安装。在需要发送请求的文件中,引入axios模块。使用axios的方法发送请求,常见的方法有get、post、put、delete等。可以通过配置选项来设置请求的URL、请求头、请求体等信息。使用then方法处理请求成功的响应,使用catch方法处理请求失败的情况。12.post请求与get请求的区别?
参数传递方式:
GET请求:GET请求的参数会暴露在URL中,可以被缓存、浏览器历史记录等获取到。POST请求:参数通过请求体传递,不会暴露在URL中,参数通过请求体以键值对的形式传递。参数长度限制:
GET请求:由于参数附加在URL中,URL长度有限制,不同浏览器和服务器对URL长度的限制不同,一般为几千个字符。POST请求:由于参数通过请求体传递,没有URL长度限制,但是服务器和应用程序可能会对请求体的大小进行限制。安全性:
GET请求:参数暴露在URL中,容易被拦截、修改或泄露,不适合传递敏感信息。POST请求:参数不暴露在URL中,相对安全,适合传递敏感信息。缓存:
GET请求:由于参数暴露在URL中,可以被浏览器缓存,下次相同的请求可以直接使用缓存结果,提高性能。POST请求:由于参数不暴露在URL中,不会被浏览器缓存。幂等性:
GET请求:对于相同的请求,多次GET请求不会对服务器产生副作用,即不会改变服务器状态。POST请求:对于相同的请求,多次POST请求可能会对服务器产生副作用,即可能改变服务器状态。总结起来,GET请求适合获取数据,参数较少且不敏感;POST请求适合提交数据,参数较多或敏感。在实际应用中,根据具体需求选择合适的请求方式。
13.常用数组方法有哪些?
push():向数组末尾添加一个或多个元素,并返回新的长度。pop():删除并返回数组的最后一个元素。shift():删除并返回数组的第一个元素。unshift():向数组的开头添加一个或多个元素,并返回新的长度。concat():将两个或多个数组合并成一个新数组。slice():从指定位置开始截取数组的一部分,并返回一个新数组。splice():从指定位置删除或替换数组的元素,并返回被删除的元素。indexOf():返回指定元素在数组中第一次出现的索引,如果不存在则返回-1。lastIndexOf():返回指定元素在数组中最后一次出现的索引,如果不存在则返回-1。join():将数组的所有元素连接成一个字符串。reverse():颠倒数组中元素的顺序。sort():对数组进行排序,默认按照Unicode编码进行排序。filter():根据指定条件过滤数组中的元素,并返回一个新数组。map():对数组中的每个元素进行操作,并返回一个新数组。reduce():对数组中的所有元素进行累加或累计操作,并返回一个结果。14.遍历数组的方法有哪些?
15.如何改变this指向
使用call()方法:call()方法允许您在调用函数时显式指定函数的this值。它接受一个对象作为第一个参数,该对象将成为函数中的this值。其他参数是传递给函数的参数。使用apply()方法:apply()方法与call()方法类似,但是它接受一个数组作为参数,而不是单独的参数。bind()方法:bind()方法创建一个新的函数,其中this值被永久地设置为指定的对象。它返回一个绑定了指定this值的函数,而不会立即执行。箭头函数:箭头函数不会创建自己的this值,而是继承外部作用域的this值。16.简述Promise
Promise是一种用于处理异步操作的对象。它可以让我们更方便地处理回调函数和处理异步代码的结果。
17.async和await用法
async:async关键字用于定义一个函数为异步函数。异步函数在执行过程中可以暂停并等待异步操作的完成,然后恢复执行。在函数声明前加上async关键字,就可以将该函数定义为异步函数。
await:await关键字用于等待一个Promise对象的解析结果。在异步函数内部,可以使用await关键字来暂停函数的执行,直到Promise对象的状态变为resolved(解析完成)或rejected(解析失败)。await关键字后面跟着一个Promise对象,表示等待该Promise对象的解析结果。
区别:
async关键字用于定义一个函数为异步函数,而await关键字用于等待一个Promise对象的解析结果。async函数内部可以包含多个await语句,每个await语句都会等待前一个await语句的Promise对象解析完成。await只能在异步函数内部使用,而不能在普通函数中使用。18.简述面向对象概念
对象:对象是JavaScript中的基本单位,它可以包含属性和方法。属性是对象的特征或数据,而方法是对象的行为或功能。
类:类是对象的模板或蓝图,用于创建具有相似属性和方法的对象。在JavaScript中,类是通过构造函数来定义的。
构造函数:构造函数是用于创建和初始化对象的特殊函数。它定义了对象的属性和方法,并且可以使用new
关键字来实例化对象。
实例化:实例化是通过调用构造函数创建一个新的对象实例的过程。每个实例都是独立的,具有自己的属性和方法。
继承:继承是一种机制,允许一个类继承另一个类的属性和方法。通过继承,子类可以重用父类的代码,并且可以添加自己的特定功能。
封装:封装是一种将数据和操作封装在对象内部的概念。通过封装,我们可以隐藏对象的内部实现细节,并提供公共接口来访问和操作对象。
多态:多态是一种允许对象根据上下文表现出不同行为的特性。在JavaScript中,多态性通过函数重写和函数重载来实现。
19.面向对象的特点?
JavaScript中的面向对象编程具有以下特点:
封装:通过将数据和操作封装在对象中,实现了数据的隐藏和保护。对象的内部状态和行为对外部是不可见的,只能通过对象提供的接口进行访问和操作。
继承:通过继承机制,一个对象可以从另一个对象继承属性和方法。继承可以减少代码的重复,提高代码的复用性和可维护性。
多态:多态性允许一个对象可以以多种不同的方式工作。同一个方法可以根据不同的对象调用产生不同的行为。这种灵活性使得代码更加可扩展和可变。
原型链:JavaScript中的对象通过原型链来实现继承。每个对象都有一个原型对象,它定义了对象的属性和方法。当访问一个对象的属性或方法时,如果对象本身没有,则会沿着原型链向上查找。
动态性:JavaScript是一门动态语言,允许在运行时动态地添加、修改和删除对象的属性和方法。这种灵活性使得对象的结构和行为可以根据需要进行动态调整。
20.描述不同环境中的this指向?
全局作用域中的this:在全局作用域中,this指向全局对象(浏览器环境下为window对象,Node.js环境下为global对象)。
函数中的this:在函数中,this的指向取决于函数的调用方式。
作为函数调用时,this指向全局对象(非严格模式下)或undefined(严格模式下)。作为对象方法调用时,this指向调用该方法的对象。使用call、apply或bind方法调用时,this可以被显式指定为任意对象。使用箭头函数定义的函数中,this继承自外层作用域,与箭头函数定义时的this保持一致。构造函数中的this:当使用new关键字调用构造函数创建对象时,this指向新创建的实例对象。
事件处理函数中的this:在事件处理函数中,this通常指向触发事件的元素。
原型方法中的this:当通过实例对象调用原型方法时,this指向该实例对象。
箭头函数中的this:箭头函数没有自己的this绑定,它会捕获外层作用域的this值。
21.字符串的常用方法与区别?
length:返回字符串的长度。charAt(index):返回指定索引位置的字符。concat(str1, str2, …):连接两个或多个字符串,并返回新的字符串。indexOf(searchValue, startIndex):返回指定字符串在原字符串中第一次出现的位置,如果没有找到则返回-1。lastIndexOf(searchValue, startIndex):返回指定字符串在原字符串中最后一次出现的位置,如果没有找到返回-1。slice(startIndex, endIndex):提取原字符串中指定范围的字符,并返回新的字符串。不包括 endIndex 对应的字符。substring(startIndex, endIndex):提取原字符串中指定范围的字符,并返回新的字符串。不包括 endIndex 对应的字符。与 slice 方法类似,但不支持负数索引。substr(startIndex, length):提取原字符串中从指定索引开始的指定长度的字符,并返回新的字符串。replace(searchValue, replaceValue):将原字符串中的指定子串替换为新的子串,并返回新的字符串。只替换第一个匹配项。toUpperCase():将原字符串转换为大写字母形式,并返回新的字符串。toLowerCase():将原字符串转换为小写字母形式,并返回新的字符串。trim():去除原字符串两端的空格,并返回新的字符串。22.创造对象有几种方法?
对象字面量:使用花括号{}来定义一个对象,并在其中添加属性和方法。
2.构造函数:使用构造函数来创建对象。构造函数是一个普通的函数,通过使用new
关键字来实例化对象。
3.Object.create()方法:使用Object.create()方法来创建一个新对象,该对象的原型是指定的原型对象。
4.ES6类:使用class关键字来定义一个类,并使用构造函数和方法来创建对象。
23.如何实现防抖和节流?
防抖是指在事件触发后等待一段时间,如果在这段时间内没有再次触发该事件,则执行相应的操作。如果在等待时间内又触发了该事件,则重新计时。防抖常用于处理频繁触发的事件,如窗口大小改变、输入框输入等。
function debounce(func, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
}, delay);
};
}
节流是指在一定时间间隔内只执行一次操作。如果在这个时间间隔内多次触发了该事件,只有第一次触发会执行相应的操作。节流常用于处理频繁触发但只需要执行一次的事件,如滚动事件、鼠标移动事件等。
function throttle(func, delay) {
let timer;
return function() {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, arguments);
timer = null;
}, delay);
}
};
}
使用防抖和节流函数可以有效地控制函数的执行频率,提升页面性能和用户体验。
24.前端如何处理跨域请求?
25.null和undefined有什么区别?
当一个变量被赋值为null时,表示该变量的值为空。
undefined表示一个未定义的值。当一个变量被声明但未被赋值时,它的默认值就是undefined。
null是一个表示空值的关键字,而undefined是一个全局变量。这意味着undefined的值可以被修改,而null不能被重新赋值.
在使用条件判断时,null和undefined都会被视为假值。
26.什么情况Boolean()函数返回false?
false0空字符串(“”)nullundefinedNaN对于其他情况,Boolean()函数返回true
27.JS中哪些事件方法是低版本浏览器不能兼容的?
addEventListener:这是一种用于添加事件监听器的方法,但在低版本的Internet Explorer(IE8及更早版本)中不被支持。在这些浏览器中,可以使用attachEvent方法来代替。
removeEventListener:这是用于移除事件监听器的方法,与addEventListener类似,在低版本的IE中不被支持。可以使用detachEvent方法来代替。
event.preventDefault:这个方法用于阻止事件的默认行为,例如阻止链接的跳转或表单的提交。在低版本的IE中,可以使用event.returnValue = false来达到相同的效果。
event.stopPropagation:这个方法用于停止事件冒泡,即阻止事件向父元素传播。在低版本的IE中,可以使用event.cancelBubble = true来达到相同的效果。
event.target:这个属性用于获取触发事件的元素,在低版本的IE中不被支持。可以使用event.srcElement来代替。
event.which:这个属性用于获取按下的键盘按键的编码,在低版本的IE中不被支持。可以使用event.keyCode来代替。
event.pageX和event.pageY:这两个属性用于获取鼠标事件发生时鼠标相对于文档的水平和垂直坐标,在低版本的IE中不被支持。可以使用event.clientX和event.clientY来代替。
28.JS优化提高性能的方法有哪些?
29.选择DOM元素的多种方法?
getElementById:通过元素的id属性选择元素。例如,使用document.getElementById(“myElement”)可以选择id为"myElement"的元素。
getElementsByClassName:通过元素的class属性选择元素。例如,使用document.getElementsByClassName(“myClass”)可以选择class为"myClass"的所有元素。
getElementsByTagName:通过元素的标签名选择元素。例如,使用document.getElementsByTagName(“div”)可以选择所有的div元素。
querySelector:通过CSS选择器选择元素。例如,使用document.querySelector(“#myElement .myClass”)可以选择id为"myElement"且包含class为"myClass"的元素。
querySelectorAll:通过CSS选择器选择多个元素。例如,使用document.querySelectorAll(“.myClass”)可以选择所有class为"myClass"的元素。
parentNode和childNodes:通过父节点和子节点选择元素。例如,使用element.parentNode可以选择元素的父节点,使用element.childNodes可以选择元素的所有子节点。
nextSibling和previousSibling:通过相邻节点选择元素。例如,使用element.nextSibling可以选择元素的下一个相邻节点,使用element.previousSibling可以选择元素的上一个相邻节点。
30.说一下JS纯函数概念?
JS纯函数是指在相同的输入下,始终返回相同的输出,并且没有副作用的函数。纯函数不会修改传入的参数,也不会对外部环境产生任何影响,包括修改全局变量、发送网络请求等。纯函数的特点是可预测性和可测试性,因为它们不依赖于外部状态。
纯函数的优点包括:
可缓存性:由于纯函数的输出只取决于输入,可以将函数的结果缓存起来,避免重复计算。可移植性:纯函数可以在不同的环境中使用,因为它们不依赖于外部状态。可测试性:由于纯函数的输出可预测且不依赖于外部状态,可以方便地编写单元测试。以下是一些判断一个函数是否为纯函数的条件:
函数的返回值只依赖于输入参数。函数内部没有修改任何外部状态。函数没有产生任何副作用。ES6高频面试题
1.请解释一下ES6中let和const与var的区别。
2.请解释一下箭头函数的特点。
箭头函数是一种更简洁的函数定义方式,可以减少代码量。箭头函数没有自己的this值,它会继承外部作用域的this值。箭头函数不能作为构造函数使用,不能使用new关键字调用。3.ES6中的模板字符串是什么。
是一种更方便拼接字符串的方式,使用反引号(`)包裹字符串,可以包含变量,使用${}来插入变量值。
4.ES6中的解构赋值是什么。
是一种从数组或对象中提取值并赋给变量的方式。可以简化代码,减少变量声明和赋值的步骤。
5.ES6中的展开运算符是什么。
展开运算符(…)可以将一个数组或对象展开成多个元素。可以使用展开运算符传递数组或对象的元素作为参数。
6.解释一下ES6中的类是什么。
类是一种面向对象编程的概念,用于创建对象的模板。类可以包含属性和方法,可以通过实例化类来创建对象。7.解释一下ES6中的模块化是什么。
模块化是一种将代码分割成独立的模块,每个模块有自己的作用域。模块可以导出(export)和导入(import)变量、函数、类等。8.请解释一下ES6中的Promise是什么。
Promise是一种处理异步操作的方式。Promise表示一个异步操作的最终完成或失败,并返回结果或错误信息算法题
1.反转字符串:编写一个函数,将输入的字符串反转。
function reverseString(str) {
return str.split('').reverse().join('');
}
2.查找数组内的最大值和最小值:编写一个函数,接受一个数字数组作为参数,返回数组中的最大值和最小值。
function findMinMax(arr) {
const min = Math.min(...arr);
const max = Math.max(...arr);
return { min, max };
}
3.数组去重:编写一个函数,接受一个数组作为参数,返回去重后的数组。
function removeDuplicates(arr) {
return [...new Set(arr)];
}
4.斐波那契数列:编写一个函数,接受一个数字n作为参数,返回斐波那契数列中第n个数字的值。
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
5.编写一个函数,判断输入的字符串是否是回文字符串(正读和反读都一样)。
function isPalindrome(str) {
const reversedStr = str.split('').reverse().join('');
return str === reversedStr;
}
6.两个字符串是否是异位词:编写一个函数,判断两个字符串是否包含相同的字符,但字符的顺序可以不同。
function isAnagram(str1, str2) {
const sortedStr1 = str1.split('').sort().join('');
const sortedStr2 = str2.split('').sort().join('');
return sortedStr1 === sortedStr2;
}
7.数组求和:编写一个函数,接受一个数字数组作为参数,返回数组中所有数字的和。
function sumArray(arr) {
return arr.reduce((sum, num) => sum + num, 0);
}
8.数组平均值:编写一个函数,接受一个数字数组作为参数,返回数组中所有数字的平均值。
function calculateAverage(arr) {
const sum = arr.reduce((sum, num) => sum + num, 0);
return sum / arr.length;
}
9.查找最长单词:编写一个函数,接受一个字符串作为参数,返回字符串中最长的单词。
function findLongestWord(str) {
const words = str.split(' ');
let longestWord = '';
for (let word of words) {
if (word.length > longestWord.length) {
longestWord = word;
}
}
return longestWord;
}
git面试题
1.为什么要使用Git?
Git是一个分布式版本控制系统,用于跟踪文件的变化并协调多人在同一个项目上的工作。使用Git可以实现团队协作、版本管理、代码回滚等功能。
2.Git的工作流程是怎样的?
克隆(Clone):将远程仓库的代码复制到本地。修改(Modify):在本地进行代码的修改。提交(Commit):将修改后的代码提交到本地仓库。推送(Push):将本地仓库的代码推送到远程仓库。3.Git中的分支(Branch)有什么作用?如何创建和切换分支?
分支是Git中用于并行开发和管理代码的重要概念。通过创建分支,可以在不影响主线代码的情况下进行新功能的开发或问题的修复。
创建分支:git branch <branch-name>
切换分支:git checkout <branch-name>
4.如何解决Git冲突?
执行git pull
命令,将远程仓库的最新代码拉取到本地。手动解决冲突:打开冲突文件,根据提示修改代码,删除或保留需要的部分。执行git add <file>
命令,将解决冲突后的文件添加到暂存区。执行git commit
命令,提交解决冲突后的代码。 5.如何撤销Git的提交?
撤销最近一次提交并保留修改:git reset HEAD~
撤销最近一次提交并丢弃修改:git reset --hard HEAD~
撤销指定提交:git revert <commit-id>