我是靠谱客的博主 腼腆宝贝,最近开发中收集的这篇文章主要介绍面试题总结 - 函数 深拷贝 驼峰转换阿里巴巴前端面试分享-社招(p6),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1  JSON key 驼峰转换

实现一个转换函数covert,将JSON对象的下划线keys({a_jh_dhs: 99})转化为驼峰形式 {aIhDhs: 99}

function getCase(obj) {
  const reg = /_([a-z])/g
  function keyToCase(str) {
    if(typeof str !== 'string') return ''
    return str.replace(reg, (match, $) => {
      return $.toUpperCase()
    })
  }
  // []和{} 不包含null
  const isObject =  (obj) => typeof obj === 'object' && obj;
  // []
  const isArray = (arr) => Array.isArray(arr);
  // {}
  const isPlainObj = (obj) => isObject(obj) && !isArray(obj);


  function _getCase(obj) {
    if(!isObject(obj)) return null;

    if(isArray(obj)) {
      return obj.reduce((curr, next) => {
         curr.push(_getCase(next));
         return curr;
      },[])
    }

    let result = {};
    for(let key in obj) {
      const value = obj[key];
      const caseKey = keyToCase(key);
      if(isObject(value)) {
        result[caseKey] = _getCase(value);
        return result;
      }
      result[caseKey] = value
    }

    return result;
  }

  return _getCase(obj);
}
// { a_b_c: 8 }

function getCarse(str) {
  if(typeof str !== 'string') {
    return ''
  }
  const reg = /_+([a-zA-Z])/g
  return str.replace(reg, function(_, $1) {
    return $1.toUpperCase()
  })

}

function isObj(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]'
}

function covert(obj) {
  if(!obj || !isObj(obj)) return {};
  function _cover(obj) {
    const result = {};
    let _key, _value;
    for(let key in obj) {
      _key = getCarse(key);
      _value = obj[key];
      if(isObj(_value)) {
        result[_key] = _cover(_value);
      } else {
        result[_key] = _value;
      }
    }
    return result;
  }
  return _cover(obj);
}
const obj = {
  'a_d_F_df': 1,
  "cc__sd_dddd_s": {
    'a_D_Fds_d': 2
  }
}
const res = covert(obj);
console.log(res); // { aDFDf: 1, ccSdDdddS: { aDFdsD: 2 } }

2 数组转数

var arr3 = [
  {
    menuId: 1,
    name: '系统管理1',
    parentMenu: null
  },
  {
    menuId: 2,
    name: '系统管理2',
    parentMenu: null
  },
  {
    menuId: 3,
    name: '系统管理1_0',
    parentMenu: 1
  },
  {
    menuId: 4,
    name: '系统管理1_1',
    parentMenu: 1
  },
  {
    menuId: 5,
    name: '系统管理2_0',
    parentMenu: 2
  },
  {
    menuId: 6,
    name: '系统管理5_0',
    parentMenu: 5
  },
  {
    menuId: 7,
    name: '系统管理3',
    parentMenu: null
  }
]
function arrToTree(list) {
  if(!Array.isArray(list)) return {};
  const parentList = list.filter((i) => !i.parentMenu );
  const childList = list.filter((i) => i.parentMenu );
  function _arrToTree(parentList, childList) {
    parentList.forEach((parentI) => {
      childList.forEach((childI) => {
        if(!parentI.children) {
          parentI.children = []
        }
        if(parentI.menuId === childI.parentMenu) {
          parentI.children.push(childI);
        }
        
      })
      if(parentI.children && parentI.children.length) {
        _arrToTree(parentI.children, childList)
      }
    })
  }
  _arrToTree(parentList, childList);
  console.dir(parentList)
  return parentList;
}

arrToTree(arr3)

3 数字千位格式化

1283543 --> 1,283,543

0.5432143144 --> 0.543,214,314,4

1343.8593218 --> 1,343.859,321,8

