美文网首页
中高级前端面试题

中高级前端面试题

作者: 会会会会 | 来源:发表于2019-10-09 10:29 被阅读0次

    事件循环机制

    同步:执行栈

    异步:任务队列

    1.宏任务

    • 点击回调
    • settimeout

    2.微任务

    • 当前task执行结束后立即执行的任务
    • 新微任务将放到队列尾部
    • promise

    微任务会在下一个宏任务前,全部执行完

    3.事件队列

    同步任务 → 主线程(执行栈)→ 执行完成 → 任务队列
    

    浏览器渲染

    1. 处理 HTML 标记并构建 DOM 树。
    2. 处理 CSS 标记并构建 CSSOM(Style Rules) 树。
    3. 将 DOM 与 CSSOM 合并成一个渲染树(Render Tree)。
    4. 根据渲染树(Layout)来布局,以计算每个节点的几何信息。
    5. 将各个节点绘制(Painting)到屏幕上

    深拷贝&浅拷贝

    • 首先可以通过 Object.assign 来解决这个问题,很多人认为这个函数是用来深拷贝的。其实并不是,Object.assign 只会拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是地址,所以并不是深拷贝。 浅拷贝就只是拷贝的对象的地址。
    let a = {
      age: 1
    }
    let b = Object.assign({}, a)
    a.age = 2
    console.log(b.age) // 1
    
    • 另外我们还可以通过展开运算符 ... 来实现浅拷贝
    let a = {
      age: 1
    }
    let b = { ...a }
    a.age = 2
    console.log(b.age) // 1
    

    解构赋值的拷贝是浅拷贝,不能复制继承自原型对象的属性。

    • 深拷贝 这个问题通常可以通过 JSON.parse(JSON.stringify(object)) 来解决。
    let a = {
      age: 1,
      jobs: {
        first: 'FE'
      }
    }
    let b = JSON.parse(JSON.stringify(a))
    a.jobs.first = 'native'
    console.log(b.jobs.first) // FE
    

    但是该方法也是有局限性的:

    • 会忽略 undefined
    • 会忽略 symbol
    • 不能序列化函数
    • 不能解决循环引用的对象

    关于枚举

    四个操作会忽略enumerable为false的属性。

    1. for...in循环:只遍历对象自身的和继承的可枚举的属性。含原型链
    2. Object.keys():返回对象自身的所有可枚举的属性的键名。含原型链
    3. JSON.stringify():只串行化对象自身的可枚举的属性。
    4. Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

    属性的遍历
    ES6 一共有 5 种方法可以遍历对象的属性。

    • (1)for...in

    for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

    • (2)Object.keys(obj)

    Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

    • (3)Object.getOwnPropertyNames(obj)

    Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

    • (4)object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

    • (5)Reflect.ownKeys(obj)

    Reflect.ownKeys()返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable影响).

    js原型

    1、proto ( [[Prototype]] )

    对象原型链,可以直接通过属性访问;如果属性不在当前对象中,就通过原型链查找

    var anotherObject = { a:2 };
    //自行了解 Object.create(..) 的原理,现在只需要知道它会创建一个
    对象并把这个对象的 [[Prototype]] 关联到指定的对象。
    
    var myObject = Object.create( anotherObject ); 
    myObject.a; // 2 
    
    myObject.__proto__ === anotherObject  //true;
    

    所有普通的 [[Prototype]] 链最终都会指向内置的 Object.prototype
    都是Object实例出来的;

    anotherObject 改变  myObject.a改变
    
    myObject.a 改变后,脱离anotherObject
    
    myObject.hasOwnProperty( "a" ); // true
    

    **myObject.foo 总是会选择原型链中最底层的 foo 属性 **

    2、prototype

    所有的函数默认都会拥有一个 名为prototyp的公有并且不可枚举的属性,它会指向另一个对象 ,这个对象通常被称为 Foo 的原型

    function Foo() { // ...
    }
    var a = new Foo();
    
    a.__proto__ === Foo.prototype// true;
    

    new Foo() 只是间接完成了我们的目 标:一个关联到其他对象的新对象。

    3、constructor

    function Foo() { // ...   }
     Foo.prototype.constructor === Foo; // true
    //Foo.prototype 的 .constructor 属性只是 Foo 函数在声明时的默认属性。
    如果 你创建了一个新对象并替换了函数默认的 .prototype
    对象引用,那么新对象并不会自动获 得 .constructor 属性。 
    
     var a = new Foo();
     a.constructor === Foo; // true
    
    
    a.__proto__ === NothingSpecial.prototype //true;
    
    a.constructor  === Foo.prototype.constructor === Foo; // true
    

    实际上 a 本身并没有 .constructor 属性。而且,虽然 a.constructor 确实指 向 Foo 函数,但是这个属性并不是表示 a 由 Foo“构造”.

    function NothingSpecial() { console.log( "Don't mind me!" ); }
    var a = new NothingSpecial(); 
    // "Don't mind me!" a; 
    // {} 
    

    小结

    • Object 是所有对象的爸爸,所有对象都可以通过__proto__找到它
    • Function 是所有函数的爸爸,所有函数都可以通过__proto__找到它
    • 函数的prototype是一个对象
    • 对象的__proto__属性指向原型,__proto__将对象和原型连接起来组成了原型链

    面向对象编程

    JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。

    所有对象都是实例,所谓继承关系不过是把一个对象的原型指向另一个对象而已。

    Object.create()方法可以传入一个原型对象,并创建一个基于该原型的新对象,但是新对象什么属性都没有,因此,我们可以编写一个函数来创建.

    下一篇,框架篇中高级前端面试题(二)框架篇

    相关文章

      网友评论

          本文标题:中高级前端面试题

          本文链接:https://www.haomeiwen.com/subject/bnmwpctx.html