Maison  >  Article  >  interface Web  >  Explication détaillée des propriétés des objets en JavaScript

Explication détaillée des propriétés des objets en JavaScript

angryTom
angryTomavant
2019-11-28 17:37:252920parcourir

Explication détaillée des propriétés des objets en JavaScript

Le concept d'objets en JavaScript peut être vraiment déroutant. Regardez l'exemple suivant :

var strPrimitive = "I'm mamacat";
typeof strPrimitive; // "string"
strPrimitive instanceof String; // false

var strObject = new String("I'm mamacat");
typeof strObject; // "object"
strObject instanceof String; // true

strPrimitive.substr(8, 3); // "cat"

La même chaîne est affectée à un objet. Parfois, il s'agit d'un type chaîne et parfois d'un objet. Cependant, les variables qui ne sont évidemment pas des types d'objet peuvent toujours utiliser des attributs d'objet. Pourquoi est-ce ?

[Recommandations de cours associées : Tutoriel vidéo JavaScript]

Types et objets intégrés

Il existe six types principaux dans les types JavaScript (Langage), à ​​savoir string, number, boolean, null, undefined et object, parmi lesquels les cinq premiers types de base ne sont pas des objets (la saisie de null entraîne "object", qui est le langage lui-même BOGUE). Au-delà de cela, il existe de nombreux sous-types d'objets spéciaux, tels que des tableaux, des fonctions et des objets intégrés.

Les noms de certains objets intégrés ressemblent à des types de base simples, tels que String, Boolean, Object, etc. En termes d'expression, ces objets intégrés sont similaires au concept de « classe » dans d'autres langages orientés objet. Comme mentionné dans l'article précédent, il ne s'agit en fait que de quelques fonctions intégrées qui peuvent être utilisées pour construire une correspondance. sous-type (ne pas confondre), les fonctions sont aussi des objets, il n'y a pas de contradiction ici). Nous pouvons donc revenir à l'exemple original. strObject est une variable construite par la fonction intégrée/objet intégré String, correspondant au sous-type String, c'est donc un objet, et strPrimitive n'est qu'une valeur littérale primitive.

Bien sûr, au bas de l'exemple ci-dessus, il semble que nous ayons appelé la fonction substr() sur strPrimitive. En effet, le moteur JavaScript convertira le littéral d'origine en objet correspondant en cas de besoin, et après. la conversion On peut naturellement utiliser des attributs pour accéder aux méthodes correspondantes.

Propriétés de l'objet

Ainsi, pour l'exemple ci-dessus, l'instance de l'objet String aura la fonction substr() disponible, mais selon l'article précédent, nous pouvons savoir que ces « fonctions » elles-mêmes n'appartiennent pas à un objet, mais ces fonctions sont essentiellement un attribut de l'objet correspondant. Bien sûr, même si nous disons qu'un certain type d'objet lui-même possède divers attributs, en fait ces attributs existent pour la plupart indépendamment, mais sont simplement liés entre eux sous forme de références. Cela n'est pas incompatible avec ce que nous avons appris auparavant. Ces éléments liés sont appelés propriétés de l’objet.

Copie d'objets

Insérer un rapport rapide Bien que mentionné dans l'article précédent, il a été souligné à plusieurs reprises ci-dessus que les attributs ne sont que des entités indépendantes liées dans le. forme de références. Oui, nous « tenons encore parfois pour acquis » que les attributs font partie de l'objet, et l'un des endroits les plus faciles à avoir des ennuis est la copie d'objets. Si vous y réfléchissez bien, vous saurez que lorsque nous copions un objet, puisque ses attributs eux-mêmes ne sont que des associations de références, les références d'attribut contenues dans l'objet "copié" pointent en fait vers le même emplacement que les références d'attribut de l'objet d'origine. :

var ori = { a : 1};
var ori_copy = ori;
ori.a = 61;
ori_copy.a; // 61

Évidemment, cela peut être différent de nos attentes, et si nous voulons véritablement copier l'objet, il n'y a pas de solution parfaitement applicable. Dans de nombreux cas, la pratique courante consiste à sérialiser l'objet puis à le désérialiser. . Obtenez un nouvel objet pour copier l'objet (par exemple en utilisant json). ES6 a ajouté Object.assign() pour effectuer une copie superficielle d'un objet en attribuant toutes les propriétés énumérables de l'objet au nouvel objet. Cependant, il convient de noter que l'attribution du signe égal n'attribue pas les méta-informations de l'attribut (descripteur d'attribut, décrit plus loin), vous devez donc y prêter une attention particulière si nécessaire.

Accès aux attributs et tableau