function format(num) {
  if(typeof num !== 'number') return '';
  const dotReg = /./;
  const reg = /B(?=(d{3})+b)/g;
  const numStr = num + '';

  function strToReverse(str) {
    if(typeof str !== 'string') return ''
    return str.split('').reverse().join('')
  }

  if(dotReg.test(numStr)) {
    const arr = numStr.split('.');
    arr[0] = arr[0]  ? arr[0].replace(reg, ',') : '';
    const _temStr = strToReverse(arr[1]).replace(reg, ',')
    arr[1] =  arr[1] ? strToReverse(_temStr) : ''
    return arr.join('.')
  }

  return numStr.replace(reg, ',');

}
console.log(format(1234329)) // 1,234,329
console.log(format(12343.2904365)) // 12,343.290,436,5
console.log(format(0.2904365)) // 0.290,436,5

4 实现call, apply, bind方法

  • call
Function.prototype.mycall = function(obj) {
    var obj = obj || window;
    obj.fu = this;
    var args = [];
    for(var i = 1; i < arguments.length; i++ ) {
        args.push(arguments[i]);
    }
    var result = eval('obj.fu(' + args.join() + ')')

    delete obj.fun;
    return result;
}

function add(a) {
   console.log(this.name, a)
}
var deep = {name: 99}

add.mycall(deep, 3)
  • apply
Function.prototype.myApply = function(obj, arr) {
    var obj = obj || window;
    obj.fun = this;
    if(!arr) {
        return obj.fun()
    }
    if( !(arr instanceof Array)) {
        throw new Error('第二个参数请输入数组')
    }
    var args = [];
    for(i = 0; i< arr.length; i++) {
        args.push(arr[i])
    }
    var result = eval('obj.fun('+ args.join()+ ')');
    delete obj.fun;
    return result;
}

var deep = {name: '麦乐'};
function add(a) {
    console.log(this.name, a)
}
add.myApply(deep, [0, 9])

  •  bind
Function.prototype.myBind = function(obj) {
    var self = this;
    var bindArgs = Array.prototype.slice.call(arguments, 1);
    return function() {
        var args = Array.prototype.slice.call(arguments);
         // 如果 是new 的方式去调用,还需要让this指向实际例子 
        return self.apply((this instanceof self) ? this : obj, bindArgs.concat(args))
    }
    
    
}

var deep = {name: 'mailes'}

function add(a) {
    console.log(this.name, a)
}

var re = add.myBind(deep);

5.实现new

function Person(name) {
    this.name = name;
    return {
        name: '麦乐',
        age: 18
    }
}

Person.prototype.sayName = function() {
    console.log(this.sayName)
};


var person = new Person('麦乐');
console.log(person.name, person.age) // 麦乐 18

function objectFactory(fun) {
    var args = Array.prototype.slice.call(arguments, 1);
    var obj = Object.create(fun.prototype);
    const result  = fun.apply(obj, args);
    return result && obj;

}
var person = objectFactory(Person, '麦乐');
console.log(person)

6.

实现instanceof

function instanceOf(L, R) {
    if(!L || !R) return false;
    var L = L.__proto__;
    var R = R.prototype;
    console.log(R)
    while(true) {
        console.log(L)
        if(L == null) return false;
        if(R === L) {
            return true;
        }
        L = L.__proto__;
    }
}
console.log(instanceOf('9', Object))

7. 深拷贝循环引用?


var s = Symbol('4')

var obj = {
    time: new Date('2020-01-27'),
    [s]: 6
};
var a = {
  name: 'maile'
}
var b = {
    name: a
}
a.a = b;
obj.a = a;

// console.log(obj.a);

function wrapDeepClone(value) {
    var  map = new WeakMap()

    function deepClone(value) {
       
        var copy, existObj; // key只能是对象类型
        
        if(!value || typeof value !== 'object') return value;
        
        // 考虑日期
        if(value instanceof Date) {
            copy = new Date();
            copy.setTime(value.getTime());
            return copy;
            
        }
        
        if(map.has(value)) {
            return map.get(value);
        }
   
       //考虑数组
        
        if(value instanceof Array) {
            copy = [];
            map.set(value, copy);
            for(var i = 0; i < value.length; i++) {
                copy[i] = deepClone(value[i]);
            }
            return copy;
        }
        
        
        if(value instanceof Object) {
            copy = {};
            map.set(value, copy);
            
            // 考虑属性名是Symbol
            var symKeys = Object.getOwnPropertySymbols(value);
            symKeys.length && symKeys.forEach((key) => {
                copy[key] = deepClone(value[key])
            })
            
            // 考虑对象{}
            for(var key in value) {
                if(value.hasOwnProperty(key)) {
                    console.log(key)
                    copy[key] = deepClone(value[key])
                }
            }
            
            return copy;
        }
    
 
    }
    return deepClone(value)
}
var copyObj = wrapDeepClone(obj);



