小言_互联网的博客

前端面试题总结

457人阅读  评论(0)

一、JavaScript:

1. setTimeOut准时吗? 不一定准时,只是时间到了放进时间队列里
2. JS打乱数组
 function getArrRandomly(arr) {
   
        var len = arr.length;
        for (var i = 0; i < len; i++) {
   
            var randomIndex = Math.floor(Math.random()*(len-i));//这里一定要注意,后面不管是(i+1)还是(len-i),它们是时变的。
            var itemAtIndex = arr[randomIndex];
            arr[randomIndex] = arr[i];
            arr[i] = itemAtIndex;
        }
        return arr;
    }
3. JS 预编译

js预编译实现过程:
1.创建GO/AO对象
2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
3.将实参值和形参统一
4.在函数体里面找函数声明,值赋予函数体

4. JS ajax
    //步骤一:创建异步对象
    var ajax = new XMLHttpRequest();
    //步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
    ajax.open('get','getStar.php?starName='+name);
    //步骤三:发送请求
    ajax.send();
    //步骤四:注册事件 onreadystatechange 状态改变就会调用
    ajax.onreadystatechange = function () {
   
    if (ajax.readyState==4 &&ajax.status==200) {
   
        //步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
        console.log(ajax.responseText);//输入相应的内容
      }
    }
    
5. 深拷贝
/**
 * 深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新
 * 的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数
 * 据,而不用担心数据之间会起冲突
 */
 function deepClone(obj) {
   
    if (typeof obj !== 'object') return obj;
    if (obj instanceof RegExp) {
   
        return new RegExp(obj);
    }
    if (obj instanceof Date) {
   
        return new Date(obj);
    }
    const result = Array.isArray(obj) ? [] : {
   };
    for(let key in obj) {
   
        if (obj.hasOwnProperty(key)) {
   
            result[key] = typeof obj[key] !== 'object' ? deepClone(obj[key]) :  obj[key]
        }
    }
    return result
}
const test = {
   name: '小米', age: 12, reg: /\d+s/, obj: {
   deep: 'test'}, fun: function() {
    console.log('test') }};
const newTest = deepClone(test);
test.age = 13;
// test输出 => {name: "小米", age: 13, reg: /\d+s/, obj: {…}, fun: ƒ}
// newTest输出 => {name: "小米", age: 12, reg: /\d+s/, obj: {…}, fun: ƒ}
6. 节流函数(常考点)
/**
 * 节流:动作绑定事件,动作发生后一段时间后触发事件,
 * 在这段时间内,如果动作有发生了,则无视该动作,直到时间执行完后,才能重新触发
 * 原理:在每次函数执行前先判断是否存在定时器,存在则跳过本次执行,否则设置定时器
 */
function throttle(fn, wait) {
   
  var pre = Date().now();
  return function () {
   
    var now = Date.now();
    if (now - prev >= wait) {
   
      fun.apply(this, arguments);
      pre = Date.now();
    }
  };
}
7. 防抖函数
/**
 * 动作绑定事件,
 * 动作发生后在一定时间内触发事件,
 * 在这段时间内,如果动作发生了,则重新等待一定时间在触发事件
 *
 * 原理:在每次函数执行前先清空上一次设置的定时器
 * */
function debounce(fn, wait) {
   
  var timer;
  return function () {
   
    if (timer) {
   
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
   
      fn.apply(this, arguments);
    }, wait);
  };
}
8. JS bind 实现
    if (!Function.prototype.bind) {
   
        Function.prototype.bind = function () {
   
            var self = this,                        // 保存原函数
            context = [].shift.call(arguments), // 保存需要绑定的this上下文
            args = [].slice.call(arguments);    // 剩余的参数转为数组
            return function () {
                       // 返回一个新函数
                self.apply(context,[].concat.call(args, [].slice.call(arguments)));
            }
        }
    }
9. JS map 实现
Array.prototype.map = function () {
   
  var arr = this, result = [];
  var [fn, thisValue] = Array.prototype.slice.call(arguments);
  for (var i = 0; i < arr.length; i++) {
   
    result.push(fn.call(thisValue, arr[i], i, arr))
  }
  return result;
}
10. IndexOf的实现
    function ArrayIndexOf(arr, value, n){
   
        var i = isNaN(n) ? 0 : n;//有第三参时
            i = (i < 0) ? arr.length + i : i;//第三参为负数时
        for(i; i < arr.length; i++){
   
            if(arr[i]===value){
    return i; }                   
        } return -1;
    }
11. 懒加载
    let lazyImages = [...document.querySelectorAll('.lazy-image')]
    let inAdvance = 300 // 自定义一个高度,当距离300px到达图片时加载
    function lazyLoad() {
   
        lazyImages.forEach(image => {
   
            if (image.offsetTop < window.innerHeight + window.pageYOffset + inAdvance) {
    // 距离xxpx时加载图片
                image.src = image.dataset.src
                image.onload = () => image.classList.add('loaded')
            }
        })
    }
    lazyLoad()
    window.addEventListener('scroll', _.throttle(lazyLoad, 16)) // 用到了lodash的节流函数
    window.addEventListener('resize', _.throttle(lazyLoad, 16))
