刷前端面经笔记(八)

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

三者均可以把一个函数应用到其余对象上,apply,call是直接执行函数调用,bind是绑定,执行须要再次调用。
applycall的区别是apply接受数组做为参数,而call是接受逗号分隔的无限多个参数列表。
代码以下:javascript

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, propertyIsEnumerable

Object.defineProperty(obj,prop,descriptor)用来给对象定义属性,有value,writeable,enumerable,set/get,configurable
hasOwnProperty用于检查某一属性是否是存在于对象自己,
propertyIsEnumerable用来检测某一属性是否可遍历,也就是能不能用for...in循环来取到。html

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上(Parent.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的理解

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

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(销毁后)在实例销毁以后调用。调用后,全部的事件监听器会被移除,全部的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。java

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

优势:
事件驱动,经过闭包很容易实现客户端的生命活期。
不用担忧多线程,锁,并行计算的问题
V8引擎速度很是快
对于游戏来讲,写一遍游戏逻辑代码,前端后端通用
缺点:
node.js更新很快,可能会出现版本兼容
node.js还不算成熟,尚未大制做
node.js不像其余的服务器,对于不一样的连接,不支持进程和线程操做node

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

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

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

11.使用npm有哪些好处?

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

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

use strict 是一种在JavaScript代码运行时自动实行更严格解析和错误处理的方法。(严格模式)
将值分配给一个未声明的变量会自动建立该名称的全局变量。这是JavaScript中最多见的错误之一。在严格模式下,这样作的话会抛出错误。消除 this 强制。
当检测到对象(例如,var object = {foo: "bar", foo: "baz"};)中重复命名的属性,或检测到函数中(例如,function foo(val1, val2, val1){})重复命名的参数时,严格模式会抛出错误,所以捕捉几乎能够确定是代码中的bug能够避免浪费大量的跟踪时间。比eval() 更安全。angularjs

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

AngularJS的区别
相同点:
都支持指令:内置指令和自定义指令。
都支持过滤器:内置过滤器和自定义过滤器。
都支持双向数据绑定。
都不支持低端浏览器。
不一样点:
1.AngularJS的学习成本高,好比增长了Dependency Injection特性,而Vue.js自己提供的API都比较简单、直观。
2.在性能上,AngularJS依赖对数据作脏检查,因此Watcher越多越慢。
Vue.js使用基于依赖追踪的观察而且使用异步队列更新。全部的数据都是独立触发的。
对于庞大的应用来讲,这个优化差别仍是比较明显的。ajax

React的区别
相同点:
React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,二者都须要编译后使用。
中心思想相同:一切都是组件,组件实例之间能够嵌套。
都提供合理的钩子函数,可让开发者定制化地去处理需求。
都不内置列数AJAXRoute等功能到核心包,而是以插件的方式加载。
在组件开发中都支持mixins的特性。
不一样点:
React依赖Virtual DOM,而Vue.js使用的是DOM模板。React采用的Virtual DOM会对渲染出来的结果作脏检查。
Vue.js在模板中提供了指令,过滤器等,能够很是方便,快捷地操做Virtual DOM

14.标签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 engineerRendering Engine)和JS引擎。
渲染引擎:负责取得网页的内容(HTMLXML、图像等等)、
整理讯息(例如加入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;
}

欢迎关注

相关文章
相关标签/搜索