console.log(copyObj);

8. 两个页面间实时通信

WindowEventHandlers.onstorage 属性包含一个在storage事件触发时的事件句柄。 

注意:该事件不在导致数据变化的当前页面触发(如果浏览器同时打开一个域名下面的多个页面,当其中的一个页面改变 sessionStorage 或 localStorage 的数据时,其他所有页面的  storage  事件会被触发,而原始页面并不触发 storage 事件)

window.onstorage = function(e) {
  console.log( e.key + ' 键已经从 ' + e.oldValue + ' 改变为 ' + e.newValue + '.');
};

9. 实现 arr[-1]的访问

function fun(arr) {
  var proxyArr = new Proxy(arr, {
    get: function(target, key, reciver) {
      if(+key < 0) return target[target.length + +key];
      return target[key];
    },
    set: function(target, key, value, reciver) {
      target[key] = value;
    }
  });
  return proxyArr
}
var arr = [4,45,54,4,3,1,57,78,5]
var proxyArr = fun(arr)

10. 手写Promise

下面是一个简单的实现:

function myPromise(fun) {
  var self = this;
  this.status = 'pending'
  if(!(this instanceof myPromise)) {
    return new myPromise(fun)
  }
  this.resultList = [];
  this.errorList = [];

  fun(resolve, reject)

  function resolve(res) {
    if(self.status === 'pending') {
      self.status = 'fulfilled'
      self.value = res
      self.resultList.forEach(function(fun) {
        fun(self.value);
      })
    }
    
  }

  function reject(err) {
    if(self.status === 'pending') {
      self.status = 'rejected'
      self.reason = err
      self.errorList.forEach(function(fun) {
        fun(self.reason);
      })
    }
    
  }

  return this;
}

myPromise.prototype.then = function(onFulfilled, onRejected) {
  var isFunc = typeof onFulfilled === 'function';
  if(this.status === 'fulfilled') {
    isFunc && onFulfilled(this.value)
  }
  if(this.status === 'rejected') {
    onRejected(this.reason)
  }
  if(this.status === 'pending') {
    isFunc &&  this.resultList.push(onFulfilled)
    typeof onRejected === 'function' &&  this.errorList.push(onRejected)

  }
 
  return this;
}

myPromise.prototype.catch = function(fun) {
  if(this.status === 'rejected') {
    fun(this.reason)
  }
  if(this.status === 'pending') {
    typeof fun === 'function'  && this.errorList.push(fun)
  }
  
  return this;

}

function fetchData() {
  return new myPromise(function(resolve, reject) {
    resolve(2)
  })
}
fetchData().then(function(res) {
  console.log(res)
}).then(function(re) {
  console.log(re)
})
console.log(1)

存在问题:

1 return 的是this,状态是确定的

2 如果是一个带有完成或者失败状态的promise,调用then方法 是同步的

下面调整为可以链式调用的:

  • 每次调用then方法,返回的都是一个新的promise
  • then方法的参数,是异步调用的
  • then方法的参数支持有返回值,可以是promise,也可以是其它类型的值。
