注:本文通过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) //
可以看作
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() //
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) //
const reduceArray = arr.reduce((acc, current) => {
acc.push(current * 2)
return acc
}, [])
console.log(mapArray, reduceArray) // [2, 4, 6]
reduce接收两个参数:回调函数和初始值
回调函数有4个参数:累计值(不限数据类型),当前元素,当前索引,原数组