手牵手系列之总结面试题

前言

最近正在找工作,将面试官的提问记录一下。吐槽南京外包公司太多!!!我们注定要被外包的命运!!!

开始

  • 合并对象 
// 用 Object.assign(); 
<script>
 var obj1 = {name:'小A',sex:'女'};
 var obj2 = {age:'30',job:'程序猿'};

 Object.assign(obj1,obj2);

 console.log(obj1);
</script>

========================================

//使用JQuery的extend方法
o3 = $.extend(o1, o2)  // 合并 o1 和 o2, 将结果返回给 o3. 注意: 此时,o1 == o3! 即 o1 被修改
// 或
o3 = $.extend({}, o1, o2) // 合并 o1 和 o2, 将结果返回给 o3. 注意: 此时,o1 != o3! 即 o1 没有被修改

========================================

//遍历赋值法
var extend=function(o,n){
   for (var p in n){
        if(n.hasOwnProperty(p) && (!o.hasOwnProperty(p) ))
            o[p]=n[p];
    }
}; 
  •  数组遍历
// 1.for循环
使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显。
for(j = 0,len=arr.length; j < len; j++) {}

===================================================

//2.foreach循环
遍历数组中的每一项,没有返回值,对原数组没有影响,不支持IE

//没有返回值
arr.forEach((item,index,array)=>{
    //执行代码
})
//参数:value数组中的当前项, index当前项的索引, array原始数组;
//数组中有几项,那么传递进去的匿名回调函数就需要执行几次;

===================================================

//3.map循环
有返回值,可以return出来

map的回调函数中支持return返回值;return的是啥,相当于把数组中的这一项变为啥(并不影响原来的数组,只是相当于把原数组克隆一份,把克隆的这一份的数组中的对应项改变了);
var ary = [12,23,24,42,1]; 
var res = ary.map(function (item,index,ary ) { 
    return item*10; 
}) 
console.log(res);//-->[120,230,240,420,10];  原数组拷贝了一份,并进行了修改
console.log(ary);//-->[12,23,24,42,1];  原数组并未发生变化

===================================================

//4.for...of遍历
可以正确响应break、continue和return语句

for (var value of myArray) {
console.log(value);
}

===================================================

//5.filter遍历
不会改变原始数组,返回新数组

var arr = [
  { id: 1, text: 'aa', done: true },
  { id: 2, text: 'bb', done: false }
]
console.log(arr.filter(item => item.done))

===================================================

//6.every遍历
every()是对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true。

var arr = [ 1, 2, 3, 4, 5, 6 ]; 
console.log( arr.every( function( item, index, array ){ 
        return item > 3; 
    })); 

===================================================

//7.some遍历
some()是对数组中每一项运行指定函数,如果该函数对任一项返回true,则返回true。

var arr = [ 1, 2, 3, 4, 5, 6 ]; 
   console.log( arr.some( function( item, index, array ){ 
        return item > 3; 
})); 

===================================================

//8.reduce
reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。

var total = [0,1,2,3,4].reduce((a, b)=>a + b); //10

reduce接受一个函数,函数有四个参数,分别是:上一次的值,当前值,当前值的索引,数组
[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array){
 return previousValue + currentValue;
});

===================================================

//9.reduceRight
reduceRight()方法的功能和reduce()功能是一样的,不同的是reduceRight()从数组的末尾向前将数组中的数组项做累加。

var arr = [0,1,2,3,4];
 
arr.reduceRight(function (preValue,curValue,index,array) {
    return preValue + curValue;
}); // 10

===================================================

//10.find
find()方法返回数组中符合测试函数条件的第一个元素。否则返回undefined 
stu.find((element) => (element.name == '李四'))

===================================================

//11.findIndex
对于数组中的每个元素,findIndex 方法都会调用一次回调函数(采用升序索引顺序),直到有元素返回 true。只要有一个元素返回 true,findIndex 立即返回该返回 true 的元素的索引值。如果数组中没有任何元素返回 true,则 findIndex 返回 -1。

findIndex 不会改变数组对象。
[1,2,3].findIndex(function(x) { x == 2; });

===================================================

