红宝书前5章
Symbol类型
symbol区别于字符串,Symbol提供的常用内置符号可以给js内建的对象的方法赋予独一无二的属性,保证不会发送命令冲突的情况,开发者可以通过这些符号重写这些1底层的行为,
比如Symbol.hasInstance
symbol.hasInstance表示的方法被instanceof操作符使用,它表示,一个构造器对象(构造函数对象)是否认可另一个对象是它的实例
function Foo() {}
let f = new Foo();
console.log( f instanceof Foo );//true
//我们这里改写这个方法
class Foo {
static [Symbol.hasInstance] () {
return false;
}
}
let f = new Foo();
console.log( f instanceof Foo);
//或者你也可以使用
function Foo() {}
Object.defineProperty(Foo, Symbol.hasInstance, {
value: function(instance) {
return false;
}
});
let f = new Foo();
console.log(f instanceof Foo); // 输出:false
类型转换
逻辑非 ! , 逻辑&&, 逻辑于||
逻辑!会把遇到的任何数都转换为布尔值,而隐式转布尔规则相当简单
除了 NaN, null, undefined, 0, '', 之外的值全部转换为true
+ 加性操作符
//如果有任一操作符是NaN,则返回NaN
console.log(1 + NaN);//NaN
//Infinity + Infinity
console.log(Infinity + Infinity);//结果为 Infinity
//这是符合直觉的
//-Infinity + (-Infinity)
console.log(-Infinity + (- Infinity));//结果为-Infinity
//-Infinity + Infinity
console.log(-Infinity + Infinity);
//结果也是符合直觉的,正无穷加负无穷,算不清吧
console.log(+0 + +0);//+0
console.log(-0 + +0);//+0
console.log(-0 + -0);//-0
当加性操作符的操作符有一个是字符串,就尽量往字符串转换了,其它就是转数值了,true + 1 = 2;
- 减法操作符
//Infinity减去 Infinity 结果NaN
console.log(Infinity - Infinity );//NaN
//infinityinfinity 不是等于0,毕竟inifinity 不是一个具体的值,也许两个Infinity 值都不一样,
//所以不能减
console.log(-Infinity - (-Infinity));//NaN,结果同上
console.log(Infinity - (-Infinity));//Infinity
//相当于Infinity + Infinity 结果是Infinity
console.log(-Infinity - Infinity);
//返回 -Infinity
关系操作符
关系操作符会尽量将操作数转换为数值进行大小的比较
[2] > 1 //true
//对象会调用原型的valueOf或者是toString,
//然后转换为数值,像这里,其实就是 [2] ==> '2' ==> 2
[2, 1, 3] > 1
// [2, 1, 3] ==> '2,1,3' ==> NaN
//在关系操作符中有条规则是 NaN和任何的关系操作符比较都是 false
NaN > 1
//false
NaN <= 1
//false
//undefined和NaN一样
undefined > null;
//false
undefined <= null;
//false
//null会被转换为 0
null >= 0
//true
//两个字符串会比较unicode的顺序
//从第一个字母比起,到最后一个
"apple" < "banna"
相等操作符
操作符中有布尔值,会被转为数字
字符串碰到数字,会被转为数字
true == '1'// true
true == 'sabhdik'//false
true == '1'//true
'1ugyj1' == 1//false
//undefined 和null ==结果是true
undefined == null //true
NaN是一个特殊值,它和任何值比较都返回false
NaN == NaN //false
//对象就会被转换为字符串
[1, 2, 3] == '1,2,3'//true
const string = 'str';
const string2 = new String('str');
string == string2; //true
//对象被转为字符串了
数组和布尔
[1, 2, 3] == true
//false
//数组要和布尔相等的情况就三种
[1] == true //true
[0] == false //false
[] == false // true
垃圾回收
垃圾回收,就是对堆中的对象的垃圾回收,当堆中的对象不再被引用的时候,垃圾回收会释放其占用的内存,
const user = {
name: "张三",
阿哥: 25
}
console.log(user.name);//输出张三
user = null;
需要强调的是,垃圾回收是一次很耗时的操作,如果让垃圾回收频繁开始,那么会极大的占用主进程,
所以,我们必须通过优化自己的代码去避免频繁的对象切换,创建,卸载,对象池就是一个优化操作
//自定义对象池
//闭包 + IIFE 创建私有属性
//构造函数原型定义实例属性
var objectPool = (function() {
var IN_POOL = Symbol("inPool");
var author = '超绝大帅哥的自定义对象池'
var maxLength = 100; //对象池能使用的最大对象数
var pool = [];
function initializePool (createFn,size) {
for (let i = 0; i < size; i++) {
const obj = createFn();
obj[IN_POOL] = true
pool.push(obj);
}
}
function Constructor(createFn, size = maxLength) {
this.createFn = createFn;
size = size > maxLength ? maxLength : size;
initializePool(createFn, size);
}
Constructor.prototype.acquire = function () {
let obj;
obj = pool.length > 0 ? pool.pop() : this.createFn();
obj[IN_POOL] = false;
console.log('申请成功');
return obj;
}
Constructor.prototype.release = function (obj) {
if(obj[IN_POOL]) {
console.log('对象已经在池中');
return ;
}
obj[IN_POOL] = true;
obj.resetFn && obj.resetFn();
pool.push(obj);
}
Constructor.author = authorl;
return Constructor;
})();
class Bullet {
constructor() {
this.active = false;
this.x = 0;
this.y = 0;
}
fire(x, y) {
this.active = true;
this.x = x;
this.y = y;
}
reset() {
this.active = true
this.x = x;
this.y = y;
}
}
const bulletPool = new objectPool(()=> new Bullet(), 5);
const b1 = bulletPool.acquire();
b1.fire(100, 200);
bulletPool.release(b1);
bulletPool.release(b1);