前端js基础面试题目
- 1、对象的深度克隆
- 2、get和post区别
- 3、js实现图片拖拽功能和鼠标滚轮放大缩小
- 4、js文件上传下载
- 5、对node.js的理解
- 6、对webpack的理解
- 7、seo搜索引擎优化
- 8、es6新特性
- 9、js中的构造函数
- 10、DOM和BOM的理解,常见BOM对象
- 12、数组去重方法
- 13、两个整数交换的方法
- 14、保存表单如何防止用户重复点击产生多条相同数据
- call()与apply()的作用与区别
- js渲染机制
- js运行机制
- 页面性能
- 错误监控
- js实现继承的方式
- call和apply的区别
- websoket与http区别
- 创建对象有几种方法
- ajax工作原理及优缺点
- 找出一段字符串中出现最多的某个字符,统计次数
- 判断js类型的方式
- 构造函数与普通函数的区别
- ES6 的 class 和构造函数的区别
- 闭包的概念,优缺点
- 箭头函数与普通函数的区别
1、对象的深度克隆
object和Array的递归:
方法一:递归遍历
deepClone(obj) {
let newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
debugger;
newObj[key] = typeof obj[key] == 'object' ? this.deepClone(obj[key]) : obj[key];
console.log(newObj[key]);
}
return newObj;
}
方法二:
JSON.parse(JSON.stringify(obj)) 实现,切断引用之间的联系,对具体数组或对象进行修改
缺点:
对Date对象拷贝后会变为字符串
对正则RegExp拷贝后会变为空对象
丢失function
对于含有date和regexp类型的可使用valueOf方法实现深拷贝
方法三:
…解构赋值
一级为深度拷贝,二级及以上为浅拷贝
代码测试:
可以看到obj2和obj4为深度拷贝,obj1为浅拷贝,obj3一级为深度拷贝,二级围为浅拷贝
另外:数组的slice、concat方法也能实现数组深度拷贝
2、get和post区别
get和post是http协议中两种发送请求的方式
HTTP是什么?HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。
HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。
一般get方法参数在url后面,post方法放在body里面,但get也能将参数放到body里面,post也能放到url后面(技术上可实现)
数据量太大对浏览器和服务器都是很大负担。大多数浏览器通常都会限制url长度在2K个字节,而大多数服务器最多处理64K大小的url。
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
GET和POST还有一个重大区别,简单的说:
GET产生一个TCP数据包;POST产生两个TCP数据包。
长的说:
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
3、js实现图片拖拽功能和鼠标滚轮放大缩小
拖拽:
首先是三个事件,分别是mousedown,mousemove和mousewheel
clientX,clientY标识的是鼠标的坐标,分别标识横坐标和纵坐标
mousedown的时间里记录鼠标的初始横纵坐标,mousemove事件里记录鼠标移动时的横纵坐标
要拖拽的div相对父盒子绝对定位,拖拽时动态改变绝对定位的top和left值
定位信息为:鼠标移动时的横纵坐标-鼠标的初始横纵坐标/父盒子的横纵坐标*100%
滚轮放大缩小:
获取滚轮事件中的wheelDelta值,然后通过transform: scale()来进行缩放
4、js文件上传下载
input type=file
参考:https://blog.csdn.net/WuLex/article/details/84296934?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3
5、对node.js的理解
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境
6、对webpack的理解
1、webpack是什么,为什么要使用webpack
代码编译工具
前端各种框架各种新语言的出现如:es6,scss等,相对于传统es5,css语法功能更强大。但并不是所有浏览器兼容这些新语法。所以写完代码后要通过工具转换。
2、基础结构
//入口出口
resolve//模块文件路径
module//配置模块的读取和解析规则
devServer//服务器,提升开发效率配置
3、webpack的构建流程是什么?
初始化参数—找到入口–编译模块–输出结果
7、seo搜索引擎优化
8、es6新特性
1、let和const命令
let命令用来声明变量用法和var类似,但let所声明的变量只在let所在的代码块有效,即块级作用域,典型的案例for循环计数器
const声明一个只读的常量。一旦声明,常量的值就不能改变。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。
2、解构赋值
如数组,对象,字符串的解构赋值,解构赋值规则:只要等号右边的值不是对象或数组,就先将其转为对象。
3、set和map数据结构
ES6提供了新的数据结构Set。类似于数组,只不过其成员值都是唯一的,没有重复的值。
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。
4、class的继承
5、promise对象
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
参考:
https://www.cnblogs.com/xkloveme/p/7456656.html
9、js中的构造函数
10、DOM和BOM的理解,常见BOM对象
12、数组去重方法
13、两个整数交换的方法
14、保存表单如何防止用户重复点击产生多条相同数据
call()与apply()的作用与区别
js渲染机制
参考:https://www.jianshu.com/p/642d1cefe86b
js运行机制
单线程、任务队列
参考:
https://www.jianshu.com/p/ca52c3c0fd8a
页面性能
错误监控
js实现继承的方式
1、原型链继承
function Parent1() {
this.name = 'parent1';
}
function Child1() {
this.type = 'child1'
}
Child1.prototype = new Parent1();
var ss = new Child1(); //ss._proto_ = Child1.prototype
特点:
非常纯粹的继承关系,实例是子类的实例,也是父类的实例;父类新增原型方法/原型属性,子类都能访问到;简单,易于实现。
缺点:
实例的原型对象共用,改一个实例的属性另一个会受影响,
要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中无法实现多继承。
创建子类实例时,无法向父类构造函数传参。
2、构造函数继承
function Parent1() {
this.name = 'parent1';
}
function Child1() {
Parent1.call(this);
this.type = 'child1'
}
var s1 = new Child1(); //不能继承原型属性/方法
var s2 = new Child1();
s1.name = 'ss_parent1';
console.log(s1.name);//ss_parent1
console.log(s2.name);//ss_parent1
特点:
创建子类实例时,可以向父类传递参数;可以实现多继承(call多个父类对象)。
缺点:
实例并不是父类的实例,只是子类的实例;只能继承父类的实例属性和方法,不能继承原型属性/方法;无法实现函数复用,每个子类都有父类实例函数的副本,影响性能。
3、组合继承
function Parent1() {
this.name = 'parent1';
}
function Child1() {
Parent1.call(this);
this.type = 'child1'
}
Child1.prototype = new Parent1();
var s1 = new Child1(); //
var s2 = new Child1();
s1.name = 'ss_parent1';
console.log(s1.name);//ss_parent1
console.log(s2.name);//parent1
使用原型链实现对原型属性和方法的继承,通过构造函数老实现实例属性的继承。这样即通过在原型上定义方法实现了函数复用,又能够保证每个实例有自己的属性;
4、es6的class继承
ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
参考:
https://blog.csdn.net/wenwen_king/article/details/80628444
call和apply的区别
改变this指向
当需要传递参数时,call可以直接写多个参数,apply需要用数组方式传递:
websoket与http区别
参考:https://www.cnblogs.com/aspirant/p/11334957.html
创建对象有几种方法
1、对象字面量表示
var person = {name: 'wangshuang',age:23}
2、new构造器
var person = new Object();
person.name = 'wangshuang';
person.age = 23;
3、构造函数
var M = function(name) {this.name = name;}
var person = new M('wangshuang');
4、Object.creat方法
var person = {name: 'wangshuang',age:23}
Object.creat(person);
原型链参考:
https://zhuanlan.zhihu.com/p/35790971
ajax工作原理及优缺点
工作原理:在用户和服务器之间加了一个中间层,使用户操作与服务器响应异步化。并不是所有请求都交给服务器,一些数据验证和数据处理交给ajax引擎处理,只有确定需要从服务器读取新数据才由ajax引擎代为向服务器发送请求
参考:https://www.cnblogs.com/yelp/p/3725664.html
找出一段字符串中出现最多的某个字符,统计次数
参考:https://blog.csdn.net/q95548854/article/details/78382900
判断js类型的方式
type of
可以判断出’string’,‘number’,‘boolean’,‘undefined’,‘symbol’
但判断 typeof(null) 时值为 ‘object’; 判断数组和对象时值均为 ‘object’
instance of
原理是 构造函数的 prototype 属性是否出现在对象的原型链中的任何位置
Array.isArray
用域检测数组
Object.prototype.toString.call()
常用于判断浏览器内置对象,对于所有基本的数据类型都能进行判断,即使是 null 和 undefined
构造函数与普通函数的区别
命名规则上:构造函数为首字母大写,普通函数没有这个要求
调用方式上:构造函数为new关键字调用,普通函数直接调用
this的指向:构造函数指向该构造函数的实例,普通函数为调用该函数的对象(如window)
参考:link.
ES6 的 class 和构造函数的区别
class实际就是语法糖,它的功能可以用es5的构造函数实现。构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
构造函数
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
class
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
闭包的概念,优缺点
闭包:能读取其他函数内部变量的函数
优点:避免全局变量的污染,希望一个变量长期存储在内存中
缺点:内存的消耗(泄露)
使用场景:封装变量,收敛权限
计数器解释闭包
var add = (function(){
var counter = 0;
return function(){
return(++counter);
}
})(); //这里add已经是执行过后的函数了。即add指定了函数自我调用的返回值
add(); //counter为1
add(); //counter为2
add(); //counter为3
参考:link.
经典案例:for循环加计时器,输出
···
for(var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
});
}
console.log(‘a’);
···
参考:link.
箭头函数与普通函数的区别
参考:link.