前言
以下内容是自我学习和整理,如有错误欢迎指出
- typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型.
用来判断基本数据类型
MDN
| 类型 | 结果 |
|---|---|
| Undefined | "undefined" |
| Null | "object" |
| Boolean | "boolean" |
| Number | "number" |
| BigInt(ECMAScript 2020 新增) | "bigint" |
| String | "string" |
| Symbol (ECMAScript 2015 新增) | "symbol" |
| 宿主对象(由 JS 环境提供) | 取决于具体实现 |
| Function 对象 (按照 ECMA-262 规范实现 [[Call]]) | "function" |
| 其他任何对象 | "object" |
// 数值
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof(42) === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管它是 "Not-A-Number" (非数值) 的缩写
typeof Number(1) === 'number'; // Number 会尝试把参数解析成数值
// Bigint
typeof 42n === 'bigint';
//当前所有的浏览器都暴露了一个类型为 undefined 的非标准宿主对象
typeof document.all === 'undefined';
// 字符串
typeof '' === 'string';
typeof '1' === 'string'; // 注意内容为数字的字符串仍是字符串
typeof (typeof 1) === 'string'; // typeof 总是返回一个字符串
typeof String(1) === 'string'; // String 将任意值转换为字符串,比 toString 更安全
// 布尔值
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(1) === 'boolean'; // Boolean() 会基于参数是真值还是虚值进行转换
typeof !!(1) === 'boolean'; // 两次调用 ! (逻辑非) 操作符相当于 Boolean()
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';
// 对象
typeof {a: 1} === 'object';
// 区分数组和普通对象
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
typeof /regex/ === 'object';
// 下面的例子令人迷惑,非常危险,没有用处。避免使用它们。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
// 函数
typeof function() {} === 'function';
typeof class C {} === 'function'
typeof Math.sin === 'function';
// null
typeof null === 'object'; // JavaScript 诞生以来便如此,在JavaScript最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 `null` 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,`typeof null` 也因此返回 `"object"`
/**
* 在ECMAScript2015之前,typeof总能保证对任何所给的操作数返回一个字符串。
* 即便是没有声明的标识符,typeof 也能返回 'undefined'。使用typeof永远不会抛出错误。
* 但在加入了块级作用域的[let]之后,在其被声明之前对块中的 let 和 const 变量使用
* typeof 会抛出一个[ReferenceError]块作用域变量在块的头部处于“[暂存死区]”直至其被初始化,在这期间,访问变量将会引发错误。
*/
typeof undeclaredVariable === 'undefined';
typeof newLetVariable; // ReferenceError
typeof newConstVariable; // ReferenceError
typeof newClass; // ReferenceError
let newLetVariable;
const newConstVariable = 'hello';
class newClass{};
- instanceof
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
/**
* 需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,
* 因为 Foo.prototype 属性的值有可能会改变,改变之后的值很有可能不存在于 obj 的原型链上,
* 这时原表达式的值就会成为 false。另外一种情况下,原表达式的值也会改变,就是改变对象 obj 的原型链的情况,
* 虽然在目前的ES规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的 __proto__ 伪属性,是可以实现的。
* 比如执行 obj.__proto__ = {} 之后,obj instanceof Foo 就会返回 false 了。
*/
// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype 不在 o 的原型链上
o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上
- 手写实现instanceof
/**
*
* @param {*} obj 实例对象
* @param {*} func 构造函数
* @return true / false
*/
const myInstanceOf = (obj, func) => {
if (obj === null || typeof obj !== 'object') {
return false
}
let proto = Object.getPrototypeOf(obj)
if (proto === func.prototype) {
return true
}
if (proto === null) {
return false
}
return myInstanceOf(proto, func)
}
// 测试
let Fn = function () { }
let instance = new Fn()
console.log(myInstanceOf({}, Object)) // true
console.log(myInstanceOf(instance, Fn)) // true
console.log(myInstanceOf({}, Fn)) // false
console.log(myInstanceOf(null, Fn)) // false
- Object.prototype.toString()
toString() 方法返回一个表示该对象的字符串。
/**
* 可以通过 toString() 来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString() 来检测,
* 需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,
* 传递要检查的对象作为第一个参数,称为 thisArg。
*/
let toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
用toString()封装一个判断数组或者对象
const isType = type => target => Object.prototype.toString.call(target) === `[object ${type}]`
const isArray = isType('Array')
const isObject = isType('Object')
//测试
console.log(isArray([])) // true
console.log(isObject({})) // true
console.log(isObject(null)) // false