• JavaScript与TypeScript总结


    一、ES6标准

    1.let、var、const

    ①let声明的变量只在let命令所在的代码块内有效。var声明的变量在全局都有效,代码块内会收到全局其他地方重复声明的影响。const将声明一个无法重复赋值的变量。

    ②var的变量提升:变量可以在声明之前使用,值为undefined。let不允许变量提升。

    ③“暂时性死区”(temporal dead zone,简称 TDZ):如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

    let不允许在相同作用域内,重复声明同一个变量。var可以。

    2.变量的解构赋值

    ①基本用法:

    let [a, b, c] = [1, 2, 3];

    ②如果解构不成功,变量的值就等于undefined

    ③解构赋值允许指定默认值。

    let [foo = true] = [];
    foo // true
    
    let [x, y = 'b'] = ['a']; // x='a', y='b'
    let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

    ④字符串的解构赋值:

    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"

    类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

    let {length : len} = 'hello';
    len // 5

    ⑤使用解构赋值交换变量的值

    let x = 1;
    let y = 2;
    
    [x, y] = [y, x];

    ⑥遍历遍历 Map 结构

    const map = new Map();
    map.set('first', 'hello');
    map.set('second', 'world');
    
    for (let [key, value] of map) {
      console.log(key + " is " + value);
    }

     3.函数的扩展

    ①利用参数默认值,可以指定某一个参数不得省略。

    function throwIfMissing() {
      throw new Error('Missing parameter');
    }
    
    function foo(mustBeProvided = throwIfMissing()) {
      return mustBeProvided;
    }
    
    foo()
    // Error: Missing parameter

    ②ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数。

    function add(...values) {
      let sum = 0;
    
      for (var val of values) {
        sum += val;
      }
    
      return sum;
    }
    
    add(2, 5, 3) // 10

    注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

    ③严格模式

    'use strict'

    ④name属性:调用XXX.name将返回这个XXX函数的函数名。

    ⑤嵌套的箭头函数

    function insert(value) {
      return {into: function (array) {
        return {after: function (afterValue) {
          array.splice(array.indexOf(afterValue) + 1, 0, value);
          return array;
        }};
      }};
    }
    
    insert(2).into([1, 3]).after(1); //[1, 2, 3]
    let insert = (value) => ({into: (array) => ({after: (afterValue) => {
      array.splice(array.indexOf(afterValue) + 1, 0, value);
      return array;
    }})});
    
    insert(2).into([1, 3]).after(1); //[1, 2, 3]

    但是,一旦不注意,可读性就会呈几何级下降。

    ⑥尾函数优化

    函数执行的时候有一个函数栈,在A函数中执行B函数,A函数的执行结果和调用点都会保存在函数栈中,因为B函数调用完会还得返回去执行A函数。当A函数的最后一步操作是执行B函数的时候,显而易见的,可以释放A函数在函数栈上的资源了。

    典型应用就是,递归函数,只要递归函数的最后一步是执行其本身,那么就会使爆栈的几率大大降低。看一个Fibonacci 数列的例子:

    function Fibonacci (n) {
      if ( n <= 1 ) {return 1};
    
      return Fibonacci(n - 1) + Fibonacci(n - 2);
    }
    
    Fibonacci(10) // 89
    Fibonacci(100) // 堆栈溢出
    Fibonacci(500) // 堆栈溢出
    function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
      if( n <= 1 ) {return ac2};
    
      return Fibonacci2 (n - 1, ac2, ac1 + ac2);
    }
    
    Fibonacci2(100) // 573147844013817200000
    Fibonacci2(1000) // 7.0330367711422765e+208
    Fibonacci2(10000) // Infinity

    遗憾的是,是否进行尾函数优化,是由编程语言跟编译器决定的。ES6支持,但是比如JAVA就不支持这个东西(JAVA不建议使用递归)。

    4.数组的扩展

    ①扩展运算符“...”

    将一个数组转为用逗号分隔的参数序列。

    console.log(1, ...[2, 3, 4], 5)
    // 1 2 3 4 5
    // 可与其他参数一起使用
    
    [...document.querySelectorAll('div')]
    // [<div>, <div>, <div>]
    
    
    function add(x, y) {
      return x + y;
    }
    
    const numbers = [4, 38];
    add(...numbers) // 42

    注意,扩展运算符如果放在括号中,JavaScript 引擎就会认为这是函数调用。如果这时不是函数调用,就会报错。

    由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。

    还可以赋值数组:const a2 = [...a1];

    还可以合并数组:const a4 = [...a1, ...a2];

    还可以将字符串转为真正的数组:const a5 = [...'hello'] (任何定义了遍历器Iterator接口的对象,都可以用扩展运算符转为真正的数组。)

    Map 和 Set 结构,Generator 函数都可以使用扩展运算符,比如 Map 结构:

    let map = new Map([
      [1, 'one'],
      [2, 'two'],
      [3, 'three'],
    ]);
    
    let arr = [...map.keys()]; // [1, 2, 3]

    5.对象的扩展

    ①ES6 允许直接写入变量和函数,作为对象的属性和方法(只要你有一个引用,你甚至可以包括整个宇宙)。

    let birth = '2000/01/01';
    
    const Person = {
    
      name: '张三',
    
      //等同于birth: birth
      birth,
    
      // 等同于hello: function ()...
      hello() { console.log('我的名字是', this.name); }
    
    };
    function getPoint() {
      const x = 1;
      const y = 10;
      return {x, y};
    }
    
    getPoint()
    // {x:1, y:10}

    ②属性遍历

    ES6 一共有 5 种方法可以遍历对象的属性。官方推荐使用Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

    遍历对象的键名,都遵守同样的属性遍历的次序规则。

    • 首先遍历所有数值键,按照数值升序排列。
    • 其次遍历所有字符串键,按照加入时间升序排列。
    • 最后遍历所有 Symbol 键,按照加入时间升序排列。

    Object.assign方法

    Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。但是,Object.assign方法实行的是浅拷贝,而不是深拷贝。

    const target = { a: 1 };
    
    const source1 = { b: 2 };
    const source2 = { c: 3 };
    
    Object.assign(target, source1, source2);
    target // {a:1, b:2, c:3}

    同样的操作也可以进行对象克隆

    function clone(origin) {
      let originProto = Object.getPrototypeOf(origin);
      return Object.assign(Object.create(originProto), origin);
    }

    为对象添加属性

    class Point {
      constructor(x, y) {
        Object.assign(this, {x, y});
      }
    }

    为对象添加方法

    Object.assign(SomeClass.prototype, {
      someMethod(arg1, arg2) {
        ···
      },
      anotherMethod() {
        ···
      }
    });
    
    // 等同于下面的写法
    SomeClass.prototype.someMethod = function (arg1, arg2) {
      ···
    };
    SomeClass.prototype.anotherMethod = function () {
      ···
    };

    6.Symbol变量

    ①Singleton 模式

    // mod.js
    const FOO_KEY = Symbol.for('foo');
    
    function A() {
      this.foo = 'hello';
    }
    
    if (!global[FOO_KEY]) {
      global[FOO_KEY] = new A();
    }
    
    module.exports = global[FOO_KEY];
    const a = require('./mod.js');
    console.log(a.foo);

    这同时也是全局变量的设置方案,唔。

    7.Set 变量

    ①成员的值都是唯一的,没有重复的值。四大方法:add、delete、has、clear。

    Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

    // 例一
    const set = new Set([1, 2, 3, 4, 4]);
    [...set]
    // [1, 2, 3, 4]

    ③利用Set给数组去重

    // 去除数组的重复成员
    [...new Set(array)]

    给字符串去重

    [...new Set('ababbc')].join('')
    // "abc"

    Array.from方法可以将 Set 结构转为数组。这就提供了去除数组重复成员的另一种方法。

    function dedupe(array) {
      return Array.from(new Set(array));
    }
    
    dedupe([1, 1, 2, 3]) // [1, 2, 3]

    8.Proxy

    Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

    其实就是一个拦截器,按照官方的描述,更像是一个C++的运算符重载,跟C#的set构造器有异曲同工之妙。它几乎可以作用于所有对象的行为,不仅仅是传参。(或许可以拿来弄一个enum)

    一个技巧是将 Proxy 对象,设置到object.proxy属性,从而可以在object对象上调用。  var object = { proxy: new Proxy(target, handler) };

    实现数组读取负数的索引

    function createArray(...elements) {
      let handler = {
        get(target, propKey, receiver) {
          let index = Number(propKey);
          if (index < 0) {
            propKey = String(target.length + index);
          }
          return Reflect.get(target, propKey, receiver);
        }
      };
    
      let target = [];
      target.push(...elements);
      return new Proxy(target, handler);
    }
    
    let arr = createArray('a', 'b', 'c');
    arr[-1] // c

    9.JavaScript Array 对象的方法

    常用方法:

    push()  向数组的末尾添加一个或更多元素,并返回新的长度。

    concat()  连接两个或更多的数组,并返回结果(a.concat(b))。

    值得注意的是,若a是空的,就不能直接concat。

    10.=== 和 ==的区别

    ===严格比较,类型不同就是不同;==会将两边转换成值再比较,比如string和int,1和‘1’是相等的。

  • 相关阅读:
    Spring在Web中使用的基本思路
    Spring整合Hibernate
    cuda cudaprintf使用
    《算法竞赛入门经典》第四章 函数和递归
    《算法竞赛入门经典》第三章 3.4
    《算法竞赛入门经典》第三章 3.3
    《算法竞赛入门经典》第三章 3.2
    《算法竞赛入门经典》第三章 3.1
    《算法竞赛入门经典》第二章 2.3
    《算法竞赛入门经典》第二章 2.4
  • 原文地址:https://www.cnblogs.com/chrisweiii/p/10553934.html
Copyright © 2020-2023  润新知