likes
comments
collection
share

JS类型判断—手写call和instanceof

作者站长头像
站长
· 阅读数 27

前言

在JavaScript这片充满活力与变数的编程疆域里,数据类型犹如变幻莫测的魔法元素,赋予了代码生命与灵魂。它们或是温顺的字符串,低吟着字符的诗篇;或是数字的洪流,精确计算着宇宙的奥秘;亦或是神秘的对象,编织着复杂而有序的信息网。然而,在这魔法的施展过程中,辨识与操控这些数据类型的真身,便成为了每位JavaScript巫师必修的基本法术。

本文,便是一段专为探索与驾驭JavaScript类型判断艺术量身定制的奇幻旅程。我们将携手踏入这片既熟悉又时常令人困惑的领域,揭开每种类型背后的秘密面纱,掌握那些在编码征途中不可或缺的“辨形术”。从朴素的typeof咒语,到进阶的instanceof与构造函数比对,再到ES6新晋贵族Array.isArrayObject.prototype.toString.call的精妙运用,每一式每一招都蕴含着转变代码世界的无限可能。

准备好了吗?让我们一同启程,不仅仅是为了学会判断,更是为了理解每一种类型的核心本质,让我们的代码如诗般优雅,如剑般锋利。在这趟旅途中,你将发现,精准的类型判断不仅是解决问题的钥匙,更是通往高效编程与逻辑思维清晰化的神秘通道。现在,让我们一同步入JavaScript类型宇宙的深邃与广阔,开始这场既实用又充满乐趣的探索吧!

正文

数据类型

原始类型

  • 数值Number
  • 字符串String
  • 布尔值Boolean
  • Null
  • Undefined
  • Symbol
  • BigInt

引用类型

  • 对象Object
  • 函数Function
  • 数组Array
  • Date

定义上面提到的所以数据类型

// 原始数据类型
let s = '123';
let n = 123;
let f = true;
let u = undefined;
let nul = null;
let sy = Symbol(123);
let b = BigInt(123);

// 引用类型
let obj = {};
let arr = [];
let fn = function () {};
let date = new Date();// date类型对象(特殊对象)

typeof

console.log(typeof(s));
console.log(typeof(n));
console.log(typeof(f));
console.log(typeof(u));
console.log(typeof(sy));
console.log(typeof(nul));// object --> 二进制前三位为0

console.log(typeof(obj));// object
console.log(typeof(arr));// object
console.log(typeof(fn));
console.log(typeof(date));// object

JS类型判断—手写call和instanceof

typeof结论

  1. 可以判断除 null 之外的所有原始类型
  2. 除了function其他所有的引用类型都会判断为object
  3. typeof是通过将值转换为二进制后判断其二进制前三位是否为0,是则为object

instanceof

console.log(obj instanceof Object);
console.log(arr instanceof Array);
console.log(obj instanceof Object);
console.log(date instanceof Date);

JS类型判断—手写call和instanceof

console.log(s instanceof String);// false

JS类型判断—手写call和instanceof

面试官叫你手写instanceof

  • 首先我们要知道arr.__proto__ = Array.prototype;Array.prototype.__proto__ = Object.prototype;
  • 一直往上找原型,直到满足=L.__proto__ === R.prototype,同时将L.__proto__赋值给L
function myinstanceof(L, R) {
    while (L !== null) {
      if (L.__proto__ === R.prototype){
        return true;
      }
      L = L.__proto__;
    }

    return false;
}

console.log(myinstanceof([], Array));// true
console.log(myinstanceof([], Object));// true
console.log(myinstanceof({}, Array));// fals

JS类型判断—手写call和instanceof

instanceof结论

  1. 只能判断引用类型
  2. 通过原型链查找来判断类型

Object.prototype.toString.call

Object.prototype.toString(this),该方法只能判断对象类型

var a = {}
var b = new Date();
var c = function(){};
var d = [];
var e = 123;
console.log(Object.prototype.toString(a));
console.log(Object.prototype.toString(b));
console.log(Object.prototype.toString(c));
console.log(Object.prototype.toString(d));
console.log(Object.prototype.toString(e));

JS类型判断—手写call和instanceof

步骤 1.如果 this 值未定义, 返回“[对象未定义]” 2. 如果 此值为 null, 返回“[object Null]” 3. 将 O 作为 ToObject(this) 的执行结果 4. 定义一个class作为内部属性 [[class]] 的值 5. 返回由 "[object" 和 class 和 "]" 组成的字符串

Object.prototype.toString.call(xxx)

用来获取对象类型的标准且可靠的方法,利用了Object.prototype.toString方法,并通过.call()方法改变其内部的this绑定,使其能够应用于任何对象,从而判断该对象的具体类型

var a = {}
var b = new Date();
var c = function(){};
var d = [];
var e = 123;
console.log(Object.prototype.toString.call(a));
console.log(Object.prototype.toString.call(b));
console.log(Object.prototype.toString.call(c));
console.log(Object.prototype.toString.call(d));
console.log(Object.prototype.toString.call(e));

JS类型判断—手写call和instanceof

手写call方法(改变任意函数的调用上下文(即函数内部的this值))

  • 类型检查: 首先,通过typeof this !== 'function'检查调用mycall方法的主体(即this指向的对象)是否为函数类型。如果不是函数,则抛出一个类型错误(TypeError),提示调用者这不是一个函数。
  • 创建唯一标识符: 使用Symbol创建一个独一无二的属性名fn。这样做可以防止与对象中已存在的属性名冲突,保证临时添加的函数不会覆盖原有的属性。
  • 将函数绑定到目标对象: 将当前函数(this,即想要改变调用上下文的函数)赋值给context对象上的fn属性。这样,context对象就暂时拥有了这个函数,可以通过context[fn]来调用它。
  • 调用函数并利用隐式绑定: 接下来,通过context[fn]()执行这个函数。由于是在context对象上调用的,根据JavaScript的函数调用规则,这里的this会被绑定到context上,实现了上下文的改变。
  • 清理: 最后,通过delete context[fn]删除之前添加到context对象上的临时函数,以保持原对象的清洁,不留下任何副作用。
Function.prototype.mycall = function(context) {
    // 调用的哥们是不是函数体
    if (typeof this !== 'function' ) {
        return new TypeError(this + 'is not a function');
    }

    // this里面的this => context
    const fn = Symbol('key');
    context[fn] = this;// 让对象拥有该函数 {Symbol('key'): foo}
    context[fn]();// 触发了隐式绑定
    delete context[fn];
}

应用

var obj = {
    a:1
}
function foo() {
    console.log(this.a);
}


foo.mycall(obj);

JS类型判断—手写call和instanceof

Array.isArray

判断某个变量是否为数组类型的一个内置函数

let a = [];
let b = {};
let c = 123;
console.log(Array.isArray(a));
console.log(Array.isArray(b));
console.log(Array.isArray(c));

JS类型判断—手写call和instanceof

结语

类型判断不仅是技术的实践,更是一种编程哲学的体现,它提醒我们时刻关注数据的本质,理解每一个变量的内涵,从而在错综复杂的代码世界中游刃有余。让我们带着这份对类型深刻理解的智慧,继续在编程的浩瀚星海中探索、创造,书写更多技术与艺术完美交融的篇章。

JS类型判断—手写call和instanceof

转载自:https://juejin.cn/post/7369435074759360551
评论
请登录