-
let不会导致变量提升 let 声明的变量不属于window属性 let 可以解决重复定义的问题, var 可以被重复声明 let 会存在暂时性死区 -
const 常量(地址不变即可) -
// ... 展开运算符 运用于对象数组 -
深拷贝、浅拷贝 1、...只能拷贝一层 2、Object.assign 等价于 ... 3、Json.parse(Json.Stringify())。 缺陷: 不能转换: 函数、正则, undefined。。。 会自动过滤 4、自己实现深拷贝的方法:(递归)自己实现深拷贝的方法:(递归)
// 掌握类型判断 typeof instanceof Object.prototype.toString.call constructor function deepClone(obj, hash = new WeakMap ()) { // 增加hash解决循环遍历的问题 // 判断obj是null还是undefined if (obj) return obj if (obj instanceof Date) return new Date(obj) if (obj instanceof RegExp) return new RegExp(obj) // 不是obj直接return if (typeof obj !== 'object') return obj if (hash.has(obj)) return hash.get(obj) // 如果weakmap中有对象就直接返回 // 判断是否是数组 // Object.prototype.toString.call(obj) === ['Object Array'] ? [] : {} let clone = new obj.constructor // 如果是对象放到weakMap中, 如果在拷贝这个对象 这个对象就存在了 直接返回这个对象即可 hash.set(obj, clone) for (let key in obj) { if (obj.hasOwnProperty(key)) { clone[key] = deepClone(obj[key], hash) } } return clone } -
set、map set 可添加删除,并且没有顺序 set 并集、交集、差集 map 是有key的, 不能放重复的 WeakMap 的key 必须是对象类型 WeakMap 不会占用空间 会销毁 map会占用空间 -
Object.defineProperty (es5): Object.defineProperty 不支持数组的更新 Object.defineProperty 只能用在对象上, 数组也不识别 vue 的数据劫持 (把所有的属性都改成 get 和set 方法) 通过Object.defineProperty定义的属性 可以增加拦截器,默认是隐藏属性,不可枚举// vue 的数据劫持 (把所有的属性都改成 get 和set 方法) function update () { console.log('更新视图') } function observer (obj) { if (typeof obj !== 'object') return obj for (let key in obj) { defineReactive(obj, key, obj[key]) } } function defineReactive (obj, key, value) { observer(value) Object.defineProperty(obj, key, { get () { return value }, set (val) { if (val !== value) { observer(val) // 检测新值 update() // 更新视图 value = val } } }) } observer(date) let methods = ['push', 'slice', 'pop', 'sort', 'reverse', 'unshift'] // 重写这几个方法,并加上自己的逻辑 methods.forEach(method => { // 面向切面开发 装饰器: 在原有的基础上加上自己的逻辑 let oldMethod = Array.prototype[method] Array.prototype[method] = function () { update() oldMethod.call(this, ...arguments) } }) Vue.prototype.$set = function(obj, key, callback) { Object.defineProperty(obj, key,{ get: callback }) }let obj = {} Object.defineProperty(obj, 'name', { enumerable: true, configurable: true, // 能否删除此属性 writable: true, // 是否可以重写 // 拦截器 get () { return 123 }, set () { } }) -
箭头函数 没有this, 没有argumentslet a = 1 let obj = { a: 2, fn: function () { // this = obj setTimeout(() => { console.log(this.a) // 2 }) } } obj.fn() //////////////////////////// let a = 1 let obj = { a: 2, fn: () => { // this = obj setTimeout(() => { console.log(this.a) // undefined }) } } obj.fn() -
js 中有this的情况 1、 { let ...} // 花括号配合着let 2、全局作用域 3、 函数作用域 -
proxy 数据劫持// 希望数组变化时就能更新视图 function update() { console.log('更新视图') } let arr = [1,2,3] // proxy 要与 Reflect配合使用 let proxy = new Proxy(arr, { set (target, key, value) { // 不要手动操作原数组, 因为数组变化时可能会调用push、pop方法, 此时key就会出现问题 if (key === 'length') return true return Reflect.set(target, key, value) // 成功返回true 失败返回false }, get (target, key) { return Reflect.get(target,key) } } -
数组的方法 : es5( forEach, reduce, map, filter, some, every) es6 (find, findIndex) es7(includes) reduce 收敛// reduce 收敛 let r = [1,2,3,4,5].reduce((a, b) => { return a+b }) console.log(r) // 15 let keys = ['name', 'age'] let values = ['yx', 18] let obj = keys.reduce((a, b, index, current) =>{ a[b] = values[index] return a },{}) console.log(obj) /////////// let keys = ['name', 'age'] let values = ['yx', 18] let obj = keys.reduce((a, b, index, current) =>(a[b] = values[index], a),{}) // 逗号运算符:只返回最后一项 console.log(obj) -
compose方法(组合多个函数)
function sum (a,b) {
return a+b
}
function toUpper (str) {
return str.toUpperCase()
}
function add (str) {
return `***${str}***`
}
// 第一种写法
function compose (...fns) {
return function (...args) {
// 获取最后一个函数
let lastFn = fns.pop()
// 倒着执行
return fns.reduceRight((a, b) => { // fns中的函数从右向左执行
return b(a)
}, lastFn(...args))
}
}
// 第二种写法
function compose(...fns) {
return fns.reduce((a, b) => {
return (...args) => {
return a(b(...args))
}
})
}
- es6中的类
-
了解构造函数的属性
属性分为两种 实例上的属性 公有属性
function Animal (name) { this.name = name this.arr = [1,2,3] } Animal.prototype.address = { location: 'ali'} let a1 = new Animal('猴子') let a2 = new Animal('小鸡') console.log(a1.arr === a2.arr) // false console.log(a1.address === a2.address) // true // 每个实例都有一个__proto__指向所属类的原型 console.log(a1.__proto__ === Animal.prototype) // true console.log(a1.prototype === Animal) // true console.log(Animal.__proto__ === Function.prototype) // true console.log(a1_proto__.__proto__=== Object.prototype) // true console.log(Object.prototype=== null) // true- 类的继承
-
// es5的写法
function Animal (name) {
this.name = name
this.eat = '吃肉'
}
Animal.prototype.address = { location: 'ali'}
function Tiger (name) {
this.name = name
this.age = 10
Animal.call(this) // Tiger继承Animal实例上的属性
}
// 继承父类的公共属性或方法
// 思路:先找自己原型上的属性,没有再去找父类身上的属性
// 方法一、
Tiger.prototype.__proto__ = Animal.prototype
// 方法二
Tiger.prototype = Object.create(Animal.prototype)
Tiger.prototype.say = function () {
console.log('说话')
}
// 继承父类实例上的属性
let tiger = new Tiger()
console.log(tiger.eat)
// es6写法
class Animal {
static flag = 123 // es6 不支持这种写法, es7支持
// 可改造成. es6 不支持静态属性, 只支持静态方法
static flag () {
return 123
}
constructor (name) {
this.name =name
this.eat = '吃肉'
}
say () {
console.log('say', this) // es6规范里: 如果单独调用原型上的方法 this是不存在的
}
}
// 类不能当做函数调用
let animal = new Animal()
animal.say()
// 错误写法
// let say = animal.say
// say()
// 继承
class Tiger extends Animal { // 实例+原型
}
let tiger = new Tiger('王老虎')
console.log(Tiger.flag()) // 静态方法可以被继承
- es6中的装饰器 npx是node 5.2以上版本提供的,帮助我们执行.bin目录下的文件
@babel/core babel的核心包 主要用于代码转化
@babel/preset-env es6转换器(只能转化es6已定案的标准)
@babel/plugin-proposal-class-properties 主要的作用是用来转化类的属性
装饰器可以修饰类,包括类的属性 类的原型上的方法。修饰的时候,就是 把这个类 属性... 传递给修饰的函数
装饰器的写法:@
@flag
class Animal {
@readonly
name = 'xxx'
@before
say (a, b, c) {
console.log('说话', a, b, c)
}
}
function flag (constructor) {
constructor.type = 'aaa'
}
// 装饰属性
function readonly (target, property, descriptor) {
descriptor.writable = false
}
// 装饰方法
function before (target, property, descriptor) {
let oldSay = descriptor.value
descriptor.value = function () {
console.log('before')
oldSay.call(target)
}
}