La façon d'accéder aux propriétés associées à l'objet se fait via l'opérateur , obj.a et obj["a" . ] Les attributs accédés sont essentiellement les mêmes, et la seule différence entre ces deux formes d'accès est de savoir s'il peut y avoir des symboles étranges dans les noms des attributs accédés. Ce qui est lancé dans l'opérateur [] est une chaîne. En fait, le nom de l'attribut est toujours une chaîne. Bien sûr, ce qui peut être surprenant dans ce concept, c'est que l'accès aux tableaux en indice ne fait pas exception. Les nombres sont toujours convertis en chaînes avant d'être utilisés.

// 对象的属性访问:
var tejilang = {1 : "Teji Wolf"};
tejilang instanceof Array; // false
tejilang["1"]; // "Teji Wolf"
tejilang[1]; // "Teji Wolf"

// 这回保证它是 Array
var macat = ["codingcat"];
macat instanceof Array; // true
macat.length; // 1
macat[0]; // "codingcat"
macat["0"]; // "codingcat"
macat.length = 20;
macat; // (20) ["codingcat", empty × 19]

数组下标既然不属例外情况,那数组对象必然有其它属性控制数组本身的行为,例如上例中,macat 数组的长度就是 length 属性所体现的,通过修改它的值也就改变了对象本身对外的表现形式。当然,由于数组本身就是对象,所以我们还是可以把数组当键值对来用,只是这种做法通常是没有意义且会让人感到困惑的。JavaScript 引擎通常都根据对象的类型做了不同程度的优化,故除了代码逻辑可读性外,合理的使用也是多少可以改善性能的。

能够通过字符访问属性还是存在一些别的好处的,比如 ES6 的可计算属性名。当然 ES6 不在本文的关注范围内,所以这里就不再讨论了。

属性描述符

有时我们可能不希望某个属性被随意修改,有时候我们需要额外配置一些属性的信息,自 ES5 起,所有的属性就都具备了“属性描述符”(Property Descriptor)来控制属性本身的这些元信息。

数据描述符

来看这个例子:

var chris = {};
Object.defineProperty(chris, "IQ", {
    value: 228,
    writable: false,
    configurable: true,
    enumerable: true
});
chris.IQ = 61; // 静默失败了,如果是严格模式则会 TypeError
chris.IQ; // 228

通过 defineProperty 可以对一个对象的属性配置其对应的属性描述符(元信息),而属性描述符则包含访问描述符和数据描述符,上面的例子中,defineProperty 的第三个参数就定义了数据的若干数据描述符,其中 writable 表示可写,configurable 表示属性是否可配置(注意,修改成不可配置是单向操作),enumerable 则表示属性是否应当出现在枚举中,比如 for..in 中。

显然我们可以通过属性描述符实现对属性的保护,而同时也存在一些方便函数来做近似的事。如 Object.preventExtensions() 会保留原有属性但禁止添加新属性,Object.seal() 会密封对象,在禁止添加新属性的基础上把原有属性标记为不可配置,Object.freeze() 会冻结对象,即在密封的基础上把数据访问属性标记为不可写。

[[Get]], [[Put]] 和访问描述符

在我们访问和赋值一个对象的属性时,实际上是通过 [[Get]] 和 [[Put]] 操作进行的,例如属性访问时,[[Get]] 会先找有没有这个属性,如果没有则会遍历对象的 [[Prototype]] 链(原型链,这次不谈这个概念)来找,实在找不到则返回 undefined 。而这个行为实际是允许我们通过设置 getter (get())和 setter (set())函数来改变的,它们被称为 访问描述符。

当我们提供访问描述符时,对应的访问操作就不再受到 value writable 属性的影响了,另外需要注意的是,尽管它们也是属性描述符,但定义 getter 和 setter 并不要求一定要通过 defineProperty 设置:

var obj = {
    get a() { // 给 a 属性定义 getter
        return this._a_;
    },
    set a(val) { // a 属性的 setter
        this._a_ = val * 2;
    }
}

obj.a = 2;
obj.a; // 4

属性存在性

因为属性的值也可能是 undefined,不存在的属性直接访问得到的也是 undefined,所以直接通过简单的属性访问是无法区分是否存在的,这时我们即可通过 in 或者 hasOwnProperty() 检查属性是否存在对象中了:

var obj = {a : 2};
"a" in obj; // true
obj.hasOwnProperty("a"); // true

尽管仍没有讲到原型链的概念,这里仍然应注意,in 操作符会检查原型链中是否存在属性,而 hasOwnProperty 则不会。另外在一些情况下,有的对象会没有 hasOwnProperty 这个属性(此处不提原因),这时可以用过 Object.prototype.hasOwnProperty.call(objName, propertyName) 来实现检查。

本文来自 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:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer