以下问题都来自于互联网前端面经分享, 回答为笔者通过查阅资料加上自身理解总结, 不保证解答的准确性, 有兴趣讨论的同学可以留言或者私信讨论.
1.JS 的异步机制?
2. 闭包如何实现?
3. 原型链, 继承?
4. 实现订阅者发布者模式?
5. 数组的方法有哪些?
1.JS 的异步机制?
JS 使用一个任务队列记录异步任务的回调函数, 当异步任务 (或者事件被激发, 如鼠标点击) 完成后, 其回调函数会被添加到该任务队列的末尾, JS 主线程在将所有的同步任务执行完毕后, 会无限循环地去检查任务队列, 如果任务队列不为空, 则主线程回去执行任务队列中的任务.
关于异步机制的详细解答, 可以参考: Javascript 异步机制
2. 闭包如何实现?
在计算机科学中, 闭包是引用了自由变量的函数. 在 Javascript 中, 在一个函数中定义一个内部函数, 并且内部函数引用了外部函数作用域的变量, 然后将这个内部函数作为外部函数的返回值, 这样就构成了一个闭包. 如下代码:
- function wrapper() {
- var milk = '特仑苏'
- function drink() {
- console.log('我喝了' + milk)
- }
- return drink
- }
- var result = wrapper()
- result() // 我喝了特仑苏
关于闭包的详细解答, 可以参考: Javascript 闭包
3. 原型链, 继承?
在 Javascript 中, 每当我们定义一个函数, Javascript 引擎就会自动为这个函数对象添加一个 prototype 属性(也被称作原型), 每当我们使用这个函数 new 创建一个对象时, Javascript 引擎就会自动为这个对象中添加一个__ proto __ 属性, 并让其指向其类的 prototype. 当我们访问一个对象的属性时, 首先回去寻找该对象本身的属性, 如果找不到的话回去寻找该对象的 __ proto __ 作用域下的属性, 一直到寻找到该属性或者没有__ proto __为止. 这种寻找实例属性的方式我们称作原型链.
当我们让子类的 prototype 指向父类的实例时, 便实现了原型链继承.
- // 原型链实现继承的关键代码
- Son.prototype = new Father()
当然 Javascript 的继承方式还有 构造函数继承 , 组合继承 , 寄生继承, 更详尽的解答, 可以参考: 对 Javascript 类, 原型链, 继承的理解
4. 实现订阅 / 发布者模式?
- var publisher = {}; // 定义发布者
- publisher.list = []; // 缓存列表 存放订阅者回调函数
- // 增加订阅者
- publisher.listen = function(fn) {
- publisher.list.push(fn); // 订阅消息添加到缓存列表
- }
- // 发布消息
- publisher.trigger = function(){
- for(var i = 0,fn; fn = this.list[i++];) {
- var that = this
- fn.apply(null, arguments);
- }
- }
详细答案可以参考: Javascript 中理解发布 -- 订阅模式 https://www.cnblogs.com/tugenhua0707/p/4687947.html
5. 数组的方法有哪些?
这个题属于开放题, 答案就比较多了, 下面我列举一下比较常用的数组方法:
遍历方法:
包括 map,foreach,filter
- let arr = [{
- name:"西瓜",
- type:"水果"
- },{
- name:"芒果",
- type:"水果"
- },{
- name:"小龙虾",
- type:"夜宵"
- }]
- arr.forEach((item, index) => {
- console.log(item.name)
- }) // 分别打印 西瓜 芒果 小龙虾
- arr.map((item, index) => {
- return item.name
- }) // 返回数组["西瓜", "芒果", "小龙虾"]
- arr.filter((item, index) => {
- if (item.type == "水果")
- return true;
- else
- return false;
- }) // 返回数组[{ name: 西瓜, type : 水果 }, { name: 芒果, type : 水果 }]
forEach: 用于遍历数组, 无返回值;
map: 遍历数组之后, 对每一项返回一个值, 并将这些返回值都推入一个数组, 最后返回这个新的数组;
filter: 对数据进行过滤, 回调函数返回值为 false 的项将被过滤掉, 最后返回过滤后的数组.
操作方法:
包括 concat,push,pop,unshift,shift,splice
- let listA = ["西瓜", "芒果"]
- let listB = ["小龙虾"]
- let listC = listA.concat(listB)
- // 返回值:[西瓜, 芒果, 小龙虾]
- listC.push("鸡腿")
- // 返回值: 4
- // 数组值:[西瓜, 芒果, 小龙虾, 鸡腿]
- listC.pop()
- // 返回值:"鸡腿"
- // 数组值:[西瓜, 芒果, 小龙虾]
- listC.unshift("鸡腿")
- // 返回值: 4
- // 数组值:[鸡腿, 西瓜, 芒果, 小龙虾]
- listC.shift()
- // 返回值:"鸡腿"
- // 数组值:[西瓜, 芒果, 小龙虾]
- listC.splice(1, 1, "冰激凌", "奶茶")
- // 返回值:[芒果]
- // 数组值:[西瓜, 冰激凌, 奶茶, 小龙虾]
concat: 拼接数组, 将参数数组拼接到调用数组末尾, 并返回这个新数组; 值得一提的是, 这个方法并不会改变调用数组和参数数组, 即上例中的 listA,listB);
push: 在数组尾部插入新的元素, 返回插入元素之后的数组长度;
pop: 从数组尾部删除元素, 返回删除的元素;
unshift: 在数组头部插入新的元素, 返回插入元素之后的数组长度;
shift: 从数组头部删除元素, 返回删除的元素;
splice: 删除元素并插入元素, 第一个参数为操作位置 X, 第二个参数为需要从操作位置 X 删除元素数量, 后面的参数为需要从操作位置 X 插入的元素, 返回删除的元素组成的数组.
来源: http://www.jianshu.com/p/4fe5433b578d