Promise.prototype.then=function(onfulfilled,onrejected){
    /** //如果当前promise进入成功态(用户调用的是resolve函数),就调用onfulfilled函数传入value
     if(self.status=='fulfilled'){//成功态
    setTimeout(function(){//异步调用onfulfilled
      onfulfilled(self.value)//拿到resolve中的value
    },0)
  }
     //如果promise进入失败态(用户调用的是reject函数),就调用onrejected函数,传入reason
     if(self.status=='rejected'){//失败状态
    setTimeout(function(){//异步调用onrejected
      onrejected(self.reason)//传入失败原因reason
    },0)
  }
     //当promise中的回调resolve,reject没有立即执行(异步执行)时,当前状态还是pending
     if(self.status=='pending'){
    //此时利用订阅发布模式,将then中的回调进行订阅,当promise的状态改变成resolve时或reject时(调用resolve或reject)时发布;
    self.onfulfilledList.push(function(){//订阅then中成功的函数
      onfulfilled(self.value);
    })
    self.onrejectedList.push(function(){//订阅then中失败的函数
      onrejected(self.reason)
    })
  }**/
    let self=this;
    let promise2=new Promise(function(resolve,reject){//返回这个promise对象
        //这个新的对象需要做的有判断当前的状态
        //判断then的onfulfilled的参数类型,onrejeced中拿到的参数的类型
        //如果then中的参数不是一个函数的话,那么promise中的value或reason就继续向下一个then传递
        //如果then的回调中返回的是一个普通对象那么就继续向下一个then传递
        //如果返回的是一个promise对象那么这个promise对象就作为下一个then的promise使用覆盖promise2;
        if(typeof onfulfilled !=='function'){//如果不是函数就将value向下传递数据
            onfulfilled=function(value){
                return value;
            }
        }
        if(typeof onrejected!=='function'){//如果不是函数就将reason向下传递数据
            onrejected=function(reason){
                return reason;
            }
        }

        if(self.status=='fulfilled'){//成功状态
            setTimeout(function(){//计时器异步的另一个作用是能让promise2对象能在promise2中正确引用
                try{
                    let x=onfulfilled(self.value);//拿到onfulfilled的返回值
                    resolvePromise(promise2,x,resolve,reject);//这个函数用来判断以上then的返回值,以处理then向下传递的状态走resolve函数还是reject函数
                }catch(e){
                    //抛出错误就返回错误
                    reject(e);
                }

            },0);
        }
        if(self.status=='rejected'){//失败状态
            setTimeout(function(){
                try{
                    let x=onrejected(self.reason);//拿到onrejected的返回值
                    resolvePromise(promise2,x,resolve,reject);
                }catch(e){
                    //抛出错误就返回错误
                    reject(e);
                }
            },0)
        }
        if(self.status=='pending'){//等待状态
            self.onfulfilledList.push(function(){
                setTimeout(function(){//计时器异步的另一个作用是能让promise2对象能在promise2中正确引用
                    try{
                        let x = onfulfilled(self.value);//拿到onfulfilled的返回值
                        resolvePromise(promise2, x, resolve, reject);
                    }catch(e){
                        reject(e)
                    }
                },0)
            })
            self.onrejectedList.push(function(){
                setTimeout(function(){
                    try{
                        let x = onrejected(self.reason);//拿到onrejected的返回值
                        resolvePromise(promise2, x, resolve, reject);
                    }catch(e){
                        reject(e);
                    }
                },0)
            })
        }
    })
    return promise2;
}

//处理then回调中x返回值的状态
function resolvePromise(promise2,x,resolve,reject){
    if(promise2 === x){//如果then回调中返回的x和promise2是一个就会陷入死循环
        return reject(new Error('死循环'))
    }
    let changeFlag;//用来做状态标识,如果状态改变后,就不再改变
    if((x!=null)&&(typeof x=='object'||typeof x=='function')){//判断x的类型函数或对象
        try{
            let then = x.then;
            //之所以用then取值而不使用x.then的原因是:避免多次取值造成不必要的错误(代码更加严谨)
            //Object.definedProperty(x,then,{get(){处理取值结果,改变不同的值}});
            if(typeof then == 'function'){//说明x有then方法
                then.call(x,function(y){
                    //resolve(value)不是应该向下传递应该继续判断下一个then的返回值类型
                    if(!changeFlag){changeFlag=true}else{return}
                    resolvePromise(x,y,resolve,reject)//递归判断
                    //避免返回的promise中依然返回的是promise,把所有嵌套的promise都执行,直到返回普通值
                },function(reason){
                    if(!changeFlag){changeFlag=true}else{return}
                    reject(reason);
                })
            }else{//不是一个promise,是个普通的对象,数据向下传递
                resolve(x)
            }
        }catch(e){
            if(!changeFlag){changeFlag=true}else{return}
            reject(e)
        }
    }else{//说明返回的是普通值,向下传递
        resolve(x)
    }
};


function isPromise(p){
  return p instanceof myPromise
}
function isObj(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]'
}

function isFunction(x) {
  return typeof x  === 'function'
}

var statusMap = {
  PENDING: 'pengding',
  FULFILLED: 'fulfilled',
  REJECTED: 'rejected'
}


function fulfillPromise(pro, res) {
  if(pro.status === statusMap.PENDING) {
    pro.status = statusMap.FULFILLED
    pro.value = res
    pro.onfulfilledList.forEach(function(fun) {
      fun(pro.value);
    })
  }
  
}

function rejectedPromise(pro, reason) {
  if(pro.status === statusMap.PENDING) {
    pro.status = statusMap.REJECTED
    pro.reason = reason
    pro.onrejectedList.forEach(function(fun) {
      fun(pro.reason);
    })
  }
  
}


function myPromise(fun) {
  var self = this;
  this.status = statusMap.PENDING
  if(!(this instanceof myPromise)) {
    return new myPromise(fun)
  }
  this.onfulfilledList = [];
  this.onrejectedList = [];

  fun(function(value) {
    fulfillPromise(self, value)
  }, function(reason) {
    rejectedPromise(self, reason)
  })


}

myPromise.prototype.then=function(onfulfilled,onrejected){
  //如果当前promise进入成功态(用户调用的是resolve函数),就调用onfulfilled函数传入value
  let self=this;
  let promise2=new Promise(function(resolve,reject){//返回这个promise对象
      //这个新的对象需要做的有判断当前的状态
      //判断then的onfulfilled的参数类型,onrejeced中拿到的参数的类型
      //如果then中的参数不是一个函数的话,那么promise中的value或reason就继续向下一个then传递
      //如果then的回调中返回的是一个普通对象那么就继续向下一个then传递
      //如果返回的是一个promise对象那么这个promise对象就作为下一个then的promise使用覆盖promise2;
      if(typeof onfulfilled !=='function'){//如果不是函数就将value向下传递数据
          onfulfilled=function(value){
              return value;
          }
      }
      if(typeof onrejected!=='function'){//如果不是函数就将reason向下传递数据
          onrejected=function(reason){
              return reason;
          }
      }

      if(self.status === statusMap.FULFILLED){//成功状态
          setTimeout(function(){//计时器异步的另一个作用是能让promise2对象能在promise2中正确引用
              try{
                  let x=onfulfilled(self.value);//拿到onfulfilled的返回值
                  resolvePromise(promise2,x,resolve,reject);//这个函数用来判断以上then的返回值,以处理then向下传递的状态走resolve函数还是reject函数
              }catch(e){
                  //抛出错误就返回错误
                  reject(e);
              }

          },0);
      }
      if(self.status === statusMap.REJECTED){//失败状态
          setTimeout(function(){
              try{
                  let x=onrejected(self.reason);//拿到onrejected的返回值
                  resolvePromise(promise2,x,resolve,reject);
              }catch(e){
                  //抛出错误就返回错误
                  reject(e);
              }
          },0)
      }
      if(self.status === statusMap.PENDING){//等待状态
          self.onfulfilledList.push(function(){
              setTimeout(function(){//计时器异步的另一个作用是能让promise2对象能在promise2中正确引用
                  try{
                      let x = onfulfilled(self.value);//拿到onfulfilled的返回值
                      resolvePromise(promise2, x, resolve, reject);
                  }catch(e){
                      reject(e)
                  }
              },0)
          })
          self.onrejectedList.push(function(){
              setTimeout(function(){
                  try{
                      let x = onrejected(self.reason);//拿到onrejected的返回值
                      resolvePromise(promise2, x, resolve, reject);
                  }catch(e){
                      reject(e);
                  }
              },0)
          })
      }
  })
  return promise2;
}


