您的位置:首页 > Web前端 > JavaScript

js小黄书总结

2021-01-05 14:11 253 查看

js 的编译与执行

  • 编译阶段:编译器、作用域 源代码 -> 静态地词法分析生层词法作用域 -> 语法分析生成AST -> 将AST转换为可执行代码
  • 执行:js引擎,作用域 执行时,js引擎沿着作用域链进行LHS与RHS,知道全局作用于,若仍未发现,则自动创建该全局变量(非严格模式下)。

js严格模式有何不同?

  • 禁止隐式或自动创建全局变量
  • eval无法改变所在的词法作用域
  • js全局作用域的执行上下文不会默认绑定到全局对象上
  • 对对象的只读数据进行写操作时,会报错。而不会静默失败。
  • 无法为undefined赋值

使用函数的优势?函数有什么用?

  • 隐藏内部实现,实现封装的效果
  • 减少命名冲突
  • 保证局部作用域中的undefined的真实性

js匿名函数的缺点

  • 可读性变差
  • 调用栈中无法根据函数名进行追踪debug
  • 递归不够方便,只能使用过期的argument.callee(已被弃用)进行引用

js中的块级作用域举例:

  • with
  • try...catch 的 catch () 作用域中
  • let
  • const

什么是闭包?

  • 当函数能够记住并访问所在的词法作用域时,就产生了闭包。
  • 以自执行函数为例,产生闭包并不是一定就使用了闭包。
  • 严格来讲,只要存在函数嵌套即会产生闭包。只不过这个闭包可能很快就被销毁。而我们常说的闭包,多为长期占用堆内存的闭包。

使用闭包的场景?

定时器、事件监听器、ajax、跨窗口通信、webworkers等,凡是使用了回调函数的地方,就会使用闭包。

改变this指向的几种方法:

  • 对象挂载 p85
  • 隐式绑定 p86
  • call、apply
  • bind 硬绑定
  • new 绑定

将数组展开成参数的几种方法:

  • apply() p97
function foo(a, b) {
console.log("a:" + a + ", b:" + b);
} // 我们的 DMZ 空对象
var ø = Object.create( null ); // 把数组展开成参数
foo.apply( ø, [2, 3] ); // a:2, b:3 // 使用 bind(..) 进行柯里化
  • es6 ...

实现new关键字

function newKeyword (constructor, ...param) {
let obj = {};
let proto = Object.create(constructor.prototype);
Object.setPrototypeOf(obj, proto);  // obj.__proto__ = proto 在浏览器端存在兼容性问题
proto.constructor = constructor;
constructor.apply(obj, param);
return obj;
}

function Baby (name, age) {
this.name = name;
this.age = age;
this.show = function () {
console.log('我是小柚子');
}
}

let baby = newKeyword(Baby, 'pomelo', 1)

js数字

  • 标注为IEEE754
  • 使用64位二进制表示,第一位表示符号位,中间11位表示指数位,最后52位表示小数位。所以可以表示为 1.x 乘以2的y次方,可表示的数值范围是 -2的53次方到2的53次方减一
  • 数字的位运算使用32位

##布尔转换

  • 假值: undefined、null、0, -0, NaN、''
  • 隐式转换为假值:new String(''), new Boolean(false), new Number(0)
new String('') && 1

== 与 === 的区别

  • == 在比较时允许使用隐式强制转换,而 === 不允许。

x == y

  • x或y都不是null 或undefined时, 且 x,y为除了symbol以外的基础类型, 当在隐式转换时会最终转换为 Number
  • x或y存在一个为null或undefined时,只有 null == undefined 为 true
  • x或y存在一个为对象时, 调用对象的toPrimitive方法(toString、valueOf)

x < y

  • x,y 存在一个为数字,则隐式转换为数字
  • x, y 都不是数字,则隐式转换为字符串,并按照字符串顺序比较

运算符的优先级

  • && > || > ?> :

回调函数的弊端

  • 回到地狱,可读性差,调试困难
  • 控制翻转,安全性降低,回调函数的调用情况不受控制

promise的问题

  • 在链式调用的最后进行catch时候,不太容易对显示reject的某个promise进行追溯。
  • 决议的单一值,在传送多值时,通过对象的封装与解封,会带来一部分开销。即使是使用...,即使是用起来优雅。
  • 相较回调的解决方案,肯定会有额外的性能开销。

优化浏览器堵塞的几种思路

  • web worker

通过时间差来计算js执行性能的局限性?

  • js的执行精度可能无法满足,例如老的IE浏览器,精度仅为15ms
  • 执行环境的不确定性,例如:是否受其他因素影响
  • 多次执行,总时间除以循环次数,这种方式本身就不够科学,即无法保证测试时每次的执行环境与发布环境下均为一致。
  • 多次执行时,js引擎本身就会根据变量的使用频率进行优化,因此会导致结果不够科学严谨。

如何测试?需要注意什么?

  • 利用第三方测试库 ,如:benchmark.js
  • 尽可能保证测试环境的真实性,跨平台实机测试,以及不同的浏览器内核。利用jsPerf,持续搜集性能数据
  • 测试代码应尽可能地真实,不同测试用例的相同逻辑应尽可能保持一致

js代码优化的技巧

  • 尾调用栈帧优化(尤其是递归),尽可能使用尾调用。

es6 自定义结构赋值

let test = {};
let target = {name: 'tate', age: 18};
({name: test.a, age: test.b} = target);
console.log(test)
let o = {
a: 1,
b: 2,
c: 3
}

let d,e,f, tate;

tate = {a: d, b:e, c: f} = o;

console.log(tate)

标签模板字面量

function tpl (tpl, val) {
console.log(tpl, val)
}
let name = 'tate';
tpl `my name is ${name}`;

什么情况下,可以将普通函数替换成箭头函数?p130

  • 函数内部没有进行任何this的调用
  • 函数的调用环境始终与函数所在的词法作用域一致
  • 函数中使用了arguments 并且,arguments依赖于父层函数

es6 正则新增模式

  • u模式, y模式

unicode 编码方式

  • utf-8 变长, 使用1-6个字节表示,兼容ascii
  • utf-16 既有定长,又有变长,2个字节或四个字节,js使用utf-16编码
  • utf-32 固定四个字节

无法被 Proxy 捕获的行为:

  • typeof obj
  • String(obj)
  • obj + ""
  • obj == proxyObj
  • obj === proxyObj
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: