• 刷面经笔记2019.02.11


    1.apply,call,bind有什么区别?

    三者都可以把一个函数应用到其他对象上,apply,call是直接执行函数调用,bind是绑定,执行需要再次调用。  

    apply和call的区别是apply接受数组作为参数,而call是接受逗号分隔的无限多个参数列表。

    代码如下:

    function Person() {
        }
        Person.prototype.sayName() { alert(this.name); }
    
        var obj = {name: 'michaelqin'}; // 注意这是一个普通对象,它不是Person的实例
        // 1) apply
        Person.prototype.sayName.apply(obj, [param1, param2, param3]);
    
        // 2) call
        Person.prototype.sayName.call(obj, param1, param2, param3);
    
        // 3) bind
        var liaoke = Person.prototype.sayName.bind(obj);    
        liaoke ([param1, param2, param3]); // bind需要先绑定,再执行 
        liaoke (param1, param2, param3); // bind需要先绑定,再执行

    2.defineProperty,hasOwnProperty,isEnumerable都是做什么用的?

    Object.defineProperty(obj,prop,descriptor)用来给对象定义属性,有value,writeable,enumerable,set/get等,

    hasOwnProperty用于检查某一属性是不是存在于对象本身,

    isEnumerable用来检测某一属性是否可遍历,也就是能不能用for...in循环来取到。

    3.JS常用设计模式的实现思路(单例、工厂、代理、装饰、观察者模式等)

     // 1) 单例: 任意对象都是单例,无须特别处理
        var obj = {name: 'michaelqin', age: 30};
    
     // 2) 工厂: 就是同样形式参数返回不同的实例
        function Person() { this.name = 'Person1'; }
        function Animal() { this.name = 'Animal1'; }
    
        function Factory() {}
        Factory.prototype.getInstance = function(className) {
            return eval('new ' + className + '()');
        }
    
        var factory = new Factory();
        var obj1 = factory.getInstance('Person');
        var obj2 = factory.getInstance('Animal');
        console.log(obj1.name); // Person1
        console.log(obj2.name); // Animal1
    
     // 3) 代理: 就是新建个类调用老类的接口,包一下
        function Person() { }
        Person.prototype.sayName = function() { console.log('michaelqin'); }
        Person.prototype.sayAge = function() { console.log(30); }
    
        function PersonProxy() { 
            this.person = new Person();
            var that = this;
            this.callMethod = function(functionName) {
                console.log('before proxy:', functionName);
                that.person[functionName](); // 代理
                console.log('after proxy:', functionName);
            }
        }
    
        var pp = new PersonProxy();
        pp.callMethod('sayName'); // 代理调用Person的方法sayName()
        pp.callMethod('sayAge'); // 代理调用Person的方法sayAge() 
    
      // 4) 观察者: 就是事件模式,比如按钮的onclick这样的应用.
        function Publisher() {
            this.listeners = [];
        }
        Publisher.prototype = {
            'addListener': function(listener) {
                this.listeners.push(listener);
            },
    
            'removeListener': function(listener) {
                delete this.listeners[listener];
            },
    
            'notify': function(obj) {
                for(var i = 0; i < this.listeners.length; i++) {
                    var listener = this.listeners[i];
                    if (typeof listener !== 'undefined') {
                        listener.process(obj);
                    }
                }
            }
        }; // 发布者
    
        function Subscriber() {
    
        }
        Subscriber.prototype = {
            'process': function(obj) {
                console.log(obj);
            }
        }; // 订阅者
    
        var publisher = new Publisher();
        publisher.addListener(new Subscriber());
        publisher.addListener(new Subscriber());
        publisher.notify({name: 'michaelqin', ageo: 30}); // 发布一个对象到所有订阅者
        publisher.notify('2 subscribers will both perform process'); // 发布一个字符串到所有订阅者

    3.字符串常用的十个函数

    charAt()   // 返回在指定位置的字符。
    concat()   // 连接字符串。
    fromCharCode()   // 从字符编码创建一个字符串。
    indexOf()  // 检索字符串。
    match()   // 找到一个或多个正则表达式的匹配。
    replace()   // 替换与正则表达式匹配的子串。
    search()   // 检索与正则表达式相匹配的值。
    slice()   // 提取字符串的片断,并在新的字符串中返回被提取的部分。
    split()   // 把字符串分割为字符串数组。
    substr()   // 从起始索引号提取字符串中指定数目的字符。
    substring()   // 提取字符串中两个指定的索引号之间的字符。
    toLocaleLowerCase()   // 把字符串转换为小写。
    toLocaleUpperCase()   // 把字符串转换为大写。
    toLowerCase()   // 把字符串转换为小写。
    toUpperCase()   // 把字符串转换为大写。
    toString()   // 返回字符串。
    valueOf()   // 返回某个字符串对象的原始值。

    4.如何判断一个变量是对象还是数组

    function isObjArr(variable){
         if (Object.prototype.toString.call(value) === "[object Array]") {
                console.log('value是数组');
           }else if(Object.prototype.toString.call(value)==='[object Object]'){//这个方法兼容性好一点
                console.log('value是对象');
          }else{
              console.log('value不是数组也不是对象')
          }
    }
    
    // 注意:千万不能使用typeof来判断对象和数组,因为这两种类型都会返回"object"。

    5.ES5的继承和ES6的继承有什么区别?

    ES5的继承是通过prototype或构造函数机制来实现。

    ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parement.apply(this))。

    ES6的继承机制实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。具体为ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其调用。如果不调用super方法,子类得不到this对象。

    注意:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。

    6.下面的ul,如何点击每一列的时候alert其index?(闭包)

     <ul id=”test”>
     <li>这是第一条</li>
     <li>这是第二条</li>
     <li>这是第三条</li>
     </ul>
    // 方法一:
    var lis=document.getElementById('test').getElementsByTagName('li');
    for(var i=0;i<3;i++)
    {
    lis[i].index=i;
    lis[i].onclick=function(){
    alert(this.index);
    };
    }
    
    //方法二:
    var lis=document.getElementById('test').getElementsByTagName('li');
    for(var i=0;i<3;i++)
    {
    lis[i].index=i;
    lis[i].onclick=(function(a){
    return function() {
    alert(a);
    }
    })(i);
    }

    7.对于MVVM的理解

    MVVM 是 Model-View-ViewModel 的缩写。
    Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。
    View 代表UI 组件,它负责将数据模型转化成UI 展现出来。
    ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,
    简单理解就是一个同步View 和 Model的对象,连接Model和View。
    在MVVM架构下,View 和 Model 之间并没有直接的联系,
    而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的,
    因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
    ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,
    而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,
    因此开发者只需关注业务逻辑,不需要手动操作DOM,
    不需要关注数据状态的同步问题,
    复杂的数据状态维护完全由 MVVM 来统一管理。

    8.解释Vue的生命周期

    Vue实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom->渲染、更新->渲染、销毁等一系列过程,称之为Vue的生命周期。

    Vue的生命周期包括:

    beforeCreate(创建前)在数据观测和初始化事件还未开始,

    created(创建后)完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来;

    beforeMount(载入前)在挂载开始之前被调用,相关的render函数首次被调用,实例已完成以下的配置:编译模板,把data里面的数据和模板生成html,注意此时还没有挂载html到页面上;

    mounted(载入后)在el被新创建的vm.$el替换,并挂载到实例上去之后调用,实例已完成以下配置:用上面编译好的html内容替换el属性指向的DOM对象,完成模板中的html渲染到html页面中,此过程中进行ajax交互。

    beforeUpdate(更新前)在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前,可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。

    updated(更新后)在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,该钩子在服务器渲染期间不被调用。

    beforeDestroy(销毁前)在实例销毁之前调用,实例仍然完全可用。

    destroyed(销毁后)在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

    9.为什么使用Node.js,它有哪些优缺点?

    优点:
    事件驱动,通过闭包很容易实现客户端的生命活期。
    不用担心多线程,锁,并行计算的问题
    V8引擎速度非常快
    对于游戏来说,写一遍游戏逻辑代码,前端后端通用
    缺点:
    nodejs更新很快,可能会出现版本兼容
    nodejs还不算成熟,还没有大制作
    nodejs不像其他的服务器,对于不同的链接,不支持进程和线程操作

    10.什么是错误优先的回调函数?

    错误优先(Error-first)的回调函数(Error-First Callback)用于同时返回错误和数据。
    第一个参数返回错误,并且验证它是否出错;其他参数返回数据。

    fs.readFile(filePath, function(err, data)
    {
        if (err)
        {
            // 处理错误
            return console.log(err);
        }
        console.log(data);
    });

    11.使用npm有哪些好处?

    通过npm,你可以安装和管理项目的依赖,
    并且能够指明依赖项的具体版本号。
    对于Node应用开发而言,
    你可以通过package.json文件来管理项目信息,
    配置脚本,以及指明依赖的具体版本

    12.在JavaScript源文件的开头包含 use strict 有什么意义和好处?

    use strict 是一种在JavaScript代码运行时自动实行更严格解析和错误处理的方法。(严格模式)

    将值分配给一个未声明的变量会自动创建该名称的全局变量。这是JavaScript中最常见的错误之一。在严格模式下,这样做的话会抛出错误。消除 this 强制。

    当检测到对象(例如,var object = {foo: "bar", foo: "baz"};)中重复命名的属性,或检测到函数中(例如,function foo(val1, val2, val1){})重复命名的参数时,严格模式会抛出错误,因此捕捉几乎可以肯定是代码中的bug可以避免浪费大量的跟踪时间。使eval() 更安全。

    13.vuejs与angularjs以及react的区别?

    与AngularJS的区别
    相同点:
    都支持指令:内置指令和自定义指令。
    都支持过滤器:内置过滤器和自定义过滤器。
    都支持双向数据绑定。
    都不支持低端浏览器。

    不同点:
    1.AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观。
    2.在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。
    Vue.js使用基于依赖追踪的观察并且使用异步队列更新。所有的数据都是独立触发的。
    对于庞大的应用来说,这个优化差异还是比较明显的。


    与React的区别

    相同点:
    React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用。
    中心思想相同:一切都是组件,组件实例之间可以嵌套。
    都提供合理的钩子函数,可以让开发者定制化地去处理需求。
    都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载。
    在组件开发中都支持mixins的特性。

    不同点:
    React依赖Virtual DOM,而Vue.js使用的是DOM模板。React采用的Virtual DOM会对渲染出来的结果做脏检查。
    Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作Virtual DOM。

    14.<keep-alive></keep-alive>的作用是什么?

     <keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。

    15.WeakMap 和 Map 的区别?

    WeakMap 结构与 Map 结构基本类似,唯一的区别是它只接受对象作为键名( null 除外),不接受其他类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制。
    WeakMap 最大的好处是可以避免内存泄漏。一个仅被 WeakMap 作为 key 而引用的对象,会被垃圾回收器回收掉。
    WeakMap 拥有和 Map 类似的 set(key, value) 、get(key)、has(key)、delete(key) 和 clear() 方法, 没有任何与迭代有关的属性和方法。

    16.http和https的基本概念?

    http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
    https: 是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
    https协议的主要作用是:建立一个信息安全通道,来确保数组的传输,确保网站的真实性。

    17.git fetch和git pull的区别?

    git pull:相当于是从远程获取最新版本并merge到本地
    git fetch:相当于是从远程获取最新版本到本地,不会自动merge

    18.介绍一下对浏览器内核的理解?

    主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
    渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、
    整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。
    浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。
    所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
    JS引擎则:解析和执行javascript来实现网页的动态效果。
    最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。

    19.什么是微格式

    微格式(Microformats)是一种让机器可读的语义化XHTML词汇的集合,是结构化数据的开放标准。
    是为特殊应用而制定的特殊格式
    优点:将智能数据添加到网页上,让网站内容在搜索引擎结果界面可以显示额外的提示。

    20.数据绑定基本的实现

    // 实现一个方法,可以给 obj 所有的属性添加动态绑定事件,当属性值发生变化时会触发事件
    let obj = {
      key_1: 1,
      key_2: 2
    }
    function func(key) {
      console.log(key + ' 的值发生改变:' + this[key]);
    }
    bindData(obj, func);
    obj.key_1 = 2; // 此时自动输出 "key_1 的值发生改变:2"
    obj.key_2 = 1; // 此时自动输出 "key_2 的值发生改变:1"

    答案:

    function bindData(obj, fn) {
      for (let key in obj) {
        Object.defineProperty(obj, key, {
          set(newVal) {
            if (this.value !== newVal) {
              this.value = newVal;
              fn.call(obj, key);
            }
          },
          get() {
            return this.value;
          }
        })
      }
    }

    20.数据结构处理

    // 有一个祖先树状 json 对象,当一个人有一个儿子的时候,其 child 为其儿子对象,如果有多个儿子,child 为儿子对象的数组。
    
    请实现一个函数,找出这个家族中所有有多个儿子的人的名字(name),输出一个数组。
    
    列子:
    // 样例数据
    let data = {
      name: 'jack',
      child: [
        { name: 'jack1' },
        {
          name: 'jack2',
          child: [{
            name: 'jack2-1',
            child: { name: 'jack2-1-1' }
          }, {
            name: 'jack2-2'
          }]
        },
        {
          name: 'jack3',
          child: { name: 'jack3-1' }
        }
      ]
    }
    
    
    答案:
    
    用递归
    function findMultiChildPerson(data) {
      let nameList = [];
    
      function tmp(data) {
        if (data.hasOwnProperty('child')) {
          if (Array.isArray(data.child)) {
            nameList.push(data.name);
            data.child.forEach(child => tmp(child));
          } else {
            tmp(data.child);
          }
        }
      }
      tmp(data);
      return nameList;
    }
    
    不用递归
    function findMultiChildPerson(data) {
      let list = [data];
      let nameList = [];
    
      while (list.length > 0) {
        const obj = list.shift();
        if (obj.hasOwnProperty('child')) {
          if (Array.isArray(obj.child)) {
            nameList.push(obj.name);
            list = list.concat(obj.child);
          } else {
            list.push(obj.child);
          }
        }
      }
      return nameList;
    }
  • 相关阅读:
    cl编译器命令行调试问题
    西电计算机专业培养
    GCN代码实现
    GCN介绍
    cpu密集型任务及IO密集型任务,GIS,多进程及多线程
    骨架提取
    视频文件的一些属性
    空洞填充
    凸包,二值图家矩形框
    RGB图片取大于阈值部分
  • 原文地址:https://www.cnblogs.com/lhh520/p/10362351.html
Copyright © 2020-2023  润新知