资讯专栏INFORMATION COLUMN

JavaScript 三种方法,可以确定一个值到底是什么类型

RyanHoo / 817人阅读

JavaScript 三种方法,可以确定一个值到底是什么类型。
typeof
instanceof
Object.prototype.toString
为什么需要确定类型 ?

​ 只有确定类型的情况,才知道当前操作对象拥有哪些功能; 比如使用 push,unshfit,shfit 等方法时,那么其必须为数组类型时才能正确使用;

​ 当某些情况添加类型检查时,这样代码更加健壮,安全;

typeof 运算符
返回一个值的数据类型。

基本语法:

typeof operand
or
typeof (operand)

operand 是一个表达式,表示对象或原始值,其类型将被返回。括号是可选的.

示例:基本数据类型
{

    typeof 1            // "number"
    typeof Number(1)    // "number"
    typeof ""           // "string"
    typeof true         // "boolean"
    typeof null         // "object"
    typeof undefined    // "undefined"
    typeof Symbol       // "function"

}

当操作数(operand)为基本数据类型,其返回字符串与期望一样,也能够辨别当前操作数得类型;

这里需要提及下基本数据类型 null ,为什么 typeof null 返回的字符串为 "object";

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了"object"

示例:引用数据类型
    typeof new Number(1)          //  "object"
    typeof new String()         //  "object"
    typeof new Array()          //  "object" 
    typeof new Date()             //  "object"
    
     typeof new Function()       //  "function"

从上面看出,所有通过 new 关键实例化的构造函数返回都 object 类型. 当然函数是一个例外;

从上述两个示例可以看出,当typeof 的操作数为基本数据类型、函数返回字符串能够区分其数据类型;

那么如果需要区分引用类型时需要借助 JavaScript中另外一个运算符;

instanceof 运算符
判断实例对象是不是类(构造函数)的实例

instanceof 工作原理基于原型链,也就是说如果在对象的原型链上能够找到构造函数的 prototype 对象,那么该操作就返回 true;

基本语法:**

    object instanceof constructor

参数

object
要检测的对象.

constructor
某个构造函数

示例一:
let o = new Object();
let bool = new Boolean();
let num = new Number(1);
let str = new String();
let arr = new Array();
// 自定义构造函数
function Person(){} 
function Animal(){} 

let person = new Person();
let animal = new Animal();
person instanceof Person   // true
animal instanceof Animal   // true

o instanceof Object;       // true
bool instanceof Boolean;   // true
num instanceof Number;     // true
str instanceof String;     // true
arr instanceof Array;      // true

这样弥补 typeof 在检测引用类型的时的问题;

通过下面的示例,验证下 instanceof 工作原理:

{
    function Person(){}
    function Animal(){}

    // 例如自定义定义两个类
    let person = new Person();
    let animal = new Animal();


    console.log(animal instanceof Object);  // =>  true
    console.log(animal instanceof Animal);   // true

    console.log(person instanceof Object); // =>  true
    console.log(person instanceof Person);  // true

    console.log(person instanceof Animal);  // =>  false
    console.log(animal instanceof Person);  // =>  false
}

上面应该跟我们预期的一样, 那么有没有通过一种办法让

person instanceof Animal  // => true

那么来针对上面作如下调整:

person.__proto__ = Animal.prototype;
console.log(person instanceof Animal) // => true
console.log(person instanceof Person) // => false

严格意义上来说, 上述这么改是没有意思;这里只是为了验证 instanceof 如何工作的;其次说明 person instanceof Person 返回 true, 则并不意味着给表达式永远返回 true, Person.prototypeperson.__proto__ 都是可变的;

instanceof 和多个全局对象(多个frame或多个window之间的交互)

可以定义两个页面测试: parent.html、 child.html

//    parent.html

    
    
//  child.html
    

严格上来说value 就是数组,但parent页面中打印输出: false ;也就是 parent 页面中 Array.prototype != window.frames[0].Array.prototype ;

主要引起问题是,因为多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数.

instanceof 应用 - 检测作用域的安全
function Person(name, age){
    this.name = name;
    this.age = age
}

// 正常情况下
{
    let person = new Person("托尼", 20);
    console.log(person.name,person.age);
}

// 假如在实例化时候忘记添加 new 关键字尼? 会出现什么情况尼?
{
     let person = Person("托尼", 20);
    console.log(person.name, person.age);  // Uncaught TypeError: Cannot read property "name" of undefined
    
    // Person 被当作普通的方法执行,其次 name ,age 被添加window上
    console.log(name, age); //=> 托尼 20
}

// 如何避免这样情况,在加 new 关键字或省略时候都能正常返回实例对象 
{
    function Person(name, age){
        if(this instanceof Person) {
            this.name = name;
            this.age = age
            return this;
        }else {
            return new Person(name, age);
        }
    }
    
    let person = Person("托尼", 20);
    console.log(person.name, person.age);  // 托尼 20
}
Object.prototype.toString 方法

默认情况下(不覆盖 toString 方法前提下),任何一个对象调用 Object 原生的 toString 方法都会返回 "[object type]",其中 type 是对象的类型;
每个类的内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的 type(构造函数名) ;

举个例子吧:

console.log(Object.prototype.toString.call([])); // [object Array]

上述中: Array 对应也就当前对象的 type,同样就是当前对象的构造函数名;

前面在说 instanceof 在多个作用域的情况下,尝试用这种方式解决:

  function isArray(arr){
      return Object.prototype.toString.call(arr) === "[object Array]"
  }
  
  console.log(isArray(value)); // true

从输出来看时完美解决了;

为什么这种方式是可以咧?这里辨别类型根据 构造函数名称,由于原生数组的构造函数名称与全局作用域无关,因此使用 toString() 就能保证返回一致的值。

同理其它原生对象检测也能按照这种方式来,如 Date,RegExp,Function

function isFunction(value) {
        return Object.prototype.toString.call(value) === "[object Function]"
    }
function isDate(value) {
        return Object.prototype.toString.call(value) === "[object Date]"
    }
function isRegExp(value) {
        return Object.prototype.toString.call(value) === "[object RegExp]"
    }

isDate(new Date()); // true
isRegExp(/w/);        // true
isFunction(function(){}); //true

上述代码,可以作进一步改进,由于 isFunction、isDate、isRegExp 方法中,其实只有 [object ConstructorName] ConstructorName不一样,可以利用工厂函数再修饰一下:

 function generator(type){
        return function(value){
            return Object.prototype.toString.call(value) === "[object "+ type +"]"
        }
    }

 let isFunction = generator("Function")
 let isArray = generator("Array");
 let isDate = generator("Date");
 let isRegExp = generator("RegExp");

isArray([]));    // true
isDate(new Date()); // true
isRegExp(/w/);        // true
isFunction(function(){}); //true

这样即使要生成其它原生对象验证函数前面时就简单多了;

总结:

typeof 适用于检测值类型, 特别注意 null 的问题,这也是面试用经常遇到的.

instanceof 检测引用类型.

toString 弥补 instanceof 在跨窗口下对类型检测问题, toString 只适应于原生对象;
对于用户自定义的对象无法区分的.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100084.html

相关文章

  • 非科班如何理解闭包,原型,原型链,继承

    摘要:闭包,原型,原型链,继承对象若干属性的集合输出的集中类型标识,其中上面的四种属于简单的值类型,不是对象。在实际应用中如何区分一个属性到底是基本的还是从原型中找到的呢,特别是在循环中由于所有的对象的原型链都会找到,因此所有的对象都会有的方法。 闭包,原型,原型链,继承 对象——若干属性的集合 typeof输出的集中类型标识,其中上面的四种(undefined, number, strin...

    xuexiangjys 评论0 收藏0
  • 搞懂 Javascript中this 指向及继承原理

    摘要:共享原型链现在我们还有另一个对象如图那么和其实是同一东西,也就是。改进通过第一节可以知道,我们可以通过原型链来解决重复创建的问题我们先创建一个士兵原型,然后让士兵的指向士兵原型。所以这个是原型链继承的缺点,原因是和指向同一个地址即父类的。 在理解继承之前,需要知道 js 的三个东西: 什么是 JS 原型链 this 的值到底是什么 JS 的new 到底是干什么的 想阅读更多优质文章...

    why_rookie 评论0 收藏0
  • JS数据类型& 判断

    摘要:的数据类型,共有六种。通常,数值字符串布尔值这三种类型,合称为原始类型的值,即它们是最基本的数据类型,不能再细分了。运算符返回一个布尔值,表示某个对象是否为指定的构造函数的实例。 以下内容摘自阮一峰-JavaScript-标准参考教程 数据类型 JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有六种。(ES6 又新增了第七种 Symbo...

    zhangxiangliang 评论0 收藏0
  • 一道JS面试题所引发的"血案",透过现象寻本质,再从本质看现象

    摘要:一看这二逼就是周杰伦的死忠粉看看控制台输出,确实没错就是对象。从根本上来说,作用域是基于函数的,而执行环境是基于对象的例如全局执行环境即全局对象。全局对象全局属性和函数可用于所有内建的对象。全局对象只是一个对象,而不是类。 觉得本人写的不算很烂的话,可以登录关注一下我的GitHub博客,博客会坚持写下去。 今天同学去面试,做了两道面试题,全部做错了,发过来给我看,我一眼就看出来了,因为...

    QiShare 评论0 收藏0
  • javascript日期类型(Date)与php日期类型详解

    摘要:注意客户端与服务器日期进行传输的时候一般都是用大整数时间戳进行传输。 前言 一个网站的开发需要要UI、前端、后端三种工程师。现在的企业在招聘前端工程师的时候一般都要求其了解或者掌握一些后端的知识。因此,此文章主要介绍javascript的日期类型,也粗略的介绍一下php的日期类型,以及二者是如何交互数据的。 时间戳 什么是时间戳 时间戳是从格林威治时间1970年1月1日(00:0...

    chemzqm 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<