1.apply,call,bind有什么区别?javascript
三者均可以把一个函数应用到其余对象上,apply,call是直接执行函数调用,bind是绑定,执行须要再次调用。 html
apply和call的区别是apply接受数组做为参数,而call是接受逗号分隔的无限多个参数列表。前端
代码以下:vue
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都是作什么用的?java
Object.defineProperty(obj,prop,descriptor)用来给对象定义属性,有value,writeable,enumerable,set/get等,node
hasOwnProperty用于检查某一属性是否是存在于对象自己,react
isEnumerable用来检测某一属性是否可遍历,也就是能不能用for...in循环来取到。git
3.JS经常使用设计模式的实现思路(单例、工厂、代理、装饰、观察者模式等)angularjs
// 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.字符串经常使用的十个函数ajax
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; }