//处理then回调中x返回值的状态
function resolvePromise(promise2,x,resolve,reject){
  if(promise2 === x){//如果then回调中返回的x和promise2是一个就会陷入死循环
      return reject(new Error('死循环'))
  }
  let changeFlag;//用来做状态标识,如果状态改变后,就不再改变
  if(!x) {
    return resolve(x)
  }
  if(isPromise(x)) {
    console.log(43)
    if(x.status === statusMap.FULFILLED) {
      return resolve(x.value)
    }
    if(x.status ===  statusMap.REJECTED) {
      return reject(x.value)
    }
    if(x.status === statusMap.PENDING) {
      return x.then(function(re) {
       return resolve(re)
      }, function(err) {
       return reject(err)
      })
    }
  }
  if(isFunction(x) || isObj(x)){
    console.log(4, 9)
    return  step(x)
  }
 
  resolve(x);

  function step(x) {
    try{
      let then = x.then;
      //之所以用then取值而不使用x.then的原因是:避免多次取值造成不必要的错误(代码更加严谨)
      //Object.definedProperty(x,then,{get(){处理取值结果,改变不同的值}});
      if(typeof then == 'function'){//说明x有then方法 以x为this调用then函数
          then.call(x,function(y){
              //resolve(value)不是应该向下传递应该继续判断下一个then的返回值类型
              if(!changeFlag){changeFlag=true}else{return}
              resolvePromise(x,y,resolve,reject)//递归判断
              //避免返回的promise中依然返回的是promise,把所有嵌套的promise都执行,直到返回普通值
          },function(reason){
              if(!changeFlag){changeFlag=true}else{return}
              reject(reason);
          })
      }else{//不是一个promise,是个普通的对象,数据向下传递
          resolve(x)
      }
    }catch(e){
        if(!changeFlag){changeFlag=true}else{return}
        reject(e)
    }
  }
   
};

11 手写Promise.all

function promiseAll(arr) {
  return new Promise(function(resolve, reject){
    var result = []
    arr.forEach((ele, index) => {
      ele.then(function(res) {
        result.push(res)
        if(index === arr.length -1) {
          resolve(result)
        }
      },function(error){
        reject(error);
      })
    });
  })
}

var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
var p4 = Promise.reject(4)

var arr = [p1, p2, p3, p4]

promiseAll(arr).then(function(res) {
  console.log(res)
}).catch(function(err) {
  console.log(err)
})

升级版

function promiseAll(promises) {
  if(Array.isArray(promises)) return [];
  const result = [];
  const len = promises.length;
  return new Promise((resolve, reject) => {
    for(let i = 0; i < len; i ++) {
      Promise.resolve(promises[i]).then((res) => {
        result[i] = res;
        if(i === len - 1) resolve(result)
      }).catch((error) => {
        reject(error)
      })
    }
  })

}

1.编程能力测试:
1.1 once函数 => passed

function once(fun) {
    return function (...args) {
        if (fun.called) {
            return fun.value;
        }
        fun.called = true;
        return (fun.value = fun.apply(null, args));
    };
}
function maile() {
    console.log(1);
}
const onceMaile = once(maile);
onceMaile();
onceMaile();


1.2 写一个限时(比如限时5s)执行函数: => 算passed。

function fun() {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, 3000);
    });
}

async function wait(fun) {
    const preTime = new Date().valueOf();
    await fun();
    const nowDate = new Date().valueOf();
    if (nowDate - preTime > 5000) {
        console.log(1);
    } else {
        console.log(2);
    }
}
wait(fun);


1.3 字符串反转函数。 => passed ,过程啰嗦

function reverse(str) {
    if (typeof str !== 'string') {
        console.info(`${reverse}函数只接受字符串`);
        return;
    }
    const list = str.split('');
    var resStr = list.reduceRight((res, i) => {
        console.log(i);
        return (res += i);
    }, '');
    return resStr;
}
console.log(reverse('ijhdsh'));


1.4深clone(包括原型链的clone)=> 经常分享不了平常。口头讲解过程,还可以,也不算很彻底。

function isObj(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
}
function isArray(obj) {
    return Array.isArray(obj);
}

function is(a, type) {
    return typeof a === type;
}

function deepClone(target) {
    if (!target || !isObj(target)) {
        return {};
    }
    const caches = [];

    function filter(target) {
        return caches.filter((i) => i.source === target);
    }

    function copy(target) {
        let result = isArray(target) ? [] : {};
        let targetValue;
        const cacheTarget = filter(target);
        if (cacheTarget && cacheTarget.length > 0) {
            return cacheTarget[0].result;
        }
        const _cache = {
            source: target,
            result,
        };
        caches.push(_cache);
        Reflect.ownKeys(target).forEach((key) => {
            targetValue = target[key];
            if (
                is(targetValue, 'string') ||
                is(targetValue, 'number') ||
                is(targetValue, 'boolean')
            ) {
                result[key] = targetValue;
            } else {
                result[key] = copy(targetValue);
            }
        });
        return result;
    }
    return copy(target);
}
var simple = { a: '卖了', b: 'jj', c: 'oo' };
var noSimple = { g: 'dd', h: simple };
simple.jj = noSimple;
const res = deepClone(noSimple);
console.log(res);


1.5对象数组,根据某属性(如name的首字母)分组,并按其 字母正序排序。 =>勉强passed。 理解不好。
笔试基本都passed,但挺慢的,加上网络屏幕经常卡顿的缘故。
2逻辑思维:
2.1假设该公司的人数为60 前端程序员为1/2 后端程序员人数为2/5 两者都是的人数为1/4 两者都不是的为多少? => passed。但回答时间非常之长,前后花费将近20分钟。
3.2 假设你有8个球,其中一个略微重一些,但是找出这个球的惟一方法是将两个球放在天平上对比。最少要称多少次才能找出这个较重的球?—>not passed yet.


3技术理解:
3.1 VUE/React。 => 没怎用过vue,更不了解vue3. react的开发,算比较扎实,虽然底层原理不大理解。
3.2 http2的特点 。 => 能回答 多路复用、新的二进制格式,这些都能回答出来。知识面好。
3.3. CSS中的BFC => 部分理解。BFC是一个“绝缘”盒子的特性,倒没回答出来。
3.4 js的数据类型、this绑定、宏任务微任务 => 能基本回答。

0. 英文。挺说不足。阅读也挺欠缺(测试中给了一小段英文,说不上意思)To save the developers from keep registering new icons to the project manually, a simple module is build. The developer only need to save the icons needed in the specific directory with naming convention specified, the icons in the specific directory then will loaded into project automatically

2.编程能力测试

2.3 数据分组和排序。 —> passed
2.4 已知数据格式,实现一个函数,找出链条所以的父级id。 比如 func(1211) -> ‘1-12-121-1211’ —> not passed

3技术理解:
4.1 VUE/React。 —>  没怎用过vue,不了解vue3。react的setState更新,优化点,回答得不好。 fiber/v-dom diff 之类,不清楚。
4.2 http2的特点 。 —> 不清楚
4.3 ['1','2','3'].map(parseInt) 结果是[1,2,3]吗? 为什么?—> 回答不了。
4.4 在移动端使用transform: translate代替top left marg等做位移有好处么 ?—>本来这道题可以引起repaint/reflow,跟他工作经历挺相干的,但完全不清楚。
4.5 css中弹性盒子,常用到的flex:1 0 auto 做何解? —> 回答不了。基本不写css。
4.6 js中+0和-0的差别,为何+0===-0 ? —>听他说是电子专业出身,临时问问。也回答得不好。

阿里巴巴前端面试分享-社招(p6)

借鉴了朋友的阿里面试经:(社招前端2年经验)

电话面

  1. 简单自我介绍, 做过哪些项目, 使用哪些技术栈 ?
  2. 如何看待前端框架选型 ?
  3. vue的如何实现双向绑定的 ?
  4. react 虚拟DOM 是什么? 如何实现? 说一下diff算法 ?
  5. 工作中最出色的点, 和你最头疼的问题 如何解决的 ?
  6. 平时如何学习, 最近接触了解了哪些新的知识 ?

