js面试题整理
- 1、JavaScript中的数据类型?存储上的差别?
- 2、js数据类型的判断?
- 3、如何转化数据类型?
- 4、JavaScript中tostring和string的区别?
- 5、说说变量提升?
- 6、数组的基本方法?
- 7、字符串中的常用方法?
- 8、数组去重?
- 9、什么是尾递归?
- 10、数组扁平化?
- 11、1+'2'和1-'2'是什么?
- 12、清除字符串前后空格和去除所有空格?
- 13、new操作符干了什么?
- 14、事件委托和事件代理?
- 15、0.1+0.2==3返回false,为什么,如何解决?
- 16、数组中取最大值?sort排序?
- 17、$(document).ready()方法和window.onload有什么区别?
- 18、== 和 === 区别?
- 19、js继承有哪些方法?
- 20、深拷贝和浅拷贝的区别?如何实现一个深拷贝?
- 21、同步和异步的区别?
- 22、对作用域链的理解?
- 23、typeof和instanceof有什么区别?
- 24、DOM常见的操作有哪些?
- 25、js中 1++ 和 ++1的区别?
- 26、如何判断this指向?箭头函数的this指向?
- 27、函数防抖节流的原理?
- 28、如何判断两个对象相等?
- 29、apply、call、bind?
- 30、数组中怎么取最大值?
- 31、promise的理解?
- 32、promise.all()?
- 33、如何实现 Promise.finally ?
- 34、ajax的核心对象(怎么去封装)?
- 35、get请求和post请求?
- 36、const 一个数组,能修改数组吗?
- 37、常见web安全及防护原理?
- 38、XML和JSON的区别?
- 39、js输入的五种方式?
- 40、什么是迭代器、生成器?
- 41、如何判断image加载完成?
- 42、怎么判断css3的动画执行结束?
- 43、prototype和proto?
- 44、原型、构造函数、实例化对象直接的关系?
- 45、如何改变this指针?
- 46、正则校验有哪些方法?如何用正则去写规则?
- 47、es6中class的理解?
- 48、class中的静态属性和静态方法?
- 49、用class类封装一个选项卡(面向对象)
- 50、什么是闭包,优缺点?
- 51、闭包的沙箱模式?
1、JavaScript中的数据类型?存储上的差别?
js中的数据类型分为基本数据类型和引用数据类型
基本数据类型(原始类型)包括——(存储在栈内存中):
- 数字类型(Number):表示数字,包括整数和浮点数
- 字符串类型(String):表示文本字符串
- 布尔类型(Boolean):表示真或假
- 空类型(Null):表述空值
- 未定义(undefined):表示未定义的值
- 符号(Symbol):唯一的标识符
引用数据类型(对象类型)包括——(存储在堆内存中):
- 对象类型(Object):表示复杂数据类型,包括数组、函数、日期、正则表达式等。
- 数组类型(Array):表示一组有序的数据。
- 函数类型(Function):表示可执行的代码块
- 正则表达式(RegExp):用于匹配字符串的模式
存储的差别?
基本数据类型存储在栈内存中,而引用数据类型存储在堆内存中。
栈内存是一种临时存储区域,用于存储基本数据类型的值和引用数据类型的引用地址。堆内存是一种动态分配的内存区域,用于存储引用数据类型的实际数据。
当一个变量存储的是基本数据类型时,它的值直接存储在栈内存中;当一个变量存储的是引用数据类型时,它的值是一个指向堆内存中实际数据的地址。
2、js数据类型的判断?
-
使用
typeof
运算符: 可以使用typeof
运算符来确定一个值的数据类型。它返回一个表示数据类型的字符串。例如:console.log(typeof 42); // 输出 "number" console.log(typeof "Hello"); // 输出 "string" console.log(typeof true); // 输出 "boolean"
-
使用
instanceof
运算符:instanceof
运算符可以用来检查对象是否属于某个特定的构造函数。例如:const arr = [1, 2, 3]; console.log(arr instanceof Array); // 输出 "true"
-
使用
Array.isArray()
方法:Array.isArray()
方法用于检查一个值是否为数组类型。例如:console.log(Array.isArray([1, 2, 3])); // 输出 "true"
-
使用
Object.prototype.toString
方法: 可以通过调用Object.prototype.toString
方法并将要检查的值作为参数传入,来获取其精确的数据类型信息。例如:console.log(Object.prototype.toString.call(42)); // 输出 "[object Number]" console.log(Object.prototype.toString.call("Hello")); // 输出 "[object String]"
3、如何转化数据类型?
-
转换为字符串(String)类型:
-
使用**toString()和String()**方法:toString不可以转undefined,null
let num = 42; let str1 = String(num); let str2 = num.toString();
-
转换为数字(Number)类型:
-
使用Number()和parseInt()等方法:
let str = "42"; let num1 = Number(str); let num2 = parseInt(str); // 解析整数 let num3 = parseFloat("3.14"); // 解析浮点数
-
转换为布尔(Boolean)类型:
-
使用Boolean()函数:
let a = 42; let b = ""; // 空字符串 let bool1 = Boolean(a); // true let bool2 = Boolean(b); // false
-
转换为数组(Array)类型:
-
使用Array.from()方法将类似数组的对象转换为真正的数组:
let arrayLikeObj = { 0: "a", 1: "b", length: 2 }; let arr = Array.from(arrayLikeObj); // ["a", "b"]
-
转换为对象(Object)类型:
-
使用对象字面量或构造函数进行对象的创建:
let obj1 = {}; // 空对象 let obj2 = new Object();
4、JavaScript中tostring和string的区别?
- tostring()是不能处理转换的值是null或者是undefined的,遇到这种情况下会在console中报错。
- string()是可以转换null和undefined的
5、说说变量提升?
变量提升是 JavaScript 中的一种特性,它是指在代码执行前,JavaScript 引擎会将变量和函数的声明提升到其所在作用域的顶部。这意味着可以在声明之前访问这些变量或函数。
在 JavaScript 中,变量提升主要包括两个方面:
-
变量声明的提升: 变量声明使用
var
、let
或const
关键字进行,而变量的赋值操作则不会被提升。如果在代码中先使用了一个变量,然后才进行声明,JavaScript 会将该声明提升到作用域的顶部。但是变量的初始值仍然是undefined
。例如:console.log(foo); // 输出 undefined var foo = "Hello";
-
函数声明的提升: JavaScript 中的函数可以先使用后声明,因为函数声明也会被提升到作用域的顶部。这意味着你可以在函数声明之前调用函数。例如:
greet(); // 输出 "Hello" function greet() { console.log("Hello"); }
需要注意的是,变量提升只会提升声明,而不会提升赋值操作。如果变量没有使用 var
、let
或 const
声明,它将被视为全局对象的属性。此外,使用 let
和 const
声明的变量在块级作用域内存在暂时性死区(TDZ),也会影响到变量的提升行为。
6、数组的基本方法?
添加:
push()
接受任意数量的参数,并且将它们添加至数组的末尾,返回数组的最新长度unshift()
在数组开头添加任意多个值,然后返回新的数组长度splice()
传入三个参数,分别是开始位置、0(要删除的元素数量)、插入的元素,返回空数组concat()
首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组删除:
pop()
方法用于删除数组的最后一项,同时减少数组的length 值,返回被删除的项shift()
方法用于删除数组的第一项,同时减少数组的length 值,返回被删除的项splice()
传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组slice()
用于创建一个包含原有数组中一个或多个元素的新数组,不会影响原始数组修改:
splice()
传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响查找:
indexOf()
返回要查找的元素在数组中的位置,如果没找到则返回-1includes()
返回要查找的元素在数组中的位置,找到返回true,否则falsefind()
返回第一个匹配的元素排序:
reverse()
顾名思义,将数组元素方向反转sort()
方法接受一个比较函数,用于判断哪个值应该排在前面转换:
join()
方法接收一个参数,即字符串分隔符,返回包含所有项的字符串迭代方法:
some()
对数组每一项都运行传入的测试函数,如果至少有1个元素返回 true ,则这个方法返回 trueevery()
对数组每一项都运行传入的测试函数,如果所有元素都返回 true ,则这个方法返回 trueforEach()
对数组每一项都运行传入的函数,没有返回值filter()
对数组每一项都运行传入的函数,函数返回 true的项会组成数组之后返回map()
对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组
7、字符串中的常用方法?
这里是引用
8、数组去重?
-
使用 Set 数据结构:Set 对象存储唯一值的集合,可以将数组转换为 Set,然后再将 Set 转回数组即可去重。例如:
const arr = [1, 2, 2, 3, 3, 4, 5, 5]; const uniqueArr = [...new Set(arr)]; console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
-
使用 filter() 方法结合 indexOf() 方法:利用数组的 filter() 方法和 indexOf() 方法,对数组进行遍历筛选,只保留首次出现的元素。例如:
const arr = [1, 2, 2, 3, 3, 4, 5, 5]; const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index); console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
-
使用 reduce() 方法:利用数组的 reduce() 方法,遍历数组,将不重复的元素放入新的数组。例如:
-
创建一个空对象 (或者使用已存在的对象)。
const arr = [1, 2, 2, 3, 3, 4, 5, 5]; const uniqueArr = arr.reduce((acc, curr) => { if (!acc.includes(curr)) { acc.push(curr); } return acc; }, []); console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
-
遍历数组,对于每个元素进行以下操作:
-
将数组元素作为对象的属性名。
-
将任意值(比如 true)作为属性值,以标记该元素已经出现过。
-
提取对象的所有属性名,组成新的数组,即为去重后的数组。
javascript复制代码const arr = [1, 2, 2, 3, 3, 4, 5, 5]; const obj = {}; const uniqueArr = []; arr.forEach(item => { if (!obj[item]) { obj[item] = true; uniqueArr.push(item); } }); console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
-
在上述代码中,obj
对象用于存储数组元素是否已经出现过。遍历数组时,如果当前元素不在 obj
对象中,则将其添加到 uniqueArr
数组中,并将 obj[item]
设置为 true
标记已经出现过。这样就可以通过对象的属性来实现数组去重。
9、什么是尾递归?
尾递归是指一个函数在调用自身之后不再执行任何其他操作,而是将返回值直接传递给函数调用的上级,从而避免了新的调用栈帧的创建。换句话说,尾递归是指递归调用发生在函数的最后一个语句中,从而使得函数调用不需要保存多个调用栈帧,而只需一个即可。
10、数组扁平化?
数组扁平化是指将多维数组转换为一维数组的操作。在 JavaScript 中,我们可以使用多种方式来实现数组的扁平化。
- 使用flat方法
const arr = [1, 2, [3, [4, 5]], 6]
console.log(arr.flat(Infinity));
- 使用正则表达式
const arr = [1, [2, [3, [4, 5],9]], 6]
function flatten(arr) {
// 使用正则表达式匹配字符,并替换
let arr1 = JSON.stringify(arr).replace(/\[|\]/g, '')
return JSON.parse('[' + arr1 + ']')
}
console.log(flatten(arr));
- 使用递归
const arr = [1, [2, [3, [4, 5]]], 6]
var array = []
function flatten(arr) {
// 判断是否是数组
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
flatten(arr[i])
}
else {
array.push(arr[i])
}
}
return array
}
console.log(flatten(arr));
- 使用reduce
const arr = [1, [2, [3, [4, 5]]], 6]
var array = []
function flatten(arr) {
return arr.reduce((sum, value) => {
return sum.concat(Array.isArray(value) ? flatten(value) : value)
}, [])
}
console.log(flatten(arr));
- 使用…扩展运算符
const arr = [1, [2, [3, [4, 5]]], 6]
function flat(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
console.log(flat(arr));
11、1+'2’和1-'2’是什么?
- 1+‘2’ =12
- 1-‘2’=-1
12、清除字符串前后空格和去除所有空格?
-
1.去除字符串首尾的空格
trim()
-
2.去除字符串中所有的空格
相当于去除字符串中所有的空字符,可以使用 replace(),
-
3.使用正则去除你想去掉的空格
正则表达式(RegEx)
13、new操作符干了什么?
- 创建一个空对象,并且
this
变量引用该对象,同时还继承了该函数的原型- 属性和方法被加入到
this
引用的对象中- 新创建的对象由
this
所引用,并且最后隐式的返回this
创建一个新的对象obj,将对象与构建函数通过原型链连接起来,将构建函数中的this绑定到新建的对象obj上,根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理。
14、事件委托和事件代理?
事件委托(event delegation)和事件代理(event delegation)是指同一种概念,在 JavaScript 中常用于处理事件的优化和性能提升。
事件委托/代理基本思想如下:
- 将事件绑定到一个父元素上,而不是将事件直接绑定到每个子元素上。
- 通过冒泡机制,当事件在子元素上触发时,会逐层向上冒泡到父元素,然后被父元素捕获并处理。
通过事件委托/代理的方式,可以实现以下几个好处:
- 减少事件处理程序的数量:只需将事件绑定到父元素上,而不需要为每个子元素分别绑定事件处理程序。
- 动态添加/删除子元素时仍可正常工作:由于事件是在父元素上处理的,因此对子元素的添加/删除不会影响事件的处理。
- 提升性能:减少了事件处理程序的个数,可以减少内存消耗,并提高事件的处理效率。
事件冒泡和捕获
事件冒泡:
- 在事件冒泡中,当一个元素触发了某个事件,该事件会从触发的元素开始向父元素逐层传播,直至传播到最顶层的文档对象。
- 也就是说,事件首先由触发事件的元素处理,然后从内部向外部传递,一层层向上冒泡。
- 通过事件冒泡,可以在父元素或祖先元素上捕获并处理事件。
事件捕获:
- 在事件捕获中,当一个元素触发了某个事件,该事件会从最顶层的文档对象开始向下传播至触发事件的元素。
- 即事件首先从最顶层的元素向下传递,直至传递到触发事件的元素。
- 通过事件捕获,可以在事件到达目标元素之前的任何祖先元素上捕获并处理事件
开启捕获(addEventListener
)
在 JavaScript 中,事件捕获是事件传播的一种阶段,它发生在事件冒泡之前。要开启事件捕获阶段,可以使用 addEventListener
方法的第三个参数,将其设置为 true
。
示例代码如下所示:
var element = document.getElementById('myElement');
element.addEventListener('click', function(event) {
console.log('捕获阶段');
}, true);
在上述示例中,我们通过将 addEventListener
的第三个参数设置为 true
,即开启了捕获阶段。当在 myElement
元素上触发 click 事件时,会先执行在捕获阶段注册的事件处理函数。
需要注意的是,大多数情况下不必显式开启捕获阶段,因为默认情况下事件会在冒泡阶段进行处理。捕获阶段和冒泡阶段共同构成了事件传播的过程。
总结起来:
- 捕获阶段:从最外层的祖先元素向目标元素传播,执行捕获阶段注册的事件处理函数。
- 目标阶段:到达目标元素本身,执行目标元素上注册的事件处理函数。
- 冒泡阶段:从目标元素向最外层的祖先元素传播,执行冒泡阶段注册的事件处理函数。
默认情况下,事件会在冒泡阶段进行处理。如果需要开启捕获阶段,可以将 addEventListener
方法的第三个参数设置为 true
。
阻止冒泡( event.stopPropagation())
在 JavaScript 中,要阻止事件冒泡(即停止事件向父元素的传播),可以使用 event.stopPropagation()
方法。
示例代码如下所示:
var element = document.getElementById('myElement');
element.addEventListener('click', function(event) {
event.stopPropagation(); // 阻止事件冒泡
console.log('点击了子元素');
});
document.addEventListener('click', function(event) {
console.log('点击了文档');
});
在上述示例中,当点击 myElement
元素时,会触发子元素的点击事件处理函数,并输出 “点击了子元素”。由于调用了 event.stopPropagation()
,事件不会继续向上层元素传播,因此不会触发文档上的点击事件处理函数。
需要注意的是,event.stopPropagation()
只能阻止事件在当前元素及其祖先元素之间的传播,无法阻止事件在同级元素之间的传播。如果希望完全取消事件的传播,包括同级元素,可以使用 event.stopImmediatePropagation()
方法。
总结起来:
event.stopPropagation()
用于阻止事件冒泡,只影响当前元素及其祖先元素之间的传播。event.stopImmediatePropagation()
用于完全取消事件的传播,包括同级元素。
请注意,以上操作是按照默认的事件冒泡阶段进行处理的。如果在捕获阶段注册了事件处理函数,并且希望阻止捕获阶段中的事件传播,可以在捕获阶段的事件处理函数中使用 event.stopPropagation()
或 event.stopImmediatePropagation()
方法。
15、0.1+0.2==3返回false,为什么,如何解决?
JavaScript 中的 number 类型就是浮点型,JavaScript 中的浮点数采用IEEE-754
格式的规定,这是一种二进制表示法,可以精确地表示分数,比如 1/2,1/8,1/1024,每个浮点数占 64 位。但是,二进制浮点数表示法并不能精确的表示类似 0.1 这样 的简单的数字,会有舍入误差。
由于采用二进制,JavaScript 也不能有限表示 1/10、1/2 等这样的分数。在二进制中,1/10(0.1)被表示为 0.00110011001100110011…… 注意 0011 是无限重复的,这是舍入误差造成的,所以对于 0.1 + 0.2 这样的运算,操作数会先被转成二进制,然后再计算
16、数组中取最大值?sort排序?
在 JavaScript 中,可以使用 Math.max()
方法或数组的 sort()
方法来获取数组中的最大值。
-
使用
Math.max()
方法:Math.max()
方法接受一组数字作为参数,并返回其中的最大值。但是,Math.max()
方法不接受数组作为参数,需要使用展开运算符...
将数组元素展开为单独的参数传递给该方法。示例代码如下:
const numbers = [10, 5, 8, 3, 12]; const maxNumber = Math.max(...numbers); console.log(maxNumber); // 输出:12
-
使用
sort()
方法:sort()
方法用于对数组进行排序,默认是按照字符编码的顺序排序。通过自定义比较函数,可以实现对数字类型的排序。使用sort()
方法将数组排序后,最后一个元素即为数组中的最大值。示例代码如下:
const numbers = [10, 5, 8, 3, 12]; numbers.sort((a, b) => a - b); // 升序排序 const maxNumber = numbers[numbers.length - 1]; console.log(maxNumber); // 输出:12
请注意,使用 sort()
方法会改变原始数组的顺序,如果不想改变原数组,可以先创建副本进行操作。
以上就是获取数组中最大值的方法,根据需求选择合适的方式进行处理。
17、$(document).ready()方法和window.onload有什么区别?
- window.onload方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行的。只能有一个
- $(document).ready() 方法可以在DOM载入就绪时就对其进行操纵,并调用执行绑定的函数。可以有多个
18、== 和 === 区别?
-
===:三个等号我们称为等同符,当等号两边的值为相同类型的时候,直接比较等号两边的值,值相同则返回true,若等号两边的值类型不同时直接返回false。
例:
100===“100” //返回falseabc===“abc” //返回false
‘abc’===“abc” //返回true
NaN===NaN //返回false
false===false //返回true
-
==:两个等号我们称为等值符,当等号两边的值为相同类型时比较值是否相同,类型不同时会发生类型的自动转换,转换为相同的类型后再作比较。
19、js继承有哪些方法?
-
1、原型链继承
- 原型链继承是通过将父类的实例作为子类的原型来实现继承。子类通过原型链可以访问到父类的属性和方法。但是,原型链继承存在的问题是所有子类实例共享同一个父类实例,导致对父类实例的修改会影响所有子类实例。
-
2、构造函数继承
- 构造函数继承通过在子类的构造函数中调用父类的构造函数来实现继承。这样可以实现每个子类实例都拥有独立的父类属性。然而,构造函数继承只能继承父类的实例属性和方法,不能继承父类原型上的属性和方法。
-
3、实例继承
-
4、拷贝继承
-
5、组合继承
- 组合继承结合了原型链继承和构造函数继承的优点。通过调用父类构造函数继承实例属性,并将父类的原型赋值给子类的原型来继承父类的原型属性和方法。这样既保证了实例属性的独立性,又继承了原型的属性和方法。但是,组合继承会导致父类构造函数被调用两次,一次是在继承实例属性时,另一次是在子类的原型赋值时。
-
6、寄生组合继承
- 通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
20、深拷贝和浅拷贝的区别?如何实现一个深拷贝?
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
在JavaScript中,存在浅拷贝的现象有:
- Object.assign
- Array.prototype.slice(),Array.prototype.concat()
- 使用拓展运算符实现复制
深拷贝就是开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
常见的深拷贝方式有:
- _.cloneDeep
- Jquery.extend()
- JSON.stringify()
- 手写循环递归的方法
21、同步和异步的区别?
同步任务 在主线程上排队执行的任务,只有前一个任务执行完毕之后,才会执行下一个任务
异步任务 不进入主线程,而进入 任务队列
的任务,只有等主线程的任务执行完毕,任务队列
开始通知主线程请求执行任务,该任务才会进入主线程执行。
简单来说,同步是阻塞式的,需要等待操作完成后才能进行下一步操作,而异步是非阻塞式的,不需要等待操作完成就可以进行下一步操作。
22、对作用域链的理解?
当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域
如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错
23、typeof和instanceof有什么区别?
typeof运算符和instanceof运算符在JavaScript中用于检测变量的类型,但它们有不同的应用场景和功能。
typeof运算符:
- typeof用于判断一个值的基本类型(原始类型)。
- 它返回一个表示值类型的字符串。常见的返回值包括:“number”、“string”、“boolean”、“undefined”、“object”、"function"以及
“symbol”(ES6新增)。 - typeof null 返回 “object” 是因为历史原因造成的错误,实际上 null 是一个特殊的原始值,而不是对象。
例子:
typeof 42; // "number"
typeof "Hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (错误的结果)
instanceof运算符:
- instanceof用于判断一个对象是否是某个构造函数的实例。
- 它基于原型链进行判断,即判断对象的原型链中是否出现了指定构造函数的原型对象。
- 如果对象是指定构造函数的实例,则返回 true,否则返回 false。
例子:
const obj = {};
obj instanceof Object; // true
function Person() {}
const person = new Person();
person instanceof Person; // true
const arr = [];
arr instanceof Array; // true
arr instanceof Object; // true,因为Array继承自Object
const str = "Hello";
str instanceof String; // false,因为str是基本类型而不是字符串对象
总结:
typeof用于判断基本类型。
instanceof用于判断对象的构造函数实例。
两者针对的对象范围不同,typeof适用于原始类型和函数(也是对象),instanceof适用于对象及其派生对象。
24、DOM常见的操作有哪些?
25、js中 1++ 和 ++1的区别?
<script>
let a = 1
console.log(a++); //1
console.log(a); //2
let b = 1
console.log(++b); //2
console.log(b); //2
</script>
- a++是先出原值,再运算;从以上可以看出,第一次打印的是原值,第二次打印的是运算后的值。
- ++a 是先运算,再出运算后的值;从以上可以看出,第一次打印就已经是运算后的值了,第二次打印依然是运算后的值。
26、如何判断this指向?箭头函数的this指向?
27、函数防抖节流的原理?
28、如何判断两个对象相等?
29、apply、call、bind?
30、数组中怎么取最大值?
31、promise的理解?
32、promise.all()?
33、如何实现 Promise.finally ?
34、ajax的核心对象(怎么去封装)?
35、get请求和post请求?
36、const 一个数组,能修改数组吗?
37、常见web安全及防护原理?
38、XML和JSON的区别?
XML(可扩展标记语言)和JSON(JavaScript对象表示)是两种常用的数据格式。它们之间的区别如下:
- 语法形式:
- XML使用标签来表示数据,具有固定的起始标签和结束标签。
- JSON使用键值对的形式来表示数据,使用花括号{}包裹,键和值之间使用冒号:分隔。
- 数据结构:
- XML以树状结构存储数据,使用嵌套的标签来表示层级关系。
- JSON以简洁的、扁平的结构存储数据,使用对象和数组来表示层级关系。
- 可读性:
- XML使用人类可读的标签和属性来表示数据,适合阅读和理解。
- JSON使用简洁的键值对结构,对于开发者来说更容易阅读和处理。
- 数据类型:
- XML中可以定义自定义的数据类型,例如DTD(文档类型定义)或者XSD(XML模式定义)。
- JSON只支持一些基本的数据类型,如字符串、数字、布尔值、数组和对象。
- 大小和传输效率:
- 由于XML使用更多的标签和元信息,相比JSON而言,XML的数据量更大。因此,在网络传输和处理速度方面,JSON通常比XML更高效。
- 数据体积方面:
- JSON相对于XML来讲,数据的体积小,传递的速度更快些。
选择使用XML还是JSON取决于具体的需求和场景。如果需要更好的人类可读性,或者需要使用自定义的数据类型,那么XML可能更适合。如果关注数据传输效率和处理速度,或者与JavaScript密切相关,那么JSON可能更合适。
39、js输入的五种方式?
JavaScript中常用的五个输入输出函数包括:
-
console.log():用于在浏览器的控制台或服务器端输出信息。可以接受多个参数,并将它们打印到控制台上。例如:
console.log("Hello, world!");
-
alert():在浏览器中显示一个弹窗,并将指定信息作为提示展示给用户。通常用于简单的消息提示,需要用户点击确认按钮才能关闭。例如:
alert("This is an alert message.");
-
prompt():在浏览器中显示一个带有输入框的弹窗,要求用户输入信息。用户输入的内容将作为函数的返回值使用。例如:
let name = prompt("Please enter your name:"); console.log("Hello, " + name);
-
confirm():在浏览器中显示一个带有确认和取消按钮的弹窗,询问用户是否同意某个操作。用户的选择结果将作为函数的返回值使用(true表示确认,false表示取消)。例如:
let result = confirm("Are you sure you want to delete this item?"); if (result) { console.log("Item deleted."); } else { console.log("Delete canceled."); }
-
document.write():将指定的内容直接写入到HTML文档中,可以用于动态生成或修改页面内容。注意,当文档已经加载完毕后再使用该函数会覆盖整个文档内容。例如:
document.write("<h1>Welcome!</h1>");
以上是JavaScript中常用的五个输入输出函数。根据需要选择适合的函数来实现所需的输入和输出操作。
40、什么是迭代器、生成器?
41、如何判断image加载完成?
42、怎么判断css3的动画执行结束?
43、prototype和proto?
44、原型、构造函数、实例化对象直接的关系?
45、如何改变this指针?
46、正则校验有哪些方法?如何用正则去写规则?
47、es6中class的理解?
48、class中的静态属性和静态方法?
49、用class类封装一个选项卡(面向对象)
50、什么是闭包,优缺点?
51、闭包的沙箱模式?
面试题会持续更新的哦---------------------,未完待续-------------------------------