刷前端面经笔记(八)

发布时间:2019-08-11 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了刷前端面经笔记(八)脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

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

三者都可以把一个函数应用到其他对象上,apply,call是直接执行函数调用bind是绑定,执行需要再次调用。
applycall的区别是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,hasOwnPropertypropertyIsEnumerable

Object.defineProperty(obj,prop,descriptor)用来给对象定义属性,有value,wrITeable,enumerable,set/get,configurable
hasOwnProperty用于检查某一属性是不是存在于对象本身,
propertyIsEnumerable用来检测某一属性是否可遍历,也就是能不能用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上(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统一管理。

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引擎速度非常快
对于游戏来说,写一遍游戏逻辑代码,前端后端通用
缺点:
node.js更新很快,可能会出现版本兼容
node.js还不算成熟,还没有大制作
node.js不像其他的服务器,对于不同的链接,不支持进程和线程操作

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.vuejsAngularjs以及react的区别?

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

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.WeakMapMap 的区别?

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;
}

刷前端面经笔记(八)

脚本宝典总结

以上是脚本宝典为你收集整理的刷前端面经笔记(八)全部内容,希望文章能够帮你解决刷前端面经笔记(八)所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。