# instanceof 原理
-
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
- 语法
object instanceof constructor
- 参数
object(某个实例对象)
、 constructor(某个构造函数)
- 本质上
instanceof
运算符用来检测 constructor.prototype
是否存在于参数 object
的原型链上。
| function _instanceof(target, origin) { |
| |
| if (typeof target !== 'object') return false |
| |
| |
| while (target) { |
| if (Reflect.getPrototypeOf(target) === origin.prototype) return true |
| |
| |
| target = Reflect.getPrototypeOf(target) |
| } |
| return false |
| } |
# instanceof 测试
| function Foo() { } |
| const f = new Foo |
| |
| f instanceof Foo |
| f instanceof Object |
| f instanceof Function |
| |
| 'abc' instanceof String |
| 123 instanceof Number |
| [] instanceof Array |
| {} instanceof Object |
| (() => {}) instanceof Object |
| (() => {}) instanceof Function |
| (() => {}) instanceof Array |
# _instanceof 测试
| function Foo() { } |
| const f = new Foo |
| |
| _instanceof(f, Foo) |
| _instanceof(f, Object) |
| _instanceof(f, Function) |
| |
| _instanceof('abc', String) |
| _instanceof(123, Number) |
| _instanceof([], Array) |
| _instanceof({}, Object) |
| _instanceof(() => {}, Object) |
| _instanceof(() => {}, Function) |
| _instanceof(() => { }, Array) |
# new 原理
# Object.setPrototypeOf 实现
| function _new(fn, ...args) { |
| |
| const obj = {} |
| |
| |
| Object.setPrototypeOf(obj, fn.prototype) |
| |
| |
| const result = fn.apply(obj, args) |
| |
| |
| return Object.prototype.toString.call(result) === '[object Object]' ? result : obj |
| } |
| function Foo() {} |
| const foo = new Foo() |
| |
| _new(Foo) instanceof Foo |
| foo instanceof Foo |
# Object. create 实现
| function _new(fn, ...args){ |
| |
| const obj = Object.create(fn.prototype); |
| |
| |
| const result = fn.apply(obj, args); |
| |
| |
| return Object.prototype.toString.call(result) === '[object Object]' ? result : obj |
| } |
| function Foo() {} |
| const foo = new Foo() |
| |
| _new(Foo) instanceof Foo |
| foo instanceof Foo |
# typeof 原理
-
typeof
一般被用于判断一个变量的类型,我们可以利用 typeof
来判断 number
, string
, object
, boolean
, function
, undefined
, symbol
这七种类型
-
这种判断能帮助我们搞定一些问题,比如在判断不是 object 类型的数据的时候, typeof
能比较清楚的告诉我们具体是哪一类的类型。
-
但是,很遗憾的一点是, typeof
在判断一个 object 的数据的时候只能告诉我们这个数据是 object, 而不能细致的具体到是哪一种 object
-
, 比如我们都知道 typeof(null) === 'object'
,关于原因,在小黄书《你不知道的 JavaScript》中有这么一段解释:
原理是这样的, 不同的对象在底层都表示为二进制, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0, 自然前三位也是 0, 所以执行 typeof 时会返回 “object”。
-
javascript 中的 null
:既是对象,又不是对象,史称「薛定谔的对象」。
| typeof null === 'object' |
| null instanceof Object |
- 会抛出异常:
TypeError: invalid 'instanceof' operand null
- 在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息:
- 000:对象
- 1:整数
- 010:浮点数
- 100:字符串
- 110:布尔
- 有 2 个值比较特殊:
- undefined:用 - (−2^30)表示。
- null:对应机器码的 NULL 指针,一般是全零。
- 在第一版的 javascript 实现中,判断类型的代码是这么写的:
| if (JSVAL_IS_VOID(v)) { |
| type = JSTYPE_VOID; |
| } else if (JSVAL_IS_OBJECT(v)) { |
| obj = JSVAL_TO_OBJECT(v); |
| if (obj && |
| (ops = obj->map->ops, |
| ops == &js_ObjectOps |
| ? (clasp = OBJ_GET_CLASS(cx, obj), |
| clasp->call || clasp == &js_FunctionClass) |
| : ops->call != 0)) { |
| type = JSTYPE_FUNCTION; |
| } else { |
| type = JSTYPE_OBJECT; |
| } |
| } else if (JSVAL_IS_NUMBER(v)) { |
| type = JSTYPE_NUMBER; |
| } else if (JSVAL_IS_STRING(v)) { |
| type = JSTYPE_STRING; |
| } else if (JSVAL_IS_BOOLEAN(v)) { |
| type = JSTYPE_BOOLEAN; |
| } |
- 判断是否为 undefined
- 如果不是 undefined,判断是否为对象
- 如果不是对象,判断是否为数字
- ......
- 这样一来,
null
就出了一个 bug。根据 type tags 信息,低位是 000
,因此 null
被判断成了一个对象。这就是为什么 typeof null
的返回值是 object
。
- 摘自:https://cloud.tencent.com/developer/article/1362660