技术一面

  1. 简单自我介绍, 介绍一下你的项目, 技术栈 ?
  2. react和vue的比较 ?
  3. React Diff 算法 ?
  4. 观察者模式实现 ?
  5. http报文头部有哪些字段? 有什么意义 ?
  6. 移动端高清方案如何解决 ?
  7. webpack的原理, loader 和 plugin 是干什么的? 有自己手写过么 ?
  8. 简述从网页输入url到网页展示的过程发生了哪些事情 ?
  9. SSR 和 客户端渲染有什么区别 , vue是如何实现绑定事件的 ?
  10. 简述公司node架构中容灾的实现 ?
  11. 浏览器事件有哪些过程? 为什么一般在冒泡阶段, 而不是在捕获阶段注册监听? addEventListener 参数分别是什么 ?
  12. 面向对象如何实现? 需要复用的变量 怎么处理 ?
  13. 移动端300ms延时的原因? 如何处理?
  14. 主流框架的数据单向/双向绑定实现原理 ?
  15. 简述转行经历, 如何学习 ?
  16. 你觉得自己在前端工作的最大的优点是什么 拿实际工作的内容举例?

技术二面

  1. 和一面前3问基本一致,简述项目,React vue区别 virsualDOM实现
  2. DIFF算法为什么是O(n)复杂度而不是O(n^3)
  3. http code码?
  4. 移动端rem布局如何实现? 简述原理?
  5. JSbridge原理, js和native是如何通信的?
  6. Rollup和webpack区别, treeshaking是什么?
  7. TCP三次握手的过程, get post请求的区别 ?
  8. 静态文件的浏览器缓存如何实现?
  9. 前端跨域方案
  10. http 请求包含哪些字段 分别是什么意思
  11. js 有哪些数据类型 如何判断? null 和 undefined区别 应用场景?
  12. new String('a') 和 'a' 是一样的么?
  13. 移动端如何实现下拉到底部 跟随移动 结束后回弹的动画?
  14. 移动端如何优化首页白屏时间过长 ?
  15. ES6 generator函数简述
  16. 数组去重实现?
  17. js浮点数运算不精确 如何解决?
  18. 工作中最得意和出色的点, 头疼的点, 问题如何解决的
  19. 为何换工作?
  20. 聊了下阿里的压力,文化

技术三面

  1. 公司的前端工程化实践
  2. 转行之后是如何自学前端的, 学习途径 有没有一些自己的代码
  3. DOM基础知识,添加元素,删除元素等等...
  4. DOM节点类型
  5. 正则表达式如何匹配一段url ?在正则表达式中有哪几种作用?
  6. 移动端优化方式? 离线包是如何实现的?
  7. 最后聊了一下项目,聊了一下目前公司
实现reduce的polyfill

function reducePolyfill() {
  if(Array.prototype.reduce) return;
  Object.defineProperty(Array.prototype, 'reduce', {
    value: function(fun) {
      if(!this) {
        throw new TypeError('Array.prototype.reduce called in null or undefined')
      }
      if(typeof fun !== 'function') {
        throw new TypeError('Reduce receive a function')
      }
      let o = Object(this);
      let result = null;
      let i = 0;
      if(arguments.length >= 2) {
        result = arguments[0]
      } else {
        result = o[0];
        i = 1;
      }
      const len = o.length;
      if(i > len) {
        throw new TypeError('Reduce of empty array called')
      }
      for(i; i < len; i ++) {
        result = fun(result, o[i], i, o)
      }
      return result;
    }
  })
}
// 实现 go函数
function go(...args) {
  let str = 'go';
  const _go = function(...agrs1) {
    if(agrs1 && agrs1.length){
      return (str = str + agrs1[0]);
    } else {
      str = str + 'o';
      return _go;
    }
  
  }
  return _go(...args);
}

最后

以上就是腼腆宝贝为你收集整理的面试题总结 - 函数 深拷贝 驼峰转换阿里巴巴前端面试分享-社招(p6)的全部内容,希望文章能够帮你解决面试题总结 - 函数 深拷贝 驼峰转换阿里巴巴前端面试分享-社招(p6)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部