这些前端技巧,让团队成员刮目相看(一)

78 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

1. let仅在作用域有效,而 var 全局作用域,

表现上面就是在定义之前打印变量,var 的结果是 undefined 而 let 会报错ReferenceError

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

暂时性死区 块级作用域类用 let 声明的所有变量的作用域都在代码块范围内。即使外面定义同名 var 变量 )

var a = 100
if (a === 100) {
    typeof a; // ReferenceError
    a = 88 // ReferenceError
    let a; // 此例子中对于 const 也是一样的
}

条件判断语句,和 for 循环判断语句里面,判断语句(就是圆括号里面的 a=== 100 i< 100; i++之类的)的变量都是父作用域,函数体里面都是子作用域 且圆括号里面变量默认都是 let 类型 报错:bar(x = y, y = 2) {} eg: for 语句里面的变量 i 是父作用域 循环函数体里面i是子作用域

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}

对于函数默认值,函数参数是独立作用域

var x = 1;
function f(x, y = x) {
  console.log(y);
}
f(2) // 2


//=====================
var x = 1;
function f(z, y = x) {
    console.log(y);
}
f(2) // 1

//=====================


var x = 1;
function test(x = x) {
   console.log(x)
}
test()// // 会报错 ReferenceError
test(2)// 2

2. const定义‘常量’,只是引用地址不变,值无法保证,基础类型的不可变,引用类型(数组[],对象{})的值可能发生变化

// good
const a = 1;
const b = 2;
const c = 3;
// best
const [a, b, c] = [1, 2, 3];

3. 结构 '='表示默认值 ':'表示重命名。

const data = { id: '232323' }
var {id: orderId = '777' } = data || {}; // 如果 data 有值,取orderId也就是 data.id的值, 如果 data 没值取orderId即data.id的值就是默认值'777'
orderId // 3

数组特殊的对象,字符串也是特殊的数组(数组很多属性字符串都具备)。 所以字符串也能结构,和数组一样一一对应。

const [a,b] = '你好';  a// 你, b//好

变量值交换可以

[x, y] = [y, x];

函数参数必传判断


function throwIfMissing(paramName) {
  throw new Error(`${paramName} 为必传参数!`);
}
function foo(params = throwIfMissing('params')) { // 同样也可以给默认值设置 undefined, 给调用方说明可以省略
    
}
foo()
// Error: Missing parameter

4.isFinite()isNaN()

isFinite() 和 isNaN() 的区别在于,传统方法先调用 Number () 将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,Number.isFinite() 对于非数值一律返回 false,Number.isNaN() 只有对于 NaN 才返回 true,非 NaN 一律返回 false

Math.trunc(a) // 返回一个数的整数部分 Math.sign(a) // 判断是正数还是负数,还是 0 返回 0 1 -1

5. 箭头函数不能使用 yield

不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

Array.from第二个参数类似于 map Array.from(arrayLike, x => x * x); // 等同于 Array.from(arrayLike).map(x => x * x);

// 将3号位复制到0号位 [1, 2, 3, 4, 5].copyWithin(0, 3, 4)// 从 0 位开始替换,替换内容为数组的第三位到第四位(含头不含尾) // [4, 2, 3, 4, 5]

6. find 找到数组中第一个满足条件的元素,找到后不再继续,在筛选唯一一个数据的时候可以替换 filter

/**
 * @param1 回调函数,参数中 arr 表示原数组
 * @param2 obj 绑定 this 对象
 * */
array.find((item, index, arr) => {}, obj)

const abc = [10, 12, 26, 15].find(
    function f(v){ //箭头函数会改变 this 指向
       return v > this.age;
       } , { age: 10 });    // 26


flat() 将二维数组拉平,只会拉平一层

[1, 2, [3, [4, 5]]].flat() // [1, 2, 3, [4, 5]]  flat(2)即拉平两层

7. 链判断运算符 ?. ES2020

const firstName = (obj
  && obj.body
  && obj.body.user
  && obj.body.user.firstName) || 'default';

等同于
const firstName = obj?.body?.user?.firstName || 'default';



a?.b
// 等同于
a == null ? undefined : a.b
a?.[x]
// 等同于
a == null ? undefined : a[x]
a?.b()
// 等同于
a == null ? undefined : a.b()
a?.()
// 等同于
a == null ? undefined : a()

8. ?? 福音啊

// price 字段 undefined 或者 null 或者''的时候用--代替,假如为 0 呢
const realPrice = obj.price || '--'
const shouldNotReload = obj.shouldNotReload || true

?? 只有运算符左侧的值为null或undefined时,才会返回右侧的值。

const animationDuration = response.obj?.price ?? '--'; //如果response.obj存在,取 obj.price 字段,如果返回undefined 或者 null 则赋值 '--' 否则显示默认值包含 0

obj.shouldNotReload ?? true //判null undefined后给默认值 true

9. Symbol

  • enum 的常量。消除魔法字符串(也就是相同的字符串在项目中多次出现)
  • 作为对象的隐藏属性使用

Symbol作为对象的 key 时候 只能被Object.getOwnPropertySymbols()和Reflect.ownKeys()获取到,其他所有遍历都会跳过 Symbol为 key 的数据

Symbol.for("cat") 保存在全局环境中,先检查key 是否存在,存在返回。可以保证只要参数相同每次返回的都是一样 Symbol("cat") 每次调用返回值都不一样

const sym = Symbol('foo');// sym.description // "foo" const sym = Symbol.for('foo');// Symbol.keyFor(sym) // "foo"

10. Object.create

/**
 * @param proto 新创建对象的原型对象
 * @param propertiesObject 添加到新对象的属性(自身属性而不是原型属性)
 */
Object.create(proto,[propertiesObject])

使用

  • 创建一个纯净的对象

该对象不具备 Object 的任何属性,比如 toString方法等等,使用 null 参数创建的对象所有属性都是对象自身属性。for...in 遍历也不会遍历原型链对象

const a = Object.create(null)

判断对象自身是否重写了 toString 方法,必须用Object.prototype.hasOwnProperty.call(a,'toString')检查,而 null 参数创建的直接 if(a.toString)判断