一、js面试题
- JavaScript 中的 this 究竟指向谁,箭头函数的 this 有什么不同
- 普通函数
this 永远指向调用它的对象,new的时候,指向new出来的对象。 - 箭头函数
箭头函数没有自己的 this,当在内部使用了 this时,它会指向最近一层作用域内的 this
- 深拷贝和浅拷贝的区别?如何实现?
两者的区别:一个对象浅复制后,是深层次的对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会发生改变,而深复制的则是开辟了一个新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
JSON.stringify与JSON.parse可以实现深拷贝,还可以借用JQ的extend方法。
- 1.可以递归递归去复制所有层级属性
// 原始对象
var obj = {
a:1,
arr: [2,3],
say:function(){
console.log('hello')
},
obj1:{
arr:[34,55,5],
hand:function(){
console.log('hand')
},
obj3:{
a:1,
take:function(){
console.log('take')
}
}
}
};
// 开始浅复制
var shallowObj = shallowCopy(obj);
// 定义浅复制逻辑
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
// 改变复制后的新对象的属性值(第二层以及更深层次)
shallowObj.obj1.obj3.take = function(){
console.log('shallowObj_take')
}
shallowObj.obj1.hand = function(){
console.log('shallowObj_hand')
}
// 打印新对象的方法调用
shallowObj.obj1.obj3.take(); // shallowObj_take
shallowObj.obj1.hand(); // shallowObj_hand
// 打印原对象的方法调用
obj.obj1.obj3.take(); // shallowObj_take
obj.obj1.hand(); // shallowObj_hand
问题出现了:原对象的方法被新对象的修改,而产生变化。
原因是复制的是对象的地址指针,两个属性共同指向一个对象,只要其一发生变化,另一个也随之变化
- JSON.stringify与JSON.parse实现深拷贝
function deepClone(obj){
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
let a=[0,1,[2,3],4],
b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
- JQ的extend方法
let a=[0,1,[2,3],4],
b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
- js的事件委托是什么,原理是什么?
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。用事件委托就可以只用一次dom操作就能完成所有的效果。 - 如何判断一个变量是否为数组(isArray)
1、instanceof
function isArray (obj) {
return obj instanceof Array;
}
2、Array对象的 isArray方法
function isArray (obj) {
return Array.isArray(obj);
}
3、Object.prototype.toString
function isArray (obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
-
'DOM2级事件'规定的事件流包含3个阶段:事件捕获,处于目标,事件冒泡
阻止事件冒泡:event.stopPropagation()
阻止默认行为:e.preventDefault()
-
回调地狱和回调函数
回调地狱(函数作为参数层层嵌套)
回调函数(一个函数作为参数需要依赖另一个函数执行调用) -
数组的基本方法
push和unshift,返回值是length
pop和shift,返回值是删除的当前项
slice:抽取当前数组中的一段元素组合成一个新数组。第一个参数从哪里开始,第二个参数是到哪结束
数组splice第一个参数是索引,第二个参数是想修改或者删除几个元素,第三个是添加的内容
split把字符串分割成数组
Array.prototype.includes()
:判断数组中是否包含某指定的值 -
数组去重的方法
- es6方法:[...new Set(arr)]或者Array.from(new Set(arr))
forEach + indexOf res.indexOf(val)=== -1,该方法不足之处是NaN进行过滤,改善的方法是使用includes方法 - filter+indexOf
- forEach + includes
- reduce + includes
- 嵌套循环+splice
- hash+hasOwnProperty+JSON.stringify
- 判断一个变量是不是数组的可靠的方法:
Object.prototype.toString.call(list) //[object Array]
Array.isArray(list) //true
-
typeof和instanceof的区别
typeof返回的类型都是字符串形式
instanceof,后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。 -
call & apply & bind() 之间的区别:
call和apply都是改变this指向的方法,区别在于call可以写多个参数,而apply只能写两个参数,第二个参数是一个数组,用于存放要传的参数。
bind()返回的是一个新函数,必须调用它才会执行 -
基本数据类型
(ES6之前)其中5种为基本类型:string,number,boolean,null,undefined,
ES6出来的Symbol也是原始数据类型 ,表示独一无二的值
基本类型的存储方式都是栈存储,引用类型的存储方式都是堆存储 -
栈和队列的区别?
栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。
队列先进先出,栈先进后出。
栈只允许在表尾一端进行插入和删除,而队列只允许在表尾一端进行插入,在表头一端进行删除 -
对闭包的理解
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
闭包有三个特性:
1.函数嵌套函数
2.函数内部可以引用外部的参数和变量
3.参数和变量不会被垃圾回收机制回收 -
跨域的解决方案
- jsonp 只能解决get跨域
原理:动态创建一个script标签。利用script标签的src属性不受同源策略限制。因为所有的src属性和href属性都不受同源策略限制。可以请求第三方服务器数据内容。
步骤:
去创建一个script标签
script的src属性设置接口地址
接口参数,必须要带一个自定义函数名 要不然后台无法返回数据。
通过定义函数名去接收后台返回数据
//去创建一个script标签
var script = document.createElement("script");
//script的src属性设置接口地址 并带一个callback回调函数名称
script.src = "http://127.0.0.1:8888/index.php?callback=jsonpCallback";
//插入到页面
document.head.appendChild(script);
//通过定义函数名去接收后台返回数据
function jsonpCallback(data){
//注意 jsonp返回的数据是json对象可以直接使用
//ajax 取得数据是json字符串需要转换成json对象才可以使用。
}
- CORS:跨域资源共享
原理:服务器设置Access-Control-Allow-OriginHTTP
响应头之后,浏览器将会允许跨域请求
限制:浏览器需要支持HTML5,可以支持POST,PUT等方法兼容ie9以上
需要后台设置
Access-Control-Allow-Origin: * //允许所有域名访问,或者 Access-Control-Allow-Origin: http://a.com //只允许所有域名访问
二、vue面试题
- router 的区别
- router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象,经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。
- route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等。
- Vue的双向数据绑定原理是什么?
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。 - <keep-alive></keep-alive>的作用是什么?
<keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
网友评论