笔记-9-JavaScript高级补充(深克隆/正则)
算数运算符没有什么难度(考点),这里只记一下自增、自减
// 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);
});