«

笔记-9-JavaScript高级补充(深克隆/正则)

codeez 发布于 阅读:2056 笔记


算数运算符没有什么难度(考点),这里只记一下自增、自减

// a++ 先用a原先的值,再自增1;++a先自增1,再提供自增后的值
var a = 1, b = 2;
var c = b++ // 这里c的值是2,b自增后变成3
// 这里a++提供的是1,--b是2,++a因为前面已经+1所以是3,c是2
console.log(a++ + --b + ++a + c); // 所以结果是8

记一下&&和|| 的短路运算

var a = true && false 
// A && B 时:A真返回B 、 A假返回A
console.log(a);// false

var a = true || false 
// A || B 时:A真返回A 、 A假返回B
console.log(a);// true

==和===的区别

// == 比较值,如果类型不一样会自动转换后再比较
// '10' == 10 是true,因为将string类型的10转为了number
// 需注意,{}对象类型是无法通过这种简单转换的
console.log([] == false); // true 
console.log(Boolean([])) // true 说明并不是将[]转为Boolean
// Number([]) 返回0,Number(false) 返回0
// 个人认为应该是通过Number()包装类统一转为数值型再比较。因为[]转String的话会输出空白行。
// 对象作为入参Number()返回NaN。注:NaN不自等
console.log({} == false); // false
// 对这方面了解透彻的小伙伴可以评论哈。

// === 是严格判断是否相等的运算符,会同时比较类型和值
// '10' === 10 是false

正则表达式

// 字面量写法
var regex1 = /abc/

// 构造函数写法
var regex2 = new RegExp('abc')

console.log(regex1.test('abcd')) // true 因为abcd里包含了abc

// 如果希望被匹配的内容与规则完全相符(全字匹配)
var regex3 = /\babc\b/
// \b匹配单词边界, \B匹配单词非边界,如果没有也是false

console.log(regex3.test('abcd')) // false 

// \d 匹配数字 \D 匹配非数字

// [] 匹配指定范围内的任意一个,[^]如果加了^则取相反意思,不得含有方括号内容

// ^ 开头 $ 结尾

// + 号前面的第一条规则可以重复1次或者N次

var regex4 = /^go+gle$/

console.log(regex4.test('gooooogle')) // true

// * 号前面的第一条规则可以重复0次或者N次

// ? 号前面的第一条规则可以重复0次或者1次

// {x} 表示前面的第一条规则可以重复x次
// {x,y} 表示前面的第一条规则可以被重复x至y次,{2,4}的意思就是可重复2\3\4次
// {x,} 表示至少x次

// () 可以用来指定多个字符组成字符串,作为一个规则

// | 表示在几个规则中有一个满足就可以返回true

// \ 如果匹配^*+等特殊符号,需要在前面加\做转译

canvas

<body>
    <canvas id="canvas" width="800" height="600"></canvas>
    <script>
      // 获取画布元素
      var canvas = document.getElementById("canvas");
      // 获取二维绘图对象
      var ctx = canvas.getContext("2d");
      // 设置线宽
      ctx.lineWidth = 3;
      // 线条颜色
      ctx.strokeStyle = 'red';
      // 填充颜色
      ctx.fillStyle = 'blue'
      // 起点
      ctx.moveTo(10,10)
      // 下一点
      ctx.lineTo(100,10)
      // 下一点
      ctx.lineTo(100,100)
      // 闭合点,完成三角形
      ctx.lineTo(10,10)
      // fill()执行填充色 stroke()执行线条
      ctx.stroke()
      ctx.fill()

      // ctx.beginPath() // 重新绘制
      // ctx.closePath() //闭合
    </script>
  </body>

requestAnimationFrame比CSS动画控制性会强一些,对性能消耗相对较大。

requestAnimationFrame 是由浏览器专门为动画提供的 API,在运行时浏览器会自动优化方法的调用,如果浏览器在后台运行或者该页面tab在后台运行时,动画会自动暂停。

动画每一帧的执行的间隔时间紧跟浏览器的刷新频率,动画更流畅,不会掉帧。

示例:

让蓝色的矩形向右侧移动【因为这个动态图的帧率很低,所以看着动起来很慢】

<body>
    <div>
      <button onclick="start()">开始</button>
      <button onclick="stop()">停止</button>
    </div>
    <div class="box" id="box"></div>

    <script>
      var handle = 0; // 用来接收动画id,它是一个整数,取消动画时需要用
      var step = 1; // 每次动画移动1个像素
      var el; // 要应用动画的dom元素
      window.onload = function () {
        el = document.getElementById("box"); // 在页面加载完后获取box元素
      };
      function start() {
        handle = requestAnimationFrame(move); // 开始动画
      }
      function move() {
        el.style.left = step + "px";
        step++;
        handle = requestAnimationFrame(move); // 需要使用递归,才可以让动画持续
      }
      function stop() {
        cancelAnimationFrame(handle); // 停止动画
      }
    </script>
  </body>

深克隆

// 深克隆

let wm = new WeakMap()