//12.keys,values,entries
 ES6 提供三个新的方法 —— entries(),keys()和values() —— 用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历

for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
  • 浅拷贝与深拷贝
// 浅拷贝

function simpleCopy(){
    var obj2 = Array.isArray(obj1)?[]:{};
    for(let i in obj1){
        obj2[i] = obj1[i]
    }
    return obj2  
}

var obj1 = {
   a: 1,
   b: 2,
   c: {
         d: 3
      }
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4

=================================================

var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3



//深拷贝
1、通过JSON对象来实现深拷贝
function deepClone2(obj) {
  var _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
  return objClone;
}

=================================================

2、采用递归去拷贝所有层级属性
function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);
  •  父组件调用子组件方法
// 父组件
<template>
  <div @click="fatherMethod">
    <child ref="child"></child>
  </div>
</template>
<script>
  import child from '~/components/dam/child.vue';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod() {this.$refs.child.childMethods();
      }
    }
  };
</script>

=============================================

// 子组件
<template>
  <div>{{name}}</div>
</template>
<script>
  export default {
    data() {
      return {
        name: '测试'
      };
    },
    methods: {
      childMethods() {
        console.log(this.name);
      }
    }
  };
</script>

在父组件中, this.$refs.child 返回的是一个vue实例,可以直接调用这个实例的方法
  • let、var、const的区别
var 没有块级作用域,支持变量提升。
let 有块级作用域,不支持变量提升。不允许重复声明,暂存性死区。不能通过window.变量名进行访问.
const 有块级作用域,不支持变量提升,不允许重复声明,暂存性死区。声明一个变量一旦声明就不能改变,改变报错。
  •  谈谈原型、原型链、继承
原型链:每个被实例对象都有__proto__对象,它指向了构造该对象的构造函数的prototype属性。、
同时该对象可以通过__proto__对象来寻找不属于自身的属性,
原型:就是实现继承过程中产生的一个概念。
继承:复制父类的属性和方法来重写子类的原型对象

原型继承
构造函数继承
组合继承
寄生继承
寄生组合继承
class
等等
  •  闭包
闭包就是有权访问一个函数内部变量的函数,也就是常说的函数内部嵌套函数,
内部函数访问外部函数变量,从而导致垃圾回收机制没有将当前变量回收掉。
这样的操作,有可能会带来内存泄漏。好处就是可以设计私有的方法和变量。
  •  简述深浅拷贝
浅拷贝
通常需要拷贝的对象内部只有一层的这种对象。
常用的方法

Object.assign方法来实现
扩展运算符 ...obj
深拷贝
通常是嵌套二层或以上的复杂对象
常用方法

JSON.parse(JSON.stringfy(object)); 该方法忽略掉undefined、忽略Symbol、忽略function。只适合简单深拷贝
手写递归方法去实现。
通过第三方库提供的深拷贝实现。
  • 函数的节流和防抖
防抖函数:将多次触发变成最后一次触发;
function debounce(fn,wait){
  let timer = null;
  return function (){
    let arg = arguments;
    if(timer){
      clearTimeout(timer);
      timer = null;
    }
    timer = setTimeout(()=>{
       fn.apply(this,arg)
    },wait)
  }
}
function clg(){
  console.log('clg')
}
window.addEventListener('resize',debounce(clg,1000))


节流函数:将多次执行变成每隔一个时间节点去执行的函数
function throttle(fn,time){
  let lastTime = null;
  return function(){
    let nowTime = Date.now();
    if(nowTime - lastTime > time || !lastTime){
      fn();
      last = nowTime
    }
  }
}
function sayHi(){
  console.log('hi')
}
setInterval(throttle(sayHi,1000),500)
  • call、apply、bind区别
相同点:都是重定向this指针的方法。
不同点:call和apply的第二个参数不相同,call是若干个参数的列表。apply是一个数组

bind方法是直接返回一个新的函数,需要手动去调用才能执行。

  •  js跨域如何解决
目前暂时已知的跨域方法是:

jsonp跨域,原理:script标签没有跨域限制的漏洞实现的一种跨域方法,只支持get请求。安全问题会受到威胁。
cors跨域,通过后端服务器实现,Access-Control-Allow-Origin。
postMessage window的一个属性方法。
websocket
nginx反向代理
iframe跨域
  •  简述cookie、localstorage、seesionstorage
