原稿:语雀 · JS 知识点 · 原目录:JavaScript › JS 知识点
JS 数据类型
JavaScript 中有八(7+1)种基本的数据类型(七种基本数据类型,也称为原始类型,object 为复杂数据类型)
- number:用于整数或浮点数,在 ±(253-1) 范围内的整数
- bigInt:用于任意长度的整数
- string:用于字符串
- boolean:用于 true 和 false
- null:只有一个 null 值的独立类型
- undefined:只有一个 undefined 值的独立类型
- symbol:用于唯一的标识符
- object:用于更复杂的数据结构
如何理解原型?
- 构造函数:任何情况下创建一个函数,都会在内部为其创建一个prototype属性,该属性是一个指向原型对象的引用。使用原型对象可以允许上面定义的属性与方法被对象实例共享。
- 原型对象:原型对象会默认自动获得一个constructor属性,该属性是指回构造函数的引用。自定义构造函数的原型对象默认只会获得constructor属性,其余方法都继承自Object
- 原型对象的原型:原型对象本身是Object或父类的实例,它也有一个暴露为__proto__的属性指向父类构造函数的原型对象(隐式原型)。特别的,Object的原型对象是原型链的起点,其constructor指向Object()构造函数,同时Object原型对象的不再有原型,其不再具有__proto__
- 对象实例:每个被构造的实例内部也有__proto__,同样指向其构造函数原型对象
参考ES5原型链继承图示理解:
var、let、const
var |
|
let |
|
const | 基本和let一致,但必须在声明同时初始化,且在生命周期中无法重新赋值 |
new 过程
new一个对象时发生了 2. 在内存中创建一个新对象 4. 新对象内部的
]特性被赋值为构造函数的prototype属性 6. 构造函数内部的this被赋值为这个新对象(即this指向新对象) 8. 执行构造函数内部的代码 10. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象
手写new():原生重写
this
参考链接:深入理解this机制系列第一篇——this的4种绑定规则
this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。 this 的绑定在构建执行上下文时确定,在实际开发中,this 的指向可以通过四种调用模式来判断:
- 默认绑定:当一个函数不是一个对象的属性时,直接作为函数来调用时,调用行为发生在全局上下文中,this 默认绑定到全局对象
- 隐式绑定:被直接对象作为方法调用的函数,其上下文的 this 隐式绑定到该对象上
- 显式绑定:通过 call()/apply()/bind() 把指定对象绑定到 this 上,叫做显式绑定
- new 绑定:new 构造一个新对象时,构造函数内部的 this 会自动绑定到新建的对象上
绑定优先级:new绑定>显式绑定>隐式绑定>默认绑定
闭包
定义:当一个函数可以访问到其他函数作用域中自由变量时,即构成闭包,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。
意义:闭包的意义就是“隐藏变量”,对外隐藏状态。当前函数能够访问到外部函数词法环境中的变量,甚至在外部函数执行上下文已经离开执行栈时,此时外部函数的变量称为当前函数的“私有变量”,而外部函数的词法环境也会被一致保存在内存中
场景: 2. 实现装饰器函数:比如防抖和节流装饰器,外部 decorator 中的 timer 被返回的 wrapper 函数所引用着,timer 变成了一个私有变量,只有调用 wrapper 才能改变计时器的状态 4. 解决循环中多个闭包共享词法作用域的问题:典型的场景就是 for 循环中使用 var 声明 i,通过 setTimeout 打印时,为了实现每次输出值的不同,使用更多的闭包解决这个问题;构造一个立即执行函数,构成计时器回调的闭包,这个立即构造函数中的 i 就成了私有变量,对外隐藏,只有回调执行时才能访问
for (var i = 0; i < 5; i++) {
(function (i) {
setTimeout(() => {
console.log(i);
}, 1000 * i);
})(i);
}
- 私有变量与特权函数:对于构造函数内不想被外界直接访问修改的变量,同时又需要操作,通过 this 提供特权函数,让特权函数构成闭包,其具备访问外部构造函数中私有变量的能力
function Counter() {
let cnt = 0;
this.add = function () {
cnt++;
};
this.now = function () {
return cnt;
};
}
let counter = new Counter();
counter.add();
counter.add();
console.log(counter.now());
箭头函数和普通函数
- 箭头函数不能使用 arguments、super 和 new.target,也不能用作构造函数。此外也没有 prototype 属性
- 箭头函数相对于普通函数语法更简洁优雅
- 箭头右侧可直接跟一个表达式,并隐含返回计算结果
- 当右侧是多行表达式或复杂函数,需要使用 {} 并显式返回结果,否则返回 undefined
let sum = (a, b) => a + b;
// 等价于
let sum = function(a, b) {
return a + b;
};
- 箭头函数没有this,其this需从外部作用域获取,因此取决于箭头函数定义位置的上下文,下面是babel转化ES6箭头函数的结果
箭头函数this继承自外层第一个普通函数的this;如果外层没有普通函数,它的this会指向window
| // ES6 const obj = { getArrow() { return () => { console.log(this === obj); }; } } | // ES5,由 Babel 转译 var obj = { getArrow: function getArrow() { var _this = this; return function () { console.log(_this === obj); }; } }; |
Object 对象
对象属性的特征
- ]:属性是否可通过 delete 删除并重新定义,默认 true
- ]:属性是否可通过 for-in 或 Object.keys() 枚举,默认 true
- ]:属性是否可被修改,默认 true
- ]:属性值,默认 undefined
下面是三种对 Object 的静态方法,用于限制对象属性
返回一个由一个给定对象的自身可枚举属性组成的数组
作为对比 for-in 循环则会遍历对象自身+其原型链上可枚举属性,每次获取的索引都是字符串类型
冻结对象,使其不能被修改(冻结一层,)
- 不能新增、删除属性
- 不能修改已有属性:不能修改已有属性的\(\[可枚举性\)]、\(\[可配置性\)]、\(\[可写性\)]、\(\[值\)],但是当属性为对象,该嵌套对象的属性可修改,除非嵌套对象被冻结
- 对象 ] 不可修改
封闭对象
- 不能新增属性
- 现有属性标记为不可配置,即不可删除
- 对象 ] 不可修改,已有可写属性可以修改
让一个对象不可扩展
- 不能新增属性
- 可删除已有属性
- 对象 ] 不可修改,其余属性都可修改
从限制的严格性来说:Object.preventExtensions()
< Object.seal()
< Object.freeze()
数字处理
- IEEE 754
JS 的 Number 类型遵循的是 IEEE 754 标准,使用的是 64 位固定长度来表示,见Ch2 信息表示与处理