1.优雅的取随机字符串
Math.random().toString(16).substring(2)
2.优雅的取整
var a= 2.33 | 0
3.标准JSON的深拷贝
var b=JSON.parse(JSON.stringify(a))
4.相等
++[[]][+[]]+[+[]] == 10
5.数组去重
[...new Set([1, "1", 2, 1, 1, 3])]
6.实现一个长度为m(6)且值都n(8)的数组
Array(6).fill(8)
7.取出一个数组中的最大值和最小值
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var maxInNumbers = Math.max.apply(Math, numbers);
var minInNumbers = Math.min.apply(Math, numbers);
8.判断奇偶数
var num=3;
!!(num & 1) // true
!!(num % 2) // true
9.JS代码混淆加密
var a=1;
var b=true;
console.log(a,b);
10.字符串比较时间先后
var a = "2014-08-08";
var b = "2014-09-09";
console.log(a>b, a<b); // false true
11.使用解构来交换参数数值
let param1 = 1;
let param2 = 2;
[param1, param2] = [param2, param1];
console.log(param1) // 2
console.log(param2) // 1
12.带有多个条件的if 语句
if (["abc", "def", "ghi", "jkl"].includes(x)) {}
13.条件查找简化
// bad
if (type === "test1") {
test1();
} else if (type === "test2") {
test2();
} else if (type === "test3") {
test3();
} else if (type === "test4") {
test4();
} else {
throw new Error("Invalid value " + type);
}
// better
var types = {
test1,
test2,
test3,
test4,
};
types[type] && types[type]();
14.打乱数组
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
list.sort(() => {
return Math.random() - 0.5;
});
15.将Object属性转成属性数组
const obj = { a: 1, b: 2, c: 3 };
Object.entries(obj);
// 输出
(3) [Array(2), Array(2), Array(2)]
0: (2) ["a", 1]
1: (2) ["b", 2]
2: (2) ["c", 3]
16.JavaScript中typeof操作符有哪些返回值?
typeof操作符返回字符串数据类型。可能的返回值有:“undefined”、“boolean”、“number”、“string”、“object"和"function”
17.如何检查一个变量是否为数组?
可以使用Array.isArray()方法检查一个变量是否为数组。该方法在ES5中引入,在ES5之前,可以使用Object.prototype.toString.call方法
18.如何判断一个变量是否为undefined
使用typeof操作符:typeof varName === “undefined”
直接比较varName与undefined:varName === undefined
使用void操作符:void(0) === undefined
19.如何将一个字符串转换为数字?
可以使用parseInt()或parseFloat()方法将一个字符串转换为数字。parseInt()方法将字符串转换为整数,parseFloat()方法将字符串转换为浮点数
20.如何将一个数字转换为字符串?
可以使用toString()方法将一个数字转换为字符串。
21.如何从一个数组中删除一个元素?
答案:可以使用splice()方法从一个数组中删除一个元素。
22.如何在JavaScript中实现继承?
JavaScript中的继承可以通过原型链实现。子类可以使用Object.create()方法继承父类的原型。还可以使用ES6中的class关键字和extends关键字来定义类和继承关系。
23.如何在JavaScript中处理异步操作?
可以使用回调函数、Promise和async/await来处理异步操作。
24.如何判断一个变量是否为对象?
可以使用typeof操作符和instanceof操作符来判断一个变量是否为对象。
25.JavaScript中的闭包是什么?
闭包指的是在一个函数内部定义的另一个函数,并且内部函数可以访问到外部函数的变量。闭包可以解决JavaScript中变量作用域的问题
当函数执行结束后,它的作用域链就会被销毁,其中的变量也会被销毁
26.如何避免JavaScript闭包内存泄漏?
及时释放闭包:当不再需要闭包时,应该将其引用设为null,以便垃圾回收器回收变量。
使用事件委托:当事件委托注册的事件处理程序执行完毕后,其作用域中的变量就可以被垃圾回收器回收。
优点:避免全局变量的污染,希望一个变量长期存储在内存中(缓存变量)
缺点:内存泄露(消耗),常驻内存,增加内存使用量
27.如何实现JavaScript中的模块化?
CommonJS规范:CommonJS规范是Node.js中广泛使用的模块化规范。该规范使用require()函数加载模块,使用module.exports导出模块。
AMD规范:AMD规范是一种异步模块定义规范,用于浏览器端的模块化。该规范使用require()函数异步加载模块,使用define()函数定义模块。
ES6模块:ES6模块是ES6中引入的一种模块化规范。该规范使用import语句加载模块,使用export语句导出模块
28.如何处理JavaScript中的错误?
JavaScript中的错误可以使用try-catch语句处理。
29.如何判断一个数组中是否包含一个特定的值?
可以使用indexOf()方法或includes()方法判断一个数组中是否包含一个特定的值。
30.ES5 和 ES6 分别几种方式声明变量
ES5 有俩种: var 和 function
ES6 有六种:增加四种, let 、 const 、 class 和 import
31.数组去重的方法
ES6 的 Set
reduce()
filter()
32.DOM 事件有哪些阶段?谈谈对事件代理的理解
分为三大阶段:捕获阶段–目标阶段–冒泡阶段
事件代理简单说就是:事件不直接绑定到某元素上,而是绑定到该元素的父元素上,进行触发事件操作时(例如’click’),再通过条件判断,执行事件触发后的语句(例如’alert(e.target.innerHTML)')
好处:(1)使代码更简洁;(2)节省内存开销
33.js 执行机制、事件循环
avaScript 语言的一大特点就是单线程,同一个时间只能做一件事
34.对前端性能优化有什么了解?一般都通过那几个方面去优化的?
1. 减少请求数量
2. 减小资源大小
3. 优化网络连接
4. 优化资源加载
5. 减少重绘回流
6. 性能更好的API
7. webpack优化
35.冒泡机制
事件冒泡(event bubbling),事件最开始时由触发的那个元素身上发生,然后沿着DOM树向上传播,直到document对象。如果想阻止事件起泡,可以使用e.stopPropagation()。
36.什么是 “use strict”; ? 使用它的好处和坏处分别是什么?
优点
消除Javascript语法的一些不严谨之处,减少一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提高编译器效率,增加运行速度;
为未来新版本的Javascript做好铺垫。
缺点
严格模式改变了语义。依赖这些改变可能会导致没有实现严格模式的浏览器中出现问题或者错误。
37.请解释 JavaScript 的同源策略
同源策略限制了一个源(origin)中加载文本或脚本与来自其它源(origin)中资源的交互方式。同源指的是协议、域名、端口相同,同源策略是一种安全协议
38.javascript有几种数据类型
一类是基本数据类型,包含7种类型,分别是Number 、String、Boolean、BigInt、Symbol、Null、Undefined。另一类是引用数据类型,通常用Object代表,普通对象,数组,正则,日期,Math数学函数都属于Object
39.let,const和var有什么区别
var声明的变量存在变量提升,允许重复声明变量。let和const在同一作用域不允许重复声明变量,var不存在暂时性死区。let和const存在暂时性死区
const 声明的变量不能被重新赋值,而 let 和 var 可以。
let 和 const 声明的变量具有块级作用域,可以在不同的块中重新定义变量,而使用 var 声明的变量在不同的块中被重新定义,会影响整个函数的作用域。
40.箭头函数
箭头函数声明的全都是匿名函数,不能用于构造函数,并且不具有arguments对象,
箭头函数中的this指向与普通函数不同
在普通函数中,this总是指向调用它的对象,如果用作构造函数,他指向创建的对象实例。
箭头函数没有自己的this,他的this是继承而来的,默认指向在定义时他所在的对象,而不是执行时的对象。
41.常用的数组方法
push:向数组末尾添加一个或多个元素,并返回新数组的长度
pop:从数组末尾删除一个元素,并返回该元素的值
shift:从数组开头删除一个元素,并返回该元素的值
unshift:向数组开头添加一个或多个元素,并返回新数组的长度
splice:从数组中删除或替换一个或多个元素,可以传入三个参数,分别是开始位置、要删除的元素数量、插入的元素(一直与slice记混,重点记一下)
slice:返回数组的一个片段或子数组,可以传入两个参数,分别是开始索引位置、截取到的索引位置
concat:将两个或多个数组合并成一个新数组
join:将数组元素连接成一个字符串
indexOf():返回要查找的元素在数组中的位置,如果没找到则返回 -1
includes():返回要查找的元素在数组中的位置,找到返回true,否则false
find():返回第一个匹配的元素
reverse:将数组元素反转
sort:对数组元素进行排序
map:对数组中的每个元素执行指定的函数,并返回一个新数组
filter:对数组中的每个元素执行指定的测试函数,并返回一个新数组,其中包含所有通过测试的元素
reduce:对数组中的每个元素执行指定的累加器函数,并返回一个累加器值。
forEach:对数组中的每个元素执行指定的函数,无返回值
42.堆和栈的区别
内存分配方式不同:栈是一种自动分配和释放内存的数据结构,由系统自动管理,程序员无需手动分配和释放内存。而堆则是程序员手动申请和释放内存。
内存管理方式不同:栈采用“先进后出”的方式管理数据,每次数据入栈时都会被压入栈顶,每次数据出栈时都会从栈顶弹出。而堆则没有固定的管理方式,程序员需要手动管理其内存。
内存空间大小不同:栈的内存空间通常较小,由系统分配的栈空间在程序运行时就已经确定,栈溢出是一种常见的错误。而堆的内存空间通常较大,可以在程序运行时动态分配并释放。
存储内容不同:栈主要用于存储函数调用时的临时变量、函数参数和返回地址等数据,而堆主要用于存储程序运行时动态分配的数据、对象和数组等
43.浅拷贝
浅拷贝是指创建一个新对象,将原对象中的属性值复制到新对象中,如果属性值是一个引用类型数据,那么新对象中的属性值仍然是原对象中的引用,也就是说,新对象和原对象中的引用类型数据共享一份内存空间
Object.assign
Array.prototype.slice(), Array.prototype.concat()
使用拓展运算符实现的复制
44.深拷贝
深拷贝是指创建一个新对象,将原对象中的属性值复制到新对象中,如果属性值是一个引用类型数据,那么新对象中的属性值是原对象中属性值的一个完全独立的副本
JSON.stringify() 手写循环递归
45.bind、call、apply 区别
call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向
apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入
改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
call
方法的第一个参数也是this的指向,后面传入的是一个参数列表
跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)
改变this指向后不会立即执行,而是返回一个永久改变this指向的函数
46.节点操作
创建dom节点
createElement() 创建一个元素节点 => 接收参数为string类型的nodename
createTextNode() 创建一个文本节点 => 接收参数为string类型的text内容
createAttribute() 创建一个属性节点 => 接收参数为string类型的属性名称
createComment() 创建一个注释节点 => 接收参数为string类型的注释文本
插入DOM节点
appendChild():把节点插入到父节点的末尾。
insertBefore():把节点插入到父节点的某个兄弟节点的前面。
删除DOM节点
removeChild()。
查找DOM节点
getElementById() getElementsByTagName()
替换DOM节点
replaceChild()