前端js基础面试题目

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

参考:
link.
link.

构造函数与普通函数的区别

命名规则上:构造函数为首字母大写,普通函数没有这个要求
调用方式上:构造函数为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 + ')';
  }
}

参考:link.
link.

闭包的概念,优缺点

闭包:能读取其他函数内部变量的函数
优点:避免全局变量的污染,希望一个变量长期存储在内存中
缺点:内存的消耗(泄露)
使用场景:封装变量,收敛权限
计数器解释闭包

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.
let和var的区别

箭头函数与普通函数的区别

参考:link.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值