名称大小网络请求生命周期
cookie4kb左右每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题默认是关闭浏览器后失效, 但是也可以设置过期时间
localstorage5M仅在浏览器中保存,不参与和服务器的通信除非手动被清除,否则永久保存
SessionStorage5M仅在浏览器中保存,不参与和服务器的通信仅在当前会话(窗口)下有效,关闭窗口或浏览器后被清除, 不能设置过期时间
  • proxy和defineProperty区别
Object.defineProperty缺点:

无法监控数组下标的变化,导致直接通过数组的下标给数组设置值。不能事实响应。vue内部通过数组的一些方法来监听。
只能劫持对象的属性,因此要对每个对象的属性进行遍历。 vue2.x版本之后是通过递归和遍历实现对data对象的数据监控。
proxy:

可以劫持整个对象,并返回一个新的对象
有多种劫持操作
  • react与vue的区别
1、vue使用的是template模版编写。react使用的是jsx语法。
2、状态管理:react中的状态全部存入state中,通常修改的时候需要用到setState方法来更新状态。
 vue中的3、state对象不是必须,vue是通过data属性在vue对象中进行管理
4、监听数据的变化,vue劫持一些函数,能精确的知道数据变化。
react中默认是通过比较引用的方式去进行,如果不优化使用
shouldComponentUpdate/PureComponent方法优化,那会导致大量的虚拟dom重新渲染
5、数据流不同:vue可以进行组件与dom之间v-modle双向绑定。react从始至终都只有单向数据流
vue中使用的是mixins。react使用的是Hoc高阶组件
  • link和import区别
linkimport
页面被加载,link会同时被加载@import引用的css会等到页面被加载完成之后再加载。
只适用与2.1之后的版本link是没有任何兼容问题的。
支持使用js去控制dom改变样式不支持
 只能加载css
  • get和post请求的区别
getpost
参数长度有限制参数长度无限制
get会把请求的数据附加在url上post请求会把数据附加在请求体中
get是明文传输post不是明文传输
请求能缓存不能缓存
  • http和https区别
httphttps
80端口443端口
无需申请证书需要申请证书
超文本传输协议ssl加密协议
慢(因为会有一个ssl包需要传输)
  • setState同步和异步
setState只是在合成事件和生命周期函数中是异步更新
在settimeout、原生事件、async函数中是同步更新。
  • react请求与生命周期
react的异步请求,放入componentDidMount中才是正确操作。
因为WillMount中请求发送,react的执行机制是不会等到数据返回之后才继续往下执行,
而是继续向下执行并render。不会‘暂停’以等待数据到达。

问题:服务器渲染时,如果在WillMount中请求数据,fetch data会执行两次,
一次在服务端一次在客户端。造成了多余的请求,而且在16版本之后,WillMount可能在一次渲染中多次调用。
  •  vue组件通信
父传子:父组件通过props的方式传递。
子传父:props+回调函数方式。
兄弟组件:找到这两个共同的父节点,结合props和回调函数进行通信
跨层级通信:context通信
store
  •  React的渲染原理
单项数据流,只能通过数据层的变化去影响视图层变化。
数据驱动视图。无需关注dom,只用关注数据即可
渲染过程,生命周期函数
diff算法。对照两次dom不同的部分渲染
  • 性能优化方法
// 性能优化方法

dns预解析
浏览器缓存,强缓存和协商缓存
预加载 将一些不影响首屏但重要的文件延后加载 preload
预渲染 prerender
懒加载
文件优化
webpack优化 使用到tree shaking。各种loader等等
  • 几个es6的新增方法
1、声明命令let和const
2、模板字符串(Template String)
3、函数的扩展
4、对象的扩展 
5、for...of  循环
6、import和export
7、Promise对象(Promise是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,
避免了层层嵌套的回调函数。)
8、解构赋值
9、set数据结构
10、箭头函数
11、class
  • 常见的HTTP相应状态码
