前端面试题总结(有解答)

302 阅读2分钟

最近在找工作,总结一些面试题和解答,如解答有误或不完善还请各位评论区指正补充,谢谢!

1. 对象的深拷贝

方法一:使用JSON.parseJSON.stringify

let targetObject = JSON.parse(JSON.stringify(source))
// 该方法简便,但是不能识别undefined,symbol和function(){}

方法二:遍历+递归

function deepCopy(source) {
    if(!source) return source // 兼容null,undefined
    let targetObject = source.constructor === Array ? [] : {}
    for (let key in source) {
        if(source.hasOwnProperty(key)) { // 是自有非继承属性
            if(source[key] && typeof(source[key]) === 'object') { //是对象需要递归,typeof [] 也等于object
                targetObject[key] = source[key].constructor === Array ? [] : {}
                targetObject[key] = deepCopy(source[key])
            } else {  //非对象直接赋值
                targetObject[key] = source[key]
            }
        }
    }
    return targetObject
}

2. 原生ajax请求

function ajax(){
    // 五步走 param为传入的参数对象
    // 第一步 创建异步对象
    var xhr;
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest()  // ie7以上
    } else {
      xhr = new ActiveXObject() // // ie7以下
    }
    
    // 第二步 设置请求方法
    if (param.type.toLowerCase() === 'get') { // get请求
      xhr.open(param.type, param.url + '?' + formatParams(param.data), true)
    } else if (param.type.toLowerCase() === 'post') { // post请求
      xhr.open(param.type, param.url, true) // true为异步,false为同步
    }
    
    // 第三步 设置请求头 (get和post设置请求头时有区别吗?)
    xhr.setRequestHeader("content-type", "application/x-www-form-urlencode")
    
    // 第四步 发送请求
    if (param.type.toLowerCase() === 'get') { // get请求
      xhr.send(null)
    } else if (param.type.toLowerCase() === 'post') { // post请求
      xhr.send(JSON.stringify(param.data))
    }
    
    // 第五步 让异步对象接受服务器的响应数据
    xhr.onreadystatechange = function () {
      // 0 未初始化未调用open
      // 1.启动 调用open 未调用 send
      // 2. 发送 已调用send() 但是未响应
      // 3. 接收 已经接收部分响应数据
      // 4.完成  完成全部数据响应
      /** 
       *status 状态说明
       * 200 服务器成功返回页面
       * 400 语法错误 服务器不识别
       * 401 请求需要用户认证
       * 404 知道url 服务器找不到
       * 500 服务器错误 无法完成请求
       * 
       */
      if (xhr.readyState == 4) {
        if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
          param.success && param.success(xhr.responseText)
        } else {
          param.error && param.error()
        }
      }
    }
 
     // 格式化参数
    function formatParams(data) {
      if (!data) return
      var arr = []
      for (var i in data) {
        arr.push(`${encodeURIComponent(name)}=${encodeURIComponent(data[i])}`)
      }
      return arr.join('&')
    }
}

3. 防抖和节流

// 防抖
function debounce(fn) {
    let timeout = null
    return function() {
        clearTimeout(timeout)
        timeout = setTimeout( () => {
            fn.apply(this, arguments)
        }, 500)
    };
}
// 节流
function throttle(fn) {
    let canRun = true
    return function() {
        if(!canRun) return
        canRun = false
        setTimeout( () => {
            fn.apply(this, argument)
            this.canRun = true
        }, 500)
    }
}

4. 两个事件循环题目

// (一)
console.log(1)

setTimeout(() => {
    console.log(2)
    new Promise(resolve => {
        console.log(4)
        resolve()
    }).then(() => {
        console.log(5)
    })
})

new Promise(resolve => {
    console.log(7)
    resolve()
}).then(() => {
    console.log(8)
})

setTimeout(() => {
    console.log(9)
    new Promise(resolve => {
        console.log(11)
        resolve()
    }).then(() => {
        console.log(12)
    })
})

// (二)
async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}
async function async2() {
  console.log('async2');
}

console.log('script start');

setTimeout(function () {
  console.log('setTimeout');
}, 0)

async1();

new Promise(function (resolve) {
  console.log('promise1');
  resolve();
}).then(function () {
  console.log('promise2');
});
console.log('script end');

5. 浏览器渲染引擎和JS引擎

6. web安全

  • 跨站脚本攻击
    - input "<script></script>"  ---> 将输入字符"<"转义,过滤
    - 减少使用JSONP进行跨域请求
    
  • 跨站请求伪造
    弹窗,图片,被攻击者带上cookie冒充身份进行攻击操作
    - 检测http referer 是否同域名
    - token
    - session的时效性
    
  • http劫持
    使用https加密
    
  • get/post请求
    - get在url后面带上传值,敏感信息要注意,可用post代替
    - get请求会被浏览器缓存
    
  1. 跨域JSONP