12. JS实现promise
    class PromiseClone {
   
    constructor (process) {
   
        this.status = 'pending'
        this.msg = ''
        process(this.resolve.bind(this), this.reject.bind(this))
        return this
    }
    resolve (val) {
   
        this.status = 'fulfilled'
        this.msg = val
    }
    reject (err) {
   
        this.status = 'rejected'
        this.msg = err
    }
    then (fufilled, reject) {
   
        if(this.status === 'fulfilled') {
   
            fufilled(this.msg)
        }
        if(this.status === 'rejected') {
   
            reject(this.msg)
        }
    }
13. Jsonp跨域
  function Jsonp(url, param, callback) {
   
  var script = document.createElement('script')
  param = {
   ...param, callback}
  var arr = [];
  for(var key in param) {
   
    arr.push(`${
     key}=${
     param[key]}`)
  }
  script.src=`${
     url}?${
     arr.join('&')}`
  document.body.appendChild(script)
  callback = function(data) {
   
    console.log(data)
    document.removeChild(script)
  }
}
14. JS 获取url参数
    function getQueryString(name) {
    
    	var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); 
    	var r = window.location.search.substr(1).match(reg); 
    	if (r != null) return unescape(r[2]); return null; 
    }export function getQueryStringByStr(data) {
   
        const url = data; // 获取url中"?"符后的字串
        const theRequest = {
   };
        if (url.indexOf('?') !== -1) {
   
            const str = url.substr(1);
            const strs = str.split('&');
            for (let i = 0; i < strs.length; i += 1) {
   
            theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]);
            }
        }
        return theRequest;
    }
