ECMAScript 中的对象是一组数据和功能的集合,对象通过 new 操作符跟一个构造函数(类名)创建 或者 直接使用 对象字面量的方式创建。Object 是所有对象的基类,所有任何对象都有基类上的方法和属性。
每个 Object 实例都有如下属性和方法
- constructor 用于创建当前对象的函数
// Object 就是一个构造函数
const obj = new Object();
// 当构造函数不需要参数的时候,可以不要括号(不推荐)
const obj2 = new Object
- hasOwnProperty(key: string | number | symbol) 用于判断当前对象实例(不是原型)上是否存在给定的属性
- isPrototypeOf(obj) 用于判断当前对象是否为另一个对象的原型
- propertyIsEnumerable(key) 判断给定的属性是否可以使用 for-in 语句枚举,即判断实例的 key 是否是可枚举的
- toLocaleString() 返回对象的字符串表示,该字符串反映度对象所在的本地化执行环境
- toString() 返回对象的字符串表示
- valueOf() 返回对象对应的字符串、数值或布尔值表
自增自减操作符
- num-- 先使用再自减
- num++ 先使用再自增
- --num 先自减再使用
- ++num 先自增再使用
数值操作符 +、-,遵循如下规则(最终都会变成 number 类型)
- 对于字符串,经过如上四个操作符,字符串类型都会变成 number 类型
- 如果是有效的数值字符串,会转化为数值再应用改变。
- 如果字符串不是有效的数值类型,会转化为 NaN
// 有效的数值字符串
let validateNumStr = "123";
log(typeof validateNumStr); // log: string
log(typeof ++validateNumStr); // log: number
log(validateNumStr); // log: 124
// 无效的数值字符串
let invalidateNumStr = "abc";
log(typeof invalidateNumStr); // log: string
log(typeof ++invalidateNumStr); // log: number
log(invalidateNumStr); // log: NaN
- 对于布尔值
- 如果是 false,变为 0 再应用
- 如果是 true,变为 1 再应用
let trueValue = true;
log(typeof trueValue); // log: boolean
log(typeof ++trueValue); // log: number
log(trueValue); // log: 2
let falseValue = false;
log(typeof falseValue); // log: boolean
log(typeof ++falseValue); // log: number
log(falseValue); // log: 1
- 对于数值,加 1 或者减 1
- 对于对象,先调用其 valueOf() 方法获取可操作的值
let obj = {
valueOf() {
return "invalidStrVal";
},
toString() {
return 3;
},
};
log(typeof obj); // log: object
log(typeof ++obj); // log: number
log(obj); // log: NaN
位操作符
位操作符用于数据的底层操作,也就是内存中表示的数据的比特(位),因为 ECMAScript 所有数值都是以 IEEE754 64 位格式存储,但是位操作并不直接应用到 64 位(不可见),它会先把 64 位转化为 32 位,在进行位操作。有符号整数使用 32 为的前 31 位表示整数值,第 32 位 0 表示正,1 表示负号。
注意⚠️:在转化为的时候,NaN 和 Infinity 在位操作中都会被当成 0 处理
负值 (补码 二进制编码存储)
一个负数的表示经过如下步骤
- 确定绝对值的二进制表示
- 找到数值的补码或反码(二进制中 0 变 1, 1 变 0)
- 将第二步 的结果 + 1
// 在 js 中,负值输出为一个二进制字符串时,会得到一个前面 加了 减号 的绝对值
log((-18).toString(2)); // log: -10010
按位非 ~
按位非的作用是对数值去反并减1 即 result = ~num = -num - 1; 尽管看起来差不多,但是位操作的速度快得多
按位与 &
两个操作数按照位数对其,都为 1 & 的结果为 1,其他情况为 0
比如: 0110 & 0101 = 0100 最终结果为 4 ,即 6 & 5 = 4;
const v1 = 6, v2 = 5;
log(6 & 5); // log: 4 0110 & 0101 = 0100 = 4(十进制)
按位或 |
都为 0 的时候才为0,有 1 就为 1;
按位 异或
不同的时候才为 1, 相同的时候为 0 (比如 1 & 1 = 0, 0 & 0 = 0, 1 & 0 = 1, 0 & 1 = 1)
左移 <<
会按照指定的位数将数值所有位向左移动(向左移动的数值为多少,就乘以2的多少次方)左移会用 0 来填充右边。
注意⚠️: 左移会保留所操作数的符号。比如, -2 左移 5 位,得到的结果是 -64
const old2 = 2;
const newVal = old2 << 5; // 2 * (Math.pow(2, 5), old2 没有变化
log(old2.toString(2)); // 0000010 (2 的二进制)
log(newVal); // log: 64
log(newVal.toString(2)); // log: 1000000 (64 的二进制)
有符号右移 >>
右移符号位不会变化,只是符号位之后的位码在移动,即会保留符号(正或负)
const oldValue = 64; // 二进制位: 1000000
log(oldValue >> 5); // 右移 5 位 后,二进制变为: 10,即十进制 2
无符号右移 >>>
无符号右移会将数值的所有 32 位都向右移,即不论正负,符号位都参与右移
const negativeVal = -64;
log(-64 >>> 5); // log: 134217726, 这就是无符号右移,变化太大了
const positiveVal = 64;
log(64 >>> 5); // log: 2, 正数的无符号右移和有符号右移一样
指数操作符 **
ECMAScript 7 新增的指数操作符 **, 等效于 Math.pow(x,y) 即 x 的 y 次幂
log(Math.pow(2, 3)); // 8;
log(2 ** 3); // 8
逻辑非 !
这个操作符始终会返回布尔值,只有 空字符串'', 0, null, NaN, undefined 五个值会返回 true,其他都会变为 false
两个 !! 相当于使用 Boolean(val) 来讲 val 转换为 boolan 值
// 记住吧,只有这个 6个 经过非之后才是 true,其他的值 !都是 false
log(!""); // true,
log(!NaN); // true;
log(!undefined); // true;
log(!0); // true;
log(!null); // true
log(!false); // true
log(!!""); // false,
log(!!NaN); // false;
log(!!undefined); // false;
log(!!0); // false;
log(!!null); // false
log(!!false); // false
逻辑与 &&
逻辑与 && 是一种短路操作符,即如果第一个操作数决定了结果为 false,那么永远不会对第二个操作数求值;只有两个为 真,其与的结果才为真
逻辑或 ||
如果有一个为真,其或的结果就为真;如果第一个操作数 为真,则直接短路,不会计算第二个值,直接返回为真
乘法操作符 *
const res = num1 * num2
计算规则如下:
- 如果两个正常的数值相乘,如果 ECMAScript 不能表示乘积,则返回 Infinity 或 -Infinity
- 如果有任意操作数是 NaN, 则返回 NaN
- 如果 Infinity * 0 , 返回 NaN
- 如果 Infinity * 非 0 有限数值,则根据 第二个操作数的符号返回 Infinity 或 -Infinity
- 如果 Infinity * Infinity, 则返回 Infinity
- 如果不是数值的操作数,则先在后台用 Number() 将其转化为数值,然后再应用上数规则
加法操作数 +
注意⚠️: 如果 操作数中有一个是字符串,则会以 字符串拼接的方式将两个操作数组合在一起
比较操作符 >, <, >=, <=, ==, ===
- 只要是设计 NaN 的比较,除了 NaN != NaN 和 NaN !== NaN 外最终结果都会返回 false
log(NaN == NaN); // log: false
log(NaN === NaN); // log: false
log(NaN >= NaN); // log: false
log(NaN <= NaN); // log: false
log(NaN > NaN); // log: false
log(NaN < NaN); // log: false
log(NaN != NaN); // log: true
log(NaN !== NaN); // log: true
等于操作符 ==
- 如果存在一操作数为 boolean 类型或者 number 类型,会优先将 其转化为 number 类型比较
- 如果一操作数是对象,而另外一个操作数不是对象,则调用对象的 valueOf() 方法获取其原始值,然后在进行比较
- null 和 undefined 相等。
- null 和 undefined 不再进行转化为其他类型的值进行比较
- 如果 存在 NaN,则返回 false, 不相等返回 true ( NaN 不等于 NaN)
- 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true。否则,两者不相等。
全等(=== ) 和不全等(!==) 操作符
全等和不全等操作符与相等和不相等操作符类似,只不过它们在比较相等时不转换操作数。全等操作符(===)和不全等操作符(!==)两个在进行比较的时候不会进行转化
log(55 == "55"); // log:true; 在等于的时候会进行「转化」后比较
log(55 === "55"); // log:false; 全等于的情况「不进行转化」比较
log(55 != "55"); // log: false; 在不等于的时候会进行「转化」后比较
log(55 !== "55"); // log: true; 不全等于(或严格不等于)的情况「不进行转化」比较
赋值操作符
- result = express; 将右边的 express 赋值给 result
- result *= express; 乘后赋值
- result /= express; 除后赋值
- result %= express; 取模后赋值
- result += express; 加后赋值
- result -= express; 减后赋值
- result <<= express; 左移后赋值
- result >>= express; 右移后赋值
- result >>>= express; 无符号右移后赋值