Skip to content

奇技淫巧笔记

统计信息:字数 12018 阅读25分钟

原始笔记链接:https://cloud.seatable.cn/dtable/external-links/59b453a8639945478de2/

0002 [1,2,3].map(parseInt) 结果是什么

结果是 [1, NaN, NaN]

数组 Map 和 parstInt 的参数的说明以及返回值

array.map((item, index, arr) => return item );

let b = parseInt(a, 10); 第一个是数字,第二个是转换后的进制

基本结果是,1转换后是1,23转换后是NaN,实际上代码不会这样写,这个属于JS的奇技淫巧

0038 什么情况下a==1 a==2 a==3

考察第1个是等于等于表示前转换,需要进行数据类型的转换

需要把数字的转换成字符串进行比较,所以说这里需要改写数字对象圆形上的to string方法,来重写字符串

具体是可以令a是一个对象,然后a的two string方法变成当前属性加一

或者令a是一个数组是123,然后two string方法呢是数组的shift方法,依次返回1 233个数

0050 如何实现 1.add() 或者 1.minus()

数字对象原本没有这两个方法,需要改写数字对象的原型,给原型上增加 add 和 minus 函数即可

实际操作中很少改动原型对象

0053 JS 语句中多个等号的执行过程

一个JS表达当中有多个等号那么JS,表达式应该是从右向左直行

对象的应用类型是堆内存

复杂的内容可能涉及到一些编译原理,就是从右到左编译,这个在深入了解JavaScript里边的第1本有提到过

0074 JS 中 Proxy 是什么,有什么作用

Proxy 是内置的一个构造函数,主要用于数据绑定和拦截,实际开发中没有用到(获取或者设置对象的属性,需要先通过代理,可以进行拦截)

https://blog.csdn.net/weixin_44691513/article/details/108060781

let proxy = new Proxy({}, {key: value});

其中第一个参数表示拦截的对象,第二个参数表示处理操作的函数

这个操作就改变了对象的读写行为,获取任何属性都返回 20,设置任何属性,都放在 attr 上面

    var proxy = new Proxy({}, {
      get: function(target, property) {
        return 20;
      },
      set: function(target, attr, value) {
        // 一般用于对于要赋值的数进行过滤,加工,权限设置等
        target.attr = value;
      }
    });

0143 v8垃圾回收

首先js因为是单线程,垃圾回收会占用主线程,导致页面卡顿,所以需要一个算法或者说策略,而v8采用的是分代式回收,而垃圾回收在堆中分成了很多部分用作不同的作用,回收主要表现在新老生代上,新生代就活得短一点的对象,老生代就活得长一点的对象。

在新生代里有一个算法,将新生代分成了两个区,一个 from,一个TO,每次经过 Scavenge 会将 from 区中的没引用的销毁,然后活着的 to 区**调换位置**,反复如此,当经过一次 acavange 后就会晋升的老生代还有个条件就是TO区的内存超过多少了也会晋升。

而老生代,采用**标记清除和标记整理**,但标记清除会造成内存不连续,所以会有标记整理取解决掉内存碎片,就是清理掉边界碎片。

为什么TO超过25%要晋升老生代?标记清除是怎么清除的?

第一个问题是为了不影响后续FORM空间的分配,第二个问题垃圾回收会构建一个根列表,从根节点去访问那些变量,可访问到位活动,不可就是垃圾

0172 0.1+0.2为什么不等于0.3?具体项目中怎么处理?

因为 JS 是弱类型语言,存储使用 64 位浮点数,这个都是基于二进制存储的(浮点数),可能就是2的多少次方。小数点是基于10进制存储的。

十进制和二进制转换过程中,会出现精度丢失,然后 JS 加法的时候需要进制转换,造成了这个问题

解决的办法

1、因为前面的部分正确,只有后面末尾不正确,那么使用 toFixed 处理即可,可以解决简单的运算

+(0.1 + 0.2).toFixed(1)

2、可以使用第三方的库 number precious

3、未来 ES 新的提案中支持大数字和精确计算,参考:https://zhuanlan.zhihu.com/p/225490777

实际场景:

1、科研运算,使用 number-precious

2、金融运算(两位小数),先转换成分,然后计算,计算后再换成元

0308 0.1 + 0.2 === 0.3 ?

JavaScirpt 使用 Number 类型来表示数字(整数或浮点数),遵循 IEEE 754 标准,通过 64 位来表示一个数字(1 + 11 + 52)

- 1 符号位,0 表示正数,1 表示负数 s

- 11 指数位(e)

- 52 尾数,小数部分(即有效数字)

最大安全数字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1,转换成整数就是 16 位,所以 0.1 === 0.1,是因为通过 toPrecision(16) 去有效位之后,两者是相等的。

在两数相加时,会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会发生无限循环,然后进行对阶运算,JS 引擎对二进制进行截断,所以造成精度丢失。

所以总结:精度丢失可能出现在进制转换和对阶运算中

https://juejin.im/post/5b90e00e6fb9a05cf9080dff

0446 setTimeout 避免循环打印

setTimeout 循环打印

《你不知道的JS》第一部分第五章——闭包。经典的案例如下

for (var i = 0; i < 10; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000)
}

这个会打印出10个10,如何解决?

可以使用ES6的 let 形成块级作用域,这样可以正常打印

for (var i = 0; i < 10; i++) {
  (function() {
    var j = i;
    setTimeout(function() {
      console.log(j + 1);
    }, j)
  })();
}

或者使用 IIEF 创建临时的作用域,然后使用中间变量 j 缓存一下

for (var i = 0; i < 10; i++) {
  (function() {
    var j = i;
    setTimeout(function() {
      console.log(j + 1);
    }, j)
  })();
}

如果改成一个变量,可以把变量 i 作为参数,传入到 IEFF 中立即执行(创建了临时的函数作用域实现)

for (var i = 0; i < 10; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j + 1);
    }, j)
  })(i);
}

0440 安卓手机连接苹果电脑传文件

点击链接下载

android file transfer

然后连接安卓手机即可显示对应的文件

https://dl.google.com/dl/androidjumper/mtp/current/androidfiletransfer.dmg

0306 webGL 是什么

webGL:内嵌在浏览器中,编写三维图形程序

相关的第三方库:Three.js:JavaScript 3D WebGL库

https://juejin.cn/post/7245682364932554808

https://juejin.cn/post/7208849836186435640

目前项目没使用,暂时不看。

0332 ES6 中 Reflect 是什么?怎么使用

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 proxy handler (en-US) 的方法相同。

与大多数全局对象不同 Reflect 并非一个构造函数,所以不能通过 new 运算符对其进行调用,或者将 Reflect 对象作为一个函数来调用。Reflect 的所有属性和方法都是静态的(就像 Math 对象)。

实际使用不是很多。

// 返回这个对象自身的属性
Reflect.ownKeys(TABLE_ALTERNATE_HIGHLIGHT_CLASS_MAP);

// 判断这个对象是否有这个属性,返回布尔值
Reflect.has(obj, key);

// 给对象设置新的属性
Reflect.set(obj, key, value);

参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

0333 ES6 中 Proxy 是什么?怎么使用

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

这个语法主要在写库使用,实际产品使用场景中用的不多。

const p = new Proxy(obj, handlerFn)

实际案例:当对象中不存在属性名时,默认返回值为 37

const handler = {
  get: function (obj, prop) {
    return prop in obj ? obj[prop] : 37;
  },
};

const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b); // 1, undefined
console.log("c" in p, p.c); // false, 37

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

0379 删除一个文件删不掉,可能是什么原因

问题:删除一个文件删不掉,可能是什么原因?

可能没有删除的权限(是否有系统管理员权限,是否文件或者文件夹加密)这个查看一下文件信息的权限

可能删除后,定时任务判断没有文件,会重新创建这个文件(造成界面上文件删除不掉)常见于日志文件或者配置文件,这个需要查看创建文件的日期和文件内容,以及定时任务脚本等

0394 parseInt 函数第二个参数是什么

parseInt 函数

parseInt(number, index)

函数作用:把一个变量转换成整数

参数:第一个是传入的变量,第二个是转换的进制(可选参数),默认是10进制。'2' 转换1进制是 NaN,’3‘ 转换为2进制是 NaN

如果什么也不传,那么也返回 NaN

例题: [1,2,3].map(parseInt),结果是 [1, NaN, NaN]

0395 arguments.callee 是什么

这个是早期 JS 的语法,实际工程使用不多

arguments.callee 使用

使用转转反侧法计算两个数的最大公约数时,看到这样一个代码

function gcd(a, b) {
    if (a % b === 0) {
        return b;
    }
    return arguments.callee(b, a % b);
}

console.log(gcd(28, 12)); // 4
console.log(gcd(7890, 123456)); // 6
console.log(gcd(5, 13)); // 1 (公约数为1说明两数互质)

其中 arguments.callee 不会经常使用,这个属性未来可能废弃,查询资料如下:

Arguments 表示函数的参数。arguments 有一个属性 cellee 表示函数参数的指针(指向当前的函数)那么这样写相当于递归调用函数。这样写的好处:如果函数名变化后,函数内部的代码不需要改动(arguments.callee),主要在递归调用函数中使用。

例子:我们使用这个优化一下斐波那契函数:

原函数递归调用

function factorial(num){
  if (num <= 1) {         
    return 1;     
  } else {         
    return num * factorial(num - 1);
  } 
}

使用 arguements.callee 的函数

function factorial(num){    
  if (num <=1) {         
    return 1;     
  } else {
    return num * arguments.callee(num - 1);
  } 
}

这个方法在 eslint 中弃用,原因:访问 arguments 是个很昂贵的操作,因为它是个很大的对象,每次递归调用时都需要重新创建,影响浏览器的性能,还会影响闭包。

0397 中文输入法的键盘事件

中文输入法

手机输入法中,大部分都是 229 事件码,无法直接监听符号或者字母(后退正常),其他键已经被输入法封装了,所以Keycode无效。

PC端中如果是中文输入法,那么键盘事件监听到的字母键 keycode 也是 229,这个也需要注意。

0468 git log 改成简化版本的 git lg

git log 改成简化版本的 git lg

https://luolei.org/better-git-log/#comments

git log 改成简化版本的 git log 加入下面的软连接配置

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

0471 VScode 清除多余空行

VScode 清除多余空行

需要选择正则按钮,然后全局替换:使用正则表达式 ^\s*(?=\r?$)\n

^\s*(?=\r?$)\n


Last update: November 9, 2024