function deepClone(obj) {

    // 基本数据类型、null、函数的处理
    // 注:typeof function 会返回'function'
    if(obj === null || typeof obj !== 'object') {
        // 函数处理不了,直接返回
        return obj
    }

    // 处理回环对象,如果已处理过某对象,则直接返回不要再递归了
    if(wm.has(obj)){
        return wm.get(obj)
    }

    if (obj instanceof Map){
        // 处理Map类型
        var tmp = new Map()
        wm.set(obj,tmp)
        for(var [key,value] of obj){
            tmp.set(deepClone(key), deepClone(value))
        }
        return tmp
    } else if (obj instanceof Set) {
        // 处理Set类型
        var tmp = new Set()
        wm.set(obj,tmp)
        for(var value of obj){
            tmp.add(deepClone(value))
        }
        return tmp
    } else if (obj instanceof RegExp) {
        // 处理RegExp 正则表达式
        var tmp = new RegExp(obj)
        wm.set(obj,tmp)
        return tmp
    } else {
        // 处理数组、对象、Date
        var tmp = new obj.constructor() // 每个对象实例都有一个constructor属性,指向创建该实例的构造函数。
        wm.set(obj,tmp)
        for(var key in obj){
            tmp[key] = deepClone(obj[key])
        }
        return tmp
    }

// 注:
    JSON.parse(JSON.stringify(obj)) // 无法处理环型对象 而且不能处理包含函数、Set、Map等特殊数据结构。因为JSON不支持那些。
// 环形对象
obj1.a = obj2
obj2.a = obj1

Map底层实现

Map 的底层实现通常涉及哈希表,哈希表是一种能够快速检索元素的数据结构。在 JavaScript 的 Map 实现中,键的哈希码是通过一个算法来生成的,而这个算法需要保证在键是可比较的情况下,相同的键总是有相同的哈希码。
class SimpleMap {
    constructor() {
        this.items = {};
    }

    set(key, value) {
        const hash = this.hash(key);
        if (!this.items[hash]) {
            this.items[hash] = [];
        }
        this.items[hash].push([key, value]);
        return this;
    }

    get(key) {
        const hash = this.hash(key);
        if (this.items[hash]) {
            for (let i = 0; i < this.items[hash].length; i++) {
                if (this.items[hash][i][0] === key) {
                    return this.items[hash][i][1]; // Value
                }
            }
        }
        return undefined;
    }

    delete(key) {
        const hash = this.hash(key);
        if (this.items[hash]) {
            for (let i = 0; i < this.items[hash].length; i++) {
                if (this.items[hash][i][0] === key) {
                    this.items[hash].splice(i, 1);
                    return true;
                }
            }
        }
        return false;
    }

    has(key) {
        const hash = this.hash(key);
        if (this.items[hash]) {
            return this.items[hash].some(pair => pair[0] === key);
        }
        return false;
    }

    hash(key) {
        let hash = 0;
        let s = JSON.stringify(key);
        for (let i = 0; i < s.length; i++) {
            hash = (hash << 5) - hash + s.charCodeAt(i);
            hash |= 0; // Convert to 32bit integer
        }
        return hash;
    }

    get size() {
        let size = 0;
        for (const key in this.items) {
            if (this.items.hasOwnProperty(key)) {
                size += this.items[key].length;
            }
        }
        return size;
    }

    clear() {
        this.items = {};
    }

    // Other methods like keys(), values(), entries(), forEach()
}

// 使用示例
const map = new SimpleMap();
map.set('key1', 'value1');
map.set('key2', 'value2');
console.log(map.get('key1')); // 输出: value1
console.log(map.has('key1')); // 输出: true
map.delete('key1');
console.log(map.has('key1')); // 输出: false

Promise.all 是一个用于并行执行多个 Promise 的方法,它接收一个 Promise 数组作为参数,并且当所有的 Promise 都成功解决时,它将以一个解决状态的数组作为参数,顺序与输入的 Promise 数组中的 Promise 顺序相同,返回一个新的 Promise。如果任何一个 Promise 失败,则立即停止等待,并返回一个失败的 Promise,失败的原因通常是第一个失败的 Promise 返回的值。

以下是一个简单的 Promise.all 实现的例子:

function myPromiseAll(promises) {
  return new Promise((resolve, reject) => {
    let results = [];
    let remaining = promises.length;

    if (remaining === 0) {
      resolve(results);
      return;
    }

    promises.forEach((promise, index) => {
      Promise.resolve(promise).then(
        (value) => {
          results[index] = value;
          if (--remaining === 0) {
            resolve(results);
          }
        },
        (reason) => {
          reject(reason);
        }
      );
    });
  });
}

// 使用示例
const promises = [fetch('url1'), fetch('url2'), fetch('url3')];

myPromiseAll(promises).then(values => {
  console.log(values); // 当所有的 fetch 都完成时,会打印出结果数组
}).catch(reason => {
  console.error('一个 promise 失败:', reason);
});

前端

请先 登录 再评论