15. JS发布订阅模式
  1. JavaScript 发布订阅模式的理解
    const event = {
   
        clientList: [],
        listen: function(key , fn) {
   
            if (this.clientListen[key]) {
   
                this.clientList[key] = []
            }
            this.clientList[key].push(fn)
        },
        trigger: function() {
   
            const key = Array.prototype.shift.call(arguments)
            const fns = this.clientList[key]
            if (!fns || fns.length === 0 ) {
   
                return false
            }
            for (let i = 0, fn ;fn = fns[i++];) {
   
                fn.apply(this, arguments)
            }
        },
        remove : function(key , fn) {
   
            const fns = this.clientList[key]
            if (!fns) {
   
                return false
            }
            if (!fn) {
   
                fns && (fns.length = 0)
            } else {
   
                for (let l = fns.length - 1; l>=0; l--) {
   
                    const _fn = fns[l]
                    if ( _fn ===fn) {
   
                        fns.splice(l, 1)
                    }
                }
            }
    }
    const installEvent = (obj) => {
   
        for (let i in event) {
   
            obj[i] = event[i]
        }
    }   

二、Vue常考点:

  1. 谈谈你对 Vue 生命周期的理解?
  2. 组件中 data 为什么是一个函数?
  3. v-model 的原理?
  4. Vue 是如何实现数据双向绑定的?
  5. Vue 框架怎么实现对象和数组的监听?
  6. 能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?

三、React知识:

  1. React相关面试题
  2. React diff算法的初步认识
  3. setstate为什么是异步的?
  4. React-Router 实现与解析
  5. diff算法的初步了解
let result = [];
// 比较叶子节点
const diffLeafs = function (beforeLeaf, afterLeaf) {
   
    // 获取较大节点树的长度
    let count = Math.max(beforeLeaf.children.length, afterLeaf.children.length);
    // 循环遍历
    for (let i = 0; i < count; i++) {
   
        const beforeTag = beforeLeaf.children[i];
        const afterTag = afterLeaf.children[i];
        // 添加 afterTag 节点
        if (beforeTag === undefined) {
   
            result.push({
    type: "add", element: afterTag });
            // 删除 beforeTag 节点
        } else if (afterTag === undefined) {
   
            result.push({
    type: "remove", element: beforeTag });
            // 节点名改变时,删除 beforeTag 节点,添加 afterTag 节点
        } else if (beforeTag.tagName !== afterTag.tagName) {
   
            result.push({
    type: "remove", element: beforeTag });
            result.push({
    type: "add", element: afterTag });
            // 节点不变而内容改变时,改变节点
        } else if (beforeTag.innerHTML !== afterTag.innerHTML) {
   
            if (beforeTag.children.length === 0) {
   
                result.push({
   
                    type: "changed",
                    beforeElement: beforeTag,
                    afterElement: afterTag,
                    html: afterTag.innerHTML
                });
            } else {
   
                // 递归比较
                diffLeafs(beforeTag, afterTag);
            }
        }
    }
    return result;
}

四、vuex与redux对比

Vuex 的核心概念:
1. mutation(用于同步操作)
2. action(可用于异步操作,提交 mutation)
3. mutation里面直接修改 state
4. state(单一数据源)

Redux 的核心概念:
1.action (同步action ,或借助 中间件 实现异步操作,action 不会改变 store,只是描述了怎 么改变store)| mutation(用于同步操作)
2.action(可用于异步操作,提交 mutation)
3.reducer(纯函数,根据 action 和旧的 store 计算出新的 store
4.store(单一数据源)

VueX使用原则:
a. 应用层级的状态应该集中到单个 store 对象中。
b. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
c. 异步逻辑都应该封装到 action 里面。

Redux使用原则:
a.单一数据源(一个Redux应用只有一个store),也是单向的数据流;
b.state只读(唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。);
c.使用纯函数(reducer)来修改state。

五、网络篇

1. 对称加密和非对称加密

get请求 对称加密和非对称加密区别:
1.对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥加密也就是密钥也可以用作解密密钥,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了数据加密标准(DES),另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,而且对计算机功能要求也没有那么高与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
2.非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。

2. https和http的区别

HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。HTTP与HTTPS的区别 - 爱笑的蛙蛙 - 博客园

3. https的握手过程
  1. 首先客户端发起请求到服务端,服务端处理后发送一个公钥给客户端
  2. 客户端进行验证公钥,看公钥是否有效和是否过期
  3. 客户端验证通过会产生随机值key,然后用公钥进行加密回传给服务端
  4. 服务端用私钥解密后获得客户端的随机值key
  5. 利用随机值key加密数据后传输给客户端
  6. 客户端利用key值进行解密数据
  7. 客户端获取真正的数据
4. https的缺点

虽然说HTTPS有很大的优势,但其相对来说,还是存在不足之处的:
(1)HTTPS协议握手阶段比较费时,会使页面的加载时间延长近50%,增加10%到20%的耗电;
(2)HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
(3)SSL证书需要钱,功能越强大的证书费用越高,个人网站、小网站没有必要一般不会用。
(4)SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
(5)HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可行。

5. http option的作用

简而言之,OPTIONS请求方法的主要用途有两个:
1、获取服务器支持的HTTP请求方法;
2、用来检查服务器的性能。
3、其实在正式跨域之前,浏览器会根据需要发起一次预检(也就是option请求),用来让服务端返回允许的方法(如get、post),被跨域访问的Origin(来源或者域),还有是否需要Credentials(认证信息)等。

6. 强缓存和协商缓存的缓存,是从哪里拿的?http缓存

7. TCP与UDP的区别

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

8. http2.0 HTTP 2.0与HTTP 1.1区别 - FrankYou - 博客园

六、算法

1. 选择排序
    function selectionSort(arr) {
   
        var len = arr.length;
        var minIndex, temp;
        for (var i = 0; i < len - 1; i++) {
   
            minIndex = i;
            for (var j = i + 1; j < len; j++) {
   
                if (arr[j] < arr[minIndex]) {
        //寻找最小的数
                    minIndex = j;                 //将最小数的索引保存
                }
            }
            temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
        return arr;
    }
2. 二分查找算法
    function binarySearch(data,item,start,end){
   
        var end=end || data.length-1;
        var start=start || 0;
        var m=Math.floor(start + (end - start) / 2); // 防止查找溢出
        if(item === data[m]){
   
            return m;
        }else if(item<data[m]){
   
            return binarySearch(data,item,start,m-1) //递归调用
        }else{
   
            return binarySearch(data,item,m+1,end);
        }
        return false;
    }
3. 快速排序
    function quickSort(arr){
   
    if(arr.length==0){
   
        return arr
    }
    var pirotIndex=Math.floor(arr.length/2)
    var pirot = arr.splice(pirotIndex,1)[0]
    var left=[],right=[]
    for(var i=0;i<arr.length;i++){
   
        if(arr[i]>pirot){
   
            right.push(arr[i])
        }else{
   
            left.push(arr[i])
        }
    }
    return quickSort(left).concat(pirot,quickSort(right))
}
console.log(quickSort([2,4,6,1,7,8,4,9,99,6]))
4. 归并算法
    function merge(left, right) {
   
      var tmp = [];
    
      while (left.length && right.length) {
   
        if (left[0] < right[0])
          tmp.push(left.shift());
        else
          tmp.push(right.shift());
      }
    
      return tmp.concat(left, right);
    }
    
    function mergeSort(a) {
   
      if (a.length === 1) 
        return a;
    
      var mid = ~~(a.length / 2)
        , left = a.slice(0, mid)
        , right = a.slice(mid);
    
      return merge(mergeSort(left), mergeSort(right));
    }
5. 回文算法
    function palindrome(str) {
   
    	var newstr = str.replace(/[^0-9a-z]/gi, ""); 
    	newstr = newstr.toLowerCase();
    	for (var i = 0, j = newstr.length - 1; i < j; i++, j--) {
    
    	    if (newstr.charAt(i) !== newstr.charAt(j)) 
    	    {
    
    	        return false; //逐个字符比较,不匹配返回false
    	    } 
    	} 
    	return true;
    }

六、面经:


转载:https://blog.csdn.net/weixin_43624724/article/details/86519903
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场