前端面试题总结

一、JavaScript:

1. setTimeOut准时吗?

不一定准时,他只是把时间到了放进时间队列里

2. JS快速打乱一个数组

先上代码
sort + Math.random()

var arr=[1,2,3,4,,5,6,7,8,9,10];
arr.sort(function(){
      return Math.random()-0.5
})

解析:
random( )方法返回一个0-1之间的随机数,用随机数减去 0.5,可以实现随机返回一个正负数字完成乱序了

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 throttle(fn, wait) {
  var pre = Date().now();
  return function () {
    var now = Date.now();
    if (now - prev >= wait) {
      fun.apply(this, arguments);
      pre = Date.now();
    }
  };
}

6. 防抖函数

/**
 * 动作绑定事件,
 * 动作发生后在一定时间内触发事件,
 * 在这段时间内,如果动作发生了,则重新等待一定时间在触发事件
 *
 * 原理:在每次函数执行前先清空上一次设置的定时器
 * */
function debounce(fn, wait) {
  var timer;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, wait);
  };
}

7. 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)));
            }
        }
    }

8. 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;
}

9. 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;
    }

10. 懒加载

    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))

11. 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)
        }
    }

12. 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)
  window[callback] = function(data) {
    console.log(data)
    document.removeChild(script)
  }
}

13. 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;
    }

14. JS发布订阅模式

vue.js是采用数据劫持结合发布者-订阅者的方式,通过object.defineProperty()来劫持各个属性的setter和getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图,
具体步骤:
第一步,我们首先需要给observer数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter,这样当我们给对象某个值赋值,会触发setter,那么就会监听到数据.
第二步:compile解析模板指令,将模板的所有变量转换为数据,然后初始化页面视图,将每个指令对应的节点绑定更新函数,添加监听订阅者,一但数据发生改变,收到通知,改变视图
第三步:watcher订阅者是observer和Complie之间通信的桥梁,主要做的有:
1.在自身实例化时往订阅器(dep)里添加自己
2.自身必须有一个updata方法
3.待属性变动dep.notice()通知时,能调用自身的update方法,并触发Complie中绑定的回调,完美退出
第四步:mvvm作为数据绑定的入口,整合observe,Comple和Watcher三者,observe,来监听自己的model数据变化,Comple来解析模板指令,Watcher用来搭起observe和Cmplie之间通信的桥梁
达到数据变化-视图更新,视图交互变化,数据model变更双向绑定效果

posted @ 2020-09-23 17:06  林9九  阅读(173)  评论(0编辑  收藏  举报