闭包闭包是Javascript中的一项重要技术,内部函数始终可以访问其外部函数的变量和参数,即使在外部函数返回后也是如此。我们使用闭包来保护我们不想向外部范围公开的数据。 //<button onclick=”increaseCounter()”>Increase Counter</button>//1. 全局变量,变量会被意外修改let counter = 0;function increaseCounter() { counter++;}//2. 局部变量,每次调用都重置为0function increaseCounter() { let counter = 0; counter++;}//3. 闭包函数,符合要求const increaseCounter = (function() { let counter = 0; return function() { counter = counter + 1; console.log(counter); };})(); 函数绑定在上下文丢失时,this将无法被确定,可以通过函数绑定解决。
使用命名空间使用命名空间可以防止代码冲突。 // 1. move、jump函数在animal命名空间下,需要通过animal.move()来调用let animal = { move: () => { console.log('Move!’); }, jump: () => { consle.log('Jump!’); }};// 2. 真实项目中,可能会按如下方式使用命名空间if (typeof APP === 'undefined') { APP = {}; APP.ANIMAL = {};}APP.ANIMAL.move = () => { console.log('Move’);};APP.ANIMAL.jump = () => { console.log('Jump’);};APP.ANIMAL.move(); // MoveAPP.ANIMAL.jump(); // Jump 判断属性是否存在使用in关键字可以判断对象中是否存在某个属性。
解构赋值利用解构赋值表达式,可以将属性、值从对象、数组中取出,赋值给其它变量,非常方便。 const { address: addressLine } = { address: '长安街20号', postcode: '518118' };console.warn(addressLine); // 长安街20号const [first, second] = [1, 2, 3, 4]console.warn(first, second) // 1 2//动态解构const extractKey = 'postcode'const { [extractKey]: youbian } = { address: '长安街20号', postcode: '518118' };console.log(youbian) //518118 遍历对象属性使用Object.entries可以遍历对象的属性和值。
过滤数组利用数组的filter、some对数组进行筛选。 const fruits = ['apple', null, 'mongo', undefined, '']const filted = fruits.filter(Boolean)console.debug(filted) //(2) ['apple', 'mongo']const any = fruits.some(Boolean)console.log(any) //true 消除重复值
判断是否数组利用Array.isArray,而不是typeof判断。 const fruits = ['apple', null, 'mongo', 'apple', '']console.debug(typeof fruits) //objectconsole.error(Array.isArray(fruits)) //true 转换数字和字符串
转换为boolean利用!!运算符可以将其它类型转换为Boolean类型。 console.log(!!null, typeof(!!null)) //false, booleanconsole.log(!!'', typeof(!!'')) //false, booleanconsole.log(!!undefined, typeof(!!undefined)) //false, booleanconsole.log(!!null, typeof(!!null)) //false, booleanconsole.log(!!true, typeof(!!true)) //true, booleanconsole.log(!!false, typeof(!!false)) //false, booleanconsole.log(!!{id:'', name:''}, typeof(!!{id:'', name:''})) //true, boolean 可选链可选链 ?. 是一种访问嵌套对象属性的安全的方式,可避免在对象或属性不可用时抛出异常。由于JavaScript不是类型化语言,该特性还是很有用。
合并运算符合并运算符的写法为两个问号 ??,对于该运算符连接的两个参数,如果第一个参数不是 null,也不是undefined,则返回第一个参数,否则返回第二个参数。 const contactInfos = { address: '长安街20号' };console.warn(contactInfos.user?.phoneNumber ?? '') // ''const contactInfos = { address: '长安街20号', addressNumber: 0 };console.warn(contactInfos.addressNumber || undefined) // undefinedconsole.warn(contactInfos.addressNumber ?? undefined) // 0 有条件地添加属性使用...扩展语法,可以仅当某个条件成立时,才为对象添加某个属性。
异步调用异常捕获以下写法让处理异步调用异常的代码变得更为简洁。 const results = await getPosts().catch((err) => { return { type: 'error', message: err.message }});console.warn(results) // { type: 'error', message: 'cannot get posts from this endpoint' } 弱引用MapWeakmap不同于Map,它的键必须是引用对象,不能是基础类型,如果没有对该键对象引用时,该对象将被从Map和内存中移除。
反射Reflect是一个全局对象,它为元编程提供了一些有用的静态方法。 const person = { name: 'Bob', [Symbol('email')]: 'bob@evil.com' };Reflect.get(person, 'name'); // = BobReflect.has(person, 'email'); // = trueReflect.has(person, 'phone'); // = falseReflect.getPrototypeOf(person); // = { constructor ... }Reflect.getOwnPropertyDescriptor( person, 'name'); // = { value: 'Bob', writable: true, enumerable: true, configurable: true }Reflect.ownKeys(person); // name, Symbol(email)Reflect.defineProperty(person, 'phone', { writable: true });Reflect.has(person, 'phone'); // = trueReflect.set(person, 'phone', '123456789');Reflect.deleteProperty(person, 'phone');Reflect.has(person, 'phone'); // = false 柯里化柯里化(Currying)是一种关于函数的高阶技术,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。柯里化不会调用函数,它只是对函数进行转换。
组合组合是一种技术,其中一个函数的结果被传递到下一个函数,该函数被传递到下一个函数,依此类推......直到执行最终函数并计算出一些结果。函数组合可以由任意数量的函数组成。 //f 和 g 都是函数,x 是在它们之间通过“管道”传输的值var compose = function(f,g) { return function(x) { return f(g(x)); };};var toUpperCase = function(x) { return x.toUpperCase(); };var exclaim = function(x) { return x + '!'; };var shout = compose(exclaim, toUpperCase);shout('send in the clowns'); //=> 'SEND IN THE CLOWNS!'
|
|