注:本文通过yck前端面试小册学习整理而得,记录下来供自己查阅
1.var 变量提升
使用var声明的变量,声明会被提升到作用域的顶部
举几个例子:
eg1:
console.log(a) // undefined var a = 1
可以看做这样
var a console.log(a) a=1
eg2:
var a = 10 var a console.log(a) // 10
可以看作
var a; var a; a=10; console.log(a)
eg3,函数声明也会提升,函数提升会把整个函数挪到作用域顶部:
console.log(a) // ƒ a() {} var a = 1 function a() {}
看作:
var a; function a() {} console.log(a) // ƒ a() {} a = 1
2.var,let,const对比
1.在全局作用域下,var声明的变量,会挂载到window上,其他二者不会
2.三者都存在提升,但是let,const的提升和var不同:虽然变量在编译的环节中就被告知在这块作用域中可以访问,但是访问是受限制的(形成暂时性死区):
所以let const必须先声明后使用
var a = 1; function test1(){ console.log(a); } function test2(){ console.log(a); let a; // 执行到上一步时就已经知道该作用域内有a,所以不会再往外层作用域找,但是形成了暂时性死区,这里的a无法访问 } test1() // 1 test2() // error, a is undefined
3.let
和 const
作用基本一致,但是后者声明的变量不能再次赋值
3.模块化
3.1为什么要模块化?
1、解决命名冲突
2、易于复用
3、增强可维护性
3.2实现模块化的方法有哪些?各有什么特点?
1、立即执行函数
通过函数作用域解决了命名冲突和污染全局作用域的问题
return出对外接口
(function(val){ function aaaa (){} return { a: aaaa } })(value)
2.CMD和AMD
// AMD 异步加载模块 define(['./a', './b'], function(a, b) { // 加载模块完毕可以使用 a.do() b.do() }) // CMD define(function(require, exports, module) { // 加载模块 // 可以把 require 写在函数体的任意地方实现延迟加载 var a = require('./a') a.doSomething() })
3.CommonJS 仍在广泛使用
关键字 require module.exports
// a.js module.exports = { a: 1 } // or exports.a = 1 // b.js var module = require('./a.js') module.a // -> log 1
4.ES Module
// 导出模块 API export default function() {} // a.js 整块导出 export function b() {} // b.js 导出多个部分,每块有自己的名字 // 引入模块 API import X from './a.js' import { b } from './b.js'
4.Proxy
let proxy = new Proxy(target, handler)
拦截,代理。用于自定义对象中的操作
vue3.0中用Proxy来代替原有的Object.defineProperty来实现数据响应式
简版例子
// 用Reflect上的静态方法确保原有的set,get行为,用setBind, getLogger部署额外的监听功能 let onWatch = (obj, setBind, getLogger) => { let handler = { get(target, property, receiver) { getLogger(target, property) return Reflect.get(target, property, receiver) }, set(target, property, value, receiver) { setBind(value, property) return Reflect.set(target, property, value) } } return new Proxy(obj, handler) } let obj = { a: 1 } let p = onWatch( obj, (v, property) => { console.log(`监听到属性${property}改变为${v}`) }, (target, property) => { console.log(`'${property}' = ${target[property]}`) } ) p.a = 2 // 监听到属性a改变 p.a // 'a' = 2
5.数组方法map, filter, reduce
map:生成新数组。遍历原数组,将原数组的每个元素拿出来做出一些变换后,放入新数组并返回
filter:生成新数组。遍历原数组时,将返回值为true的元素放入新数组,并返回。用于删除一些不需要的元素
它们都接收三个参数:当前元素,索引,原数组
reduce:累加器
const arr = [1, 2, 3] const sum = arr.reduce((acc, current,index,arr) => acc + current, 0) console.log(sum) // 6
const reduceArray = arr.reduce((acc, current) => { acc.push(current * 2) return acc }, []) console.log(mapArray, reduceArray) // [2, 4, 6]
reduce接收两个参数:回调函数和初始值
回调函数有4个参数:累计值(不限数据类型),当前元素,当前索引,原数组