前端面试题--02

几道前端经典的面试题

  1. 对象(数组)的深克隆和浅克隆

    let obj = {
        a: 100,
        b: [10,20,30],
        c: {
            x: 10
        },
        d: /^\d+$/
    };
    
    //浅克隆1
    let obj2 = {};
    for(let key in obj){
        if(!obj.hasOwnProperty(key)) break;
        obj2[key] = obj[key];
    }
    console.log(obj2)
    console.log(obj === obj2) //false
    console.log(obj.c === obj2.c) //true
    
    //浅克隆2
    let obj2 = {...obj}
    
    //深克隆1
    //函数、日期格式以及正则用JSON.stringify()都会有问题
    let obj2 = JSON.parse(JSON.stringify(obj));
    console.log(obj2)
    
    //深克隆2
    function deepClone(obj){
        //=>过滤特殊情况
        if(obj === null) return null;
        if(typeof obj !== 'Object') return obj;
        //正则
        if(obj instanceof RegExp){
            return new RegExp(obj);
        }
        //日期格式
        if(obj instanceof Date){
            return new Date(obj);
        }
        // let newObj = {};
        // let newObj = new Object();
        //=>不直接创建空对象,目的:克隆的结果和之前保持相同的所属类
        let newObj = new obj.constructor;
        for(let key in obj){
            if(obj.hasOwnProperty(key)){
    
                newObj[key] = deepClone(obj[key])
            }
        }
        return newObj;
    }
    let obj2 = deepClone(obj)
    console.log(obj2)
    console.log(obj === obj2) //false
    console.log(obj.c === obj2.c) //false
    
    //深克隆3 使用lodash.cloneDeep实现深克隆
    import _ from 'lodash'
    var obj2 = _.cloneDeep(obj);
    obj2.c.x = 'obj2';
    console.log(obj,obj2)
    
  2. 几道关于堆栈内存和闭包作用域的题

    堆:存储引用类型值的空间

    栈:存储基本类型值和指定代码的环境

    闭包:保存和保护()

    //example 1
    let a={},b='0',c=0;
    a[b]='zhangsan';
    a[c]='lisi';
    console.log(a[b]); //lisi
    //对象的属性名不能重复,作为属性名数字和字符串是一样的
    //=>对象和数组的区别?
    
    //example 2
    let a = {},
        b = Symbol('1'),
        c = Symbol('1');
    a[b]='zhangsan';
    a[c]='lisi';
    console.log(a[b]); //zhangsan
    //Symbol创建唯一值的
    //=>自己实现Symbol?
    
    //example 3
    let a = {},
        b = {
            n: '1'
        },
        c = {
            m: '2'
        };
    a[b]='zhangsan';
    a[c]='lisi';
    console.log(a[b]); //lisi
    //属性名为对象的话,会转化为字符串, Object.tostring() ==> "[object Object]"
    //=>Object.prototype.toString()的应用? /  valueOf和toString区别?
    
    //example 1
    var test = (function(i){
        return function(){
            alert(i *= 2);
        }
    })(2);
    test(5); //'4' ,alert会转化为字符串
    //test为立即执行的自执行函数,形成闭包,引用了上级作用域的参数
    
    //example 2
    var a=0,b=0;
    function A(a){
        A=function(b){
            alert(a+b++); 
        }
        alert(a++) //先执行alert(a),然后a自增;  ++a和a++的区别
    }
    A(1);//'1'
    A(2);//'4'
    //函数A中的A没有用var声明,就是全局的A,重写了函数A,又形成了闭包
    
  3. 一道关于面对对象面试题所引发的血案(阿里)

    对象成员访问级别高,优先执行,new函数级别低,次之执行

    function Foo() {
        getName = function () {
            console.log(1);
        };
        return this;
    }
    Foo.getName = function () {
        console.log(2);
    };
    Foo.prototype.getName = function () {
        console.log(3);
    };
    var getName = function () {
        console.log(4);
    };
    
    function getName() {
        console.log(5);
    }
    Foo.getName(); //2
    getName(); //4
    Foo().getName(); //1
    getName(); //1
    new Foo.getName(); //2
    new Foo().getName(); //3
    new new Foo().getName(); //3
    

  4. 一道面试题让你彻底掌握JS中的EventLoop

    async function async1() {
        console.log('async1 satrt')
        await async2()
        console.log('async1 end')
    }
    
    async function async2() {
        console.log('async2 end')
    }
    
    console.log('script start')
    
    setTimeout(function() {
        console.log('setTimeout')
    }, 0)
    
    async1()
    
    new Promise(resolve => {
        console.log('Promise')
        resolve()
    }).then(function() {
        console.log('promise1')
    }).then(function() {
        console.log('promise2')
    })
    
    console.log('script end')
    
    //浏览器是多线程的,js是单线程=>浏览器只给了其一个线程来渲染
    //定时器、事件绑定、ajax等属于宏任务,Promise async await等属于微任务。会优先执行微任务
    //执行顺序
    创建函数async1
    创建函数async2
    =>'script start'
    设置定时器 (宏任务A)
    函数执行
        => 'async1 satrt'
    	await async2(); 执行async2等待返回的结果 (微任务B)
        	=> 'async2 end'
    new Promise的时候会立即把EC函数执行(new 的时候是同步的)
        => 'Promise'
    	resolve() / reject() (微任务C)
    => 'script end'
    //主栈第一阶段完成
    => B =>'async1 end'
    => C =>'promise1'
    	resolve() / reject() (微任务D)
    => D => 'promise2'
    => A => 'setTimeout'
    
function A() {
    alert(1);
}
function Func() {
    A = function () {
        alert(2);
    };
    return this;
}
Func.A = A;
Func.prototype = {
    A: () => {
        alert(3);
    },
};
A();  //1
Func.A(); //1
Func().A();//2
new Func.A();//1
new Func().A(); //3
new new Func().A();  //报错,箭头函数没有原型链,不能new
//问题: 当a为什么时,以下条件成立
var a = ?;
if (a == 1 && a == 2 && a == 3) {
    console.log('条件成立');
} 
// TO-STRING
// 1.手动添加一个toString方法,每次判断==都会自动调用toString方法
var a = {
    i: 0,
    toString() {
        return ++this.i;
    }
};

// a为什么,以下成立
if (a == 1 && a == 2 && a == 3) {
    console.log('条件成立');
} 

/* var a = [1, 2, 3];
   a.toString = a.shift;
   if (a == 1 && a == 2 && a == 3) {
       console.log('条件成立');
   } */


/* 2.数据劫持实现 */
var i = 0;
Object.defineProperty(window, 'a', {
    get() {
        return ++i;
    }
});
if (a == 1 && a == 2 && a == 3) {
    console.log('条件成立');
} 

/* var a = 0;
   Object.defineProperty(window, 'a', {
      get() {
        // Uncaught TypeError: Cannot redefine property: a
        // defineProperty GETER拦截器中不能再次获取当前属性,会死循环
        return ++a;
      }
   });
console.log(a); */
 == ,数据类型不一样
1. 对象==字符串, 对象自动调用toString变成字符窜 ['a']=='a'
2. null ==undefind相等,但是和其他值比较不在相等了
3. NaN ==NaN,不相等
4. 剩下的都是转换成数字 '1'==true //true
[10]==10 ,底层转换
[10]自动调用toString为‘10’,然后自动调用number,为10
posted @ 2021-04-07 01:06  含光~~仌槑槑仌  阅读(91)  评论(0)    收藏  举报