Maison >interface Web >js tutoriel >Compréhension approfondie des types de données js

Compréhension approfondie des types de données js

小云云
小云云original
2018-03-29 17:18:491468parcourir

Cet article partage principalement avec vous une compréhension approfondie des types de données js

Dans la spécification ECMAScript, un total de 7 types de données sont définis, divisés en deux catégories : les types de base et les types de référence, comme indiqué ci-dessous :

Types de base : Chaîne, Nombre, Booléen, Symbole, Non défini, Null

Type de référence  : Objet

Le type de base est également appelé type simple Parce qu'il occupe un espace fixe, il s'agit d'un simple segment de données. améliorer la vitesse de requête des variables, elles sont stockées dans la pile, c'est-à-dire accès par valeur.

Le type de référence est également appelé type complexe. Étant donné que la taille de sa valeur changera, il ne peut pas être stocké dans la pile, sinon il réduira la vitesse de requête des variables. la valeur est stockée dans Dans le tas, la valeur stockée dans la variable est un pointeur pointant vers la mémoire où l'objet est stocké, c'est-à-dire l'accès par adresse. En plus de l'objet, les types de référence incluent également Function, Array, RegExp, Date, etc.

Étant donné que ECMAScript est mal typé, il doit y avoir un moyen de détecter le type de données d'une variable donnée. JavaScript propose également diverses méthodes pour résoudre ce problème, mais malheureusement, les résultats obtenus par différentes méthodes sont inégaux.

Ce qui suit présente quatre méthodes couramment utilisées et analyse brièvement les problèmes de chaque méthode.

1. typeof

typeof est un opérateur avec une expression unaire à droite et renvoie le type de données de cette expression. Le résultat renvoyé est exprimé sous la forme d'une chaîne de ce type (toutes en minuscules), comprenant les 7 types suivants : nombre, booléen, symbole, chaîne, objet, non défini, fonction, etc.

typeof '';// string 有效
typeof 1;// number 有效
typeof Symbol();// symbol 有效
typeof true;//boolean 有效
typeof undefined;//undefined 有效
typeof null;//object 无效
typeof [] ;//object 无效
typeof new Function();// function 有效
typeof new Date();//object 无效
typeof new RegExp();//object 无效


Parfois, l'opérateur typeof renvoie des valeurs déroutantes mais techniquement correctes :

  • Pour les types de base, sauf null, le le résultat correct peut être renvoyé.

  • Pour les types référence, sauf fonction, le type d'objet est toujours renvoyé.

  • Pour null , renvoie le type d'objet.

  • Pour la fonction renvoie le type de fonction.

Parmi eux, null a son propre type de données Null, et les tableaux, dates et expressions régulières dans les types référence ont également leurs propres types spécifiques, et typeof ne gère que ces types. Le type en haut de sa chaîne de prototypes est renvoyé, ce qui est correct, mais ce n'est pas le résultat souhaité.

2. instanceof

instanceof est utilisée pour déterminer si A est une instance de B. L'expression est : Une instance de B. Si A est une instance de B, il est renvoyé vrai, sinon renvoie faux. Ce qui nécessite une attention particulière ici est :

instanceof détecte le prototype , et nous utilisons un morceau de pseudo-code pour simuler son processus d'exécution interne :

instanceof (A,B) = {
    var L = A.__proto__;
    var R = B.prototype;
    if(L === R) {
        //A的内部属性__proto__指向B的原型对象
        return true;
    }
    return false;
}


Comme le montre le processus ci-dessus, lorsque le __proto__ de A pointe vers le prototype de B, A est considéré comme une instance de B. Regardons quelques exemples supplémentaires :

[] instanceof Array;//true
{} instanceof Object;//true
new Date() instanceof Date;//true
 
function Person(){};
new Person() instanceof Person;
 
[] instanceof Object;//true
new Date() instanceof Object;//true
new Person instanceof Object;//true


Nous avons constaté que bien que instanceof puisse déterminer que [ ] est une instance de Array, il pense que [ ] est également une instance d'Object Pourquoi ?

Analysons la relation entre [ ], Array et Object :

从 instanceof 能够判断出 [ ].__proto__  指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最终 Object.prototype.__proto__ 指向了null,标志着原型链的结束。因此,[]、Array、Object 就在内部形成了一条原型链:

从原型链可以看出,[] 的 __proto__  直接指向Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是Object的实例。依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。因此instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。

instanceof 操作符的问题在于,它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[0].Array;
var arr =new xArray(1,2,3);// [1,2,3]
arr instanceof Array;// false


针对数组的这个问题,ES5 提供了 Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型,而不区分该对象在哪个环境中创建。

if (Array.isArray(value)){
   //对数组执行某些操作
}


Array.isArray() 本质上检测的是对象的 [[Class]] 值,[[Class]] 是对象的一个内部属性,里面包含了对象的类型信息,其格式为 [object Xxx] ,Xxx 就是对应的具体类型 。对于数组而言,[[Class]] 的值就是 [object Array] 。

3、constructor

当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。如下所示:

当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F

可以看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上, 从原型链角度讲,构造函数 F 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。

同样,JavaScript 中的内置对象在内部构建时也是这样做的:

细节问题:

  • null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

  • 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

为什么变成了 Object?

因为 prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。

因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。

4、toString

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString()  就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

Object.prototype.toString.call('') ;  // [object String]
Object.prototype.toString.call(1) ;   // [object Number]
Object.prototype.toString.call(true) ;// [object Boolean]
Object.prototype.toString.call(Symbol());//[object Symbol]
Object.prototype.toString.call(undefined) ;// [object Undefined]
Object.prototype.toString.call(null) ;// [object Null]
Object.prototype.toString.call(new Function()) ;// [object Function]
Object.prototype.toString.call(new Date()) ;// [object Date]
Object.prototype.toString.call([]) ;// [object Array]
Object.prototype.toString.call(new RegExp()) ;// [object RegExp]
Object.prototype.toString.call(new Error()) ;// [object Error]
Object.prototype.toString.call(document) ;// [object HTMLDocument]
Object.prototype.toString.call(window) ;//[object global] window是全局对象 global 的引用

 相关推荐:

js数据类型详解

七种js数据类型分享

js数据类型的转换实例

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn