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, propertyIsEnumerable
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?(闭包)
- 这是第一条
- 这是第二条
- 这是第三条
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
引擎速度非常快对于游戏来说,写一遍游戏逻辑代码,前端后端通用缺点: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.vuejs与angularjs以及react的区别?
与AngularJS
的区别
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>
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
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;}