为了提高公司内小伙伴的前端业务水平,每个月都有一个前端的测试,以下是第一期试题以及参考答案
恒星计划第一期-前端考试
1. let const var 区别
var | let | const |
---|---|---|
函数级作用域 | 块级作用域 | 块级作用域 |
变量提升 | 不存在变量提升 | 不存在变量提升 |
值可更改 | 值可更改 | 值不可更改 |
- | 暂时性锁区特性 | 如果变量是基本数据类型,不能更改值;如果是复杂数据类型,则不能更改内存地址。 |
2. js 中 this 的指向
this 的指向,是当我们调用函数的时候指定的,调用方式的不同,决定了 this 指向的不同
调用方式 | this 指向 |
---|---|
普通函数调用 | window |
定时器函数 | window |
立即执行函数 | window |
对象方法调用 | 该方法所属的对象 |
事件绑定方法 | 绑定事件的对象 |
构造函数调用 | 实例对象,原型对象里面的方法也指向实例对象 |
3. call、apply、bind 的区别
- 不同点
- call 和 apply 会调用函数,并且改变函数内部 this 指向
- call 和 apply 传递的参数不一样,前者传递参数使用逗号隔开,apply 使用数组传递
- bind 不会调用函数,但可以改变函数内部 this 指向
- 应用场景
- call 经常做继承
- apply 经常跟数组有关,比如借助数学对象方法找出数组最大值最小值
- bind 方法执行后,返回的是原函数改变 this 指向之后的新函数,比如改变定时器内部 this 指向
3,js 中继承各自有什么特点
-
原型链继承
主要代码
Child.prototype = new Parent()
-
特点
- 引用类型的属性被所有实例共享
- 在创建子类实例时,不能向父类传参
-
构造函数继承
主要代码
function Child() { Parent.call(this) }
-
特点
- 避免了引用类型的属性被所有实例共享
- 可以在 Child 中向 Parent 传参
- 方法都在构造函数中定义,每次创建实例都会创建一遍方法
-
组合继承:以上两种继承的组合
主要代码
function Child (name, age) { Parent.call(this, name) this.age = age } Child.prototype = new Parent() Child.prototype.constructor = Child
-
特点
- 融合原型链继承和构造函数继承的优点,是最常用的继承模式
-
原型式继承
主要代码
function createObj(o){ function F() {} F.prototype = o; return new F() }
-
特点:
- 就是 Object.create 的模拟实现,将传入对象作为创建对象的原型
- 包含引用类型的属性值始终都会共享相应的值,类似原型链继承
-
寄生组合式继承
主要代码
function Child (name, age) { Parent.call(this, name) this.age = age } Child.prototype = Object.create(Parent.prototype) Child.prototype.constructor = Child
-
特点:
- 比起组合继承少调用一次 Parent 构造函数
- 引用类型最理想的继承方式
4. new 关键字的作用
- 在内存中创建一个新对象
- 该新对象会被链接到原型链上
- 把 this 指向创建出来的空对象,并执行构造函数中的代码
- 如果函数没有返回其它对象,则返回这个新对象
5. js中创建对象的方式
- 使用 new Object 创建对象
- 使用对象字面量创建对象
- 使用构造函数创建对象
6. ES6怎么定义类,以及实现类的继承
- 通过class关键字创建类
class Animal {}
- 通过 extends 关键字实现继承
class Dog extends Animal{}
7. JS中对象访问规则
- 通过 . 方式访问,如: obj.a
- 通过中括号的方式访问,如:obj['hello-world']
8. JS中构造函数和Object的原型链搜索机制
- 先从对象自身查找,找到则直接访问,结束查找
- 如果找不到则沿着原型链依次往上查找,找到则直接访问
- 如果最终来到原型链顶端,Object.prototye 还是没有找到的话则直接返回 undefined
9. 构造函数和普通函数的区别
- 本质上来说构造函数和普通函数没有任何区别
- 它们只有调用方式的不同,构造函数通过new操作符调用的时候会返回一个新对象
10. promise 主要解决了什么问题,如何一直 .then 下去
- 主要解决了无限嵌套回调地狱的问题
- promise 实例拥有的then方法,而then方法返回的结果也会被js包装成promise实例,所以能够一直 .then 下去
11. ES6 怎么实现数组去重
- Array.from(new Set(arr))
12. ES6中字符串新增了哪些方法
模板字符串
padStart, padEnd
startsWith, endsWith
includes
repeat
13. 代码实现数组从小到大排序,至少两种方式
var arr = [1,2,1,3,4] for (let i = 0; i < arr.length; i++){ for (let j = i; j < arr.length; j++){ if (arr[i] > arr[j]) { var max = arr[i] arr[i] = arr[j] arr[j] = max } } } console.log(arr)
var arr = [1,3,2,-1] var newArr = [] for (;arr.length>0;) { var min = Math.min.apply(null, arr) newArr.push(min) var index = arr.findIndex(x => x === min) arr.splice(index, 1) } console.log(newArr)
arr.sort((a, b) => a - b)
14. 使用 proxy 实现观察者模式
观察者模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
const callbacks = new Set();
const observe = fn => callbacks.add(fn)
const observable = obj => new Proxy(obj, {set})
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
callbacks.forEach(observe => observe());
return result;
}
// 一个可观察的对象
const person = observable({name: 'hui', age: 22})
function change() {
console.log(`${person.name} is ${person.age}`)
}
observe(change)
pserson.age = 33