1. 对原型和原型链的理解
- 什么是原型和原型链?
- 原型:函数中有属性,每个函数中的特殊属性(prototype)叫做原型
- 原型链:当我们访问某个属性或者方法时,如果当前对象中找不到,就会到当前对象的原型对象中查找,没有继续向上查找,直到顶层原型对象(Object.prototype),最终如果没有找到就返回undefined,这种查找过程就是链式查找,这整个链条就是原型链
- 原型和原型链存在的意义?
- 实例对象中可以共享构造函数中的属性和方法,构造函数原型中的属性和方法越多,节省内存越大
2. 对作用域和作用域的理解
- 作用域: 作用域是在运行代码中某个特定变量,函数和对象的可访问性,作用域决定了代码区块中变量和其他资源的可见性
- 作用域存在的意义: 作用域存在最大的意义是变量隔离,不同作用域下同名的变量不会有冲突问题
- 作用域链: 当我们在某个函数的内部作用域中查找某个变量,如果没有就到他的父级作用域中查找,如果父级也没有就一层层向上查找,如果最终都没有就放弃,这种一层层作用域嵌套关系就是作用域链
3. 对闭包的理解
- 闭包: 形式为函数嵌套函数,可以访问这个函数内部变量的函数
- 使用场景:
- 例如一些事件函数的封装
- 模拟私有方法
- 循环中给页面元素绑定事件响应函数
- 存在问题: 造成内部变量常驻内存
4. call、apply、bind
this 谁调用它就指向谁,而call、apply、bind用来改变this指向
- 共同点: bind, call, apply都可以改变this指向
- 不同点:
- call和apply的传参方式不同,call直接传递,apply使用数组形式
b. bind和call, apply的返回值不同,bind返回的是个函数,要指向得再调用
object.say.call(this指向的对象, 参数) object.say.apply(this指向的对象, ['参数']) const say = object.say.bind(this指向的对象, 参数); say();
- 应用:
// call应用: // * 判断数据类型 const array = [1,2,3,4]; const type = Object.prototype.toString.call(array); console.log(type) // * 类数组转数组 const arrayLike = { 0: "name", 1: "age", length: 2 } const res = Array.prototype.slice.call(arrayLike); console.log(res) // apply 给定数组求最大值/最小值 const array = [1,2,3,4,5] const max = Math.max.apply(null, array) const min = Math.min.apply(null, array) console.log(max, min) // bind react类组件事件响应函数得绑定 class App extends React.Component { constructor(props) { super(props); this.name = 'Aaron' this.handleClick = this.handleClick.bind(this) } handleClick() { console.log(this.name) } render() { return ( <button onClick="this.handleClick">点击</button> ) } }
5. 数组去重
普通数组去重
- filter + indexOf
const array = [1,2,3,4,5,3,2,1]; function unique(array) { if(!Array.isArray(array)) { throw new Error("unique function parmas is not Array") } return array.filter((item, index) => { return array.indexOf(item) === index }) }
- 相邻元素排序
const array = [1,2,3,4,5,3,2,1]; function unique(array) { array = array.sort() let res = []; for(let i = 0; i< array.length; i++) { if(array[i] !== array[i-1]) { res.push(array[i]) } } return res } const res = unique(array)
- Set + 解构赋值
function unique(array) { return [...new Set(array)] } const res = unique(array);
- Set + Array.from
function unique(array) { return Array.from(new Set(array)) } const res = unique(array);
对象数组去重
- 临时对象缓存数组项key值
const array = [{name: "Aaron", age: "20"}, {name: "Con", age: "20"}] function unique(array, key) { let result = []; let template = {} for (let i = 0; i < array.length; i++) { var keyname = array[i][key]; if(template[key]) { continue; } template[keyName] = true; result.push(array[i]) } return result; } const res = unique(array, 'age');
- reduce方法 + 缓存对象
const array = [{name: "Aaron", age: "20"}, {name: "Con", age: "20"}] function unique(array, key) { var cacheObject = {} return array.reduce((prve, current) => { cacheObject[current[key]] ? "" : cacheObject[current[key]] = true && prve.push(current) return prve; }, []) } const res = unique(array, 'age')
6. 对给定数组求最大值
- Math.max
const res = Math.max(...array) const res = Math.max.apply(null, array)
- reduce函数
function getMax(array) { return array.reduce((prev, current) => { return current > prev ? current: prev }) } const res = getMax(array);
- sort函数
function getMax(array) { const result = array.sort(); return result[result.length - 1] } const res = getMax(array);
7. 判断数据类型
- typeof
const array = []; const object = {}; const number = 1; const string = 'string'; const type = typeof number; // 优点:使用简单 // 缺点:功能残缺,只能判断: number,string, boolean, undefined, function, symbol
- Object.prototype.toString.call
const type = Object.prototype.toString.call(array); // 优点:适用于判断所有数据类型 // 缺点:使用上相对繁琐
- instanceof(用于类型排除)
//用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上 const object = {}; // true const res = object instanceof Object
8. 如何实现节流函数
- 概念: 在一个规定的单位时间内,事件函数被触发多次,只生效一次
- 应用场景: window.onresize / mousemove 等事件监听
- 函数实现:
function throttle(fn, interval) { var timer return (event) => { if(timer) { return } timer = setTimeOut(() => { fn(event) clearTimeout(timer) timer = null }, interval) } } window.onresize = throttle(function(event) { console.log(event) }, 2000)
9. 如何实现防抖函数
- 概念: 事件被触发n秒之后执行回调,如果在这n秒之内又被触发,又重新计时
- 场景: 商品搜索 / 数据查询等
- 函数实现:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="text" id="search"> <script> const s = document.getElementById('search') function debounce(fn, interval) { let timer = null return (event) => { clearTimeout(timer) timer = setTimeout(() => fn(event), interval) } } s.oninput = debounce(function(event) { const value = s.value console.log(value) }, 2000) </script> </body> </html>
10. 实现数组拍平
- 概念: 指将多维数组变成一维数组,又叫数组扁平化,数组降维
- 场景: echarts做大屏数据展示
- 实现:
- reduce函数
const array = [1,2,3,4,[5,6,[7,8]]] function flatten(array) { return array.reduce(function(prev, current) { return prev.concat(Array.isArray(current)?flatten(current):current) }, []) } const res = flatten(array)
ES6中的flat函数
const array = [1,2,3,4,[5,6,[7,8]]] function flatten(array) { return array.flat(Infinity); } const res = flatten(array)
while循环 + 扩展运算符
const array = [1,2,3,4,[5,6,[7,8]]] function flatten(array) { while(array.som(Array.isArray)) { array = [].concat(..array) } return arrray } const res = flatter(array)
11. 使判断成立
let value = 0; Object.defineProperty(window, 'a', { get() { return value += 1 } }) if(a === 1 && a === 2 && a === 3) { console.log('成立') }
12. 实现new操作符
const ObjectFactory = (...args) => { // 1.创建空对象 const obj = {} // 2.获取构造函数 const Constructor = [].shift.call(args) // 3.对象的_proto_指向Constructor.prototype obj._proto_ = Constructor.prototype // 4.用apply的方式把构造函数 Constructor的this指向obj执行Constructor var ret = Constructor.apply(obj, args) // 根据ret的执行结果判断返回构造函数的返回对象还是新创建的空对象 return typeof ret === 'object'? ret : obj }
13. 实现bind函数
Function.prototype.bindFn = function() { const fn = this const obj = arguments[0] const args = [].slice.call(arguments, 1) return function() { const returnArgs = [].slice.call(arguments) fn.apply(obj, args.concat(returnArgs)) } }
14. 实现call和apply函数
// call函数 Function.prototype.callFn = function(context, ...args) { args = args || [] const key = Symbol() context[key] = this const result = context[key](...args) delete context[key] return result }
// apply函数 Function.prototype.applyFn = function(context, args) { args = args || [] const key = Symbol() context[key] = this const result = context[key](...args) delete context[key] return result }
15. 实现instanceof
function instance_of(Obj, Constructor) { let implicitPrototype = Obj._proto_ let displayPrototype = Constructor.prototype while(true) { if(implicitPrototype === null) { return false } else if (implicitPrototype === displayPrototype) { return true } implicitPrototype = implicitPrototype._proto_ } }