200:请求被正常处理
204:请求被受理但没有资源可以返回
206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中通过Content-Range指定范围的资源。
301:永久性重定向
302:临时重定向
303:与302状态码有相似功能,只是它希望客户端在请求一个URI的时候,能通过GET方法重定向到另一个URI上
304:发送附带条件的请求时,条件不满足时返回,与重定向无关
307:临时重定向,与302类似,只是强制要求使用POST方法
400:请求报文语法有误,服务器无法识别
401:请求需要认证
403:请求的对应资源禁止被访问
404:服务器无法找到对应资源
500:服务器内部错误
503:服务器正忙
  • 一次完整的HTTP请求所经历的7个步骤
1、建立TCP连接
2、Web浏览器向Web服务器发送请求行
3、Web浏览器发送请求头
4、Web服务器应答
5、Web服务器发送应答头
6、Web服务器向浏览器发送数据
7、Web服务器关闭TCP连接
  •  常用的HTTP方法有哪些?
GET: 用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器
POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式。
PUT: 传输文件,报文主体中包含文件内容,保存到对应URI位置。
HEAD: 获得报文首部,与GET方法类似,只是不返回报文主体,一般用于验证URI是否有效。
DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件。
OPTIONS:查询相应URI支持的HTTP方法。
  •  如何产生跨域
由于浏览器的 同源策略,在出现 域名、端口、协议有一种不一致时,
就会出现跨域,属于浏览器的一种安全限制。
  • 提升页面性能优化的常见方式
1、资源压缩合并,减少http请求

2、非核心代码异步加载 --> 异步加载的方式 --> 异步加载的区别

3、利用浏览器缓存 --> 缓存的分类 --> 缓存的原理

4、使用CDN

5、DNS预解析
  • 首页白屏优化以及解决方案

1、css文件加载需要一些时间,在加载的过程中页面是空白的。 解决:可以考虑将css代码前置和内联。

2、首屏无实际的数据内容,等待异步加载数据再渲染页面导致白屏。 解决:在首屏直接同步渲染html,
后续的滚屏等再采用异步请求数据和渲染html。

3、首屏内联js的执行会阻塞页面的渲染。 解决:尽量不在首屏html代码中放置内联脚本。(来自翔歌)

解决方案

根本原因是客户端渲染的无力,因此最简单的方法是在服务器端,使用模板引擎渲染所有页面。同时

1减少文件加载体积,如html压缩,js压缩

2加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西

3提供一些友好的交互,比如提供一些假的滚动条

4使用本地存储处理静态文件。
  •  vue等单页面应用及其优缺点
优点:
1、具有桌面应用的即时性、网站的可移植性和可访问性。
2、用户体验好、快,内容的改变不需要重新加载整个页面。
3、基于上面一点,SPA相对对服务器压力小。
4、良好的前后端分离。SPA和RESTful架构一起使用,后端不再负责模板渲染、输出页面工作,
web前端和各种移动终端地位对等,后端API通用化。
5、同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端;


缺点:
1、不利于SEO。(如果你看中SEO,那就不应该在页面上使用JavaScript,你应该使用网站而不是Web应用)
2、初次加载耗时相对增多。
3、导航不可用,如果一定要导航需要自行实现前进、后退。
  • vue prop不同数据类型设置默认值
refAge: {
type: Number,
default: 0
},
refName: {
type: String,
default: ''
},
hotDataLoading: {
type: Boolean,
default: false
},
hotData: {
type: Array,
default: () => {
return []
}
},
getParams: {
type: Function,
default: () => () => {}
},
meta: {
type: Object,
default: () => ({})
}
  •  怎么定义vue-router的动态路由?怎么获取传过来的动态参数? 
在router目录下的index.js文件中,对path属性加上/:id。  使用router对象的params.id 例如 :  this.$route.params.id;
  •  vue-router是什么?它有哪些组件?
vue用来写路由一个插件。router-link、router-view
  •  js 截取文件名和后缀
var str ='http://p1.ifengimg.com/fck/2017_21/2c1b05acd3d0b73_w600_h344.jpg';

str.substring(str.lastIndexOf('/')+1);  //2c1b05acd3d0b73_w600_h344.jpg

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值