Maison > Article > interface Web > Explication détaillée des objets de base JavaScript (organisés et partagés)
Cet article vous apporte des connaissances pertinentes sur les objets en JavaScript. Les objets en JavaScript sont également des variables, mais les objets contiennent de nombreuses valeurs. J'espère que cela vous sera utile après avoir lu cet article.
JavaScript a six types de langage principaux :
chaîne, nombre, booléen, non défini, nul, objet
Types de base : chaîne, nombre, booléen, non défini, null ; le type primitif lui-même n’est pas un objet.
Mais null est parfois considéré comme un objet, et typeof null renverra un objet. En fait, null est un type de base. La raison en est que différents objets sont représentés comme binaires au niveau inférieur. En JavaScript, si les trois premiers chiffres du binaire sont 0, il sera jugé comme type d'objet, et null signifie que tous les 0, donc typeof renverra l'objet.
Les tableaux sont également un type d'objet avec des comportements supplémentaires. L'organisation des tableaux est plus complexe que celle des objets ordinaires.
La fonction est essentiellement la même qu'une fonction ordinaire, sauf qu'elle peut être appelée, vous pouvez donc utiliser des fonctions comme des objets.
Chaîne
Numéro
Date
Booléen
Objet
Fonction
Tableau
.a est appelé accès aux attributs, ['a'] est appelé accès opérateur.
//对象中的属性名始终是字符串 myobj={} myobj[myobj]='bar'//赋值 myobj['[object object]'] //'bar'
es6 Ajout d'un nom d'attribut calculable, vous pouvez utiliser [] sous forme de texte pour envelopper une expression comme nom d'attribut
var perfix = 'foo' var myobj={ [perfix + 'bar'] :'hello' } myobj['foobar']//hello
À partir d'es5, tous les attributs ont Avec l'attribut descripteur, par exemple, vous pouvez déterminer directement si l'attribut est lisible et inscriptible.
/* * 重要函数: * Object.getOwnPropertyDescriptor(..) //获取属性描述符 * Object.defineProperty(..) //设置属性描述符 */ writeble(可读性) configurable(可配置性) enumerable (可枚举性)
for in peut être utilisé pour parcourir la liste d'attributs énumérables d'un objet (y compris la chaîne [[Prototype]]), et vous devez obtenir manuellement la valeur de l'attribut. Peut traverser des tableaux et des objets ordinaires
es6 est nouveau et peut être utilisé pour parcourir les valeurs d'attribut des tableaux. La boucle for of demandera d'abord un objet itérateur à l'objet accédé, puis appellera ensuite. (de l'objet itérateur) pour parcourir toutes les valeurs de retour.
Les tableaux ont des @@iterators intégrés,
var arr = [1, 2, 3] var it = arr[Symbol.iterator]()//迭代器对象 console.log(it.next());//{value: 1, done: false} console.log(it.next());//{value: 2, done: false} console.log(it.next());//{value: 3, done: false} console.log(it.next());//{value: undefined, done: true} /* * 用es6 的Symbol.iterator 来获取对象的迭代器内部属性。 * @@iterator本身并不是一个迭代器对象,而是一个返回迭代器对象的函数。 */
Étant donné que l'objet n'a pas d'@@iterator intégré, for...of traversal ne peut pas être automatiquement complété. Cependant, vous pouvez définir @@iterator pour tout objet que vous souhaitez parcourir, par exemple :
var obj={ a:1,b:2 } Object.defineProperty(obj, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function () { var self = this var idx = 0 var ks = Object.keys(self) return { next: function () { return { value: self[ks[idx++]], done: (idx > ks.length) } } } } }) //手动遍历 var it = obj[Symbol.iterator]()//迭代器对象 console.log(it.next());//{value: 1, done: false} console.log(it.next());//{value: 2, done: false} console.log(it.next());//{value: undefined, done: true} //for of 遍历 for (const v of obj) { console.log(v); } //2 //3
/* forEach:会遍历所有并忽略返回值 some:会一直运行到回调函数返回 true(或者"真"值) every:会一直运行到回调函数返回 false(或者"假"值) map: filter:返回满足条件的值 reduce: some和every 和for的break语句类似,会提前终止遍历 */
Heap : allocation dynamique La taille de la mémoire est variable et ne sera pas libéré automatiquement. Les valeurs de type référence y sont stockées
Copie superficielle : Une copie superficielle d'un objet copiera l'objet « principal », mais ne copiera pas les objets à l'intérieur de l'objet. L'« objet intérieur » est partagé entre l'objet original et sa copie.
Copie approfondie : une copie approfondie d'un objet copie non seulement chaque attribut de l'objet d'origine un par un, mais copie également de manière récursive les objets contenus dans chaque attribut de l'objet d'origine vers le nouvel objet en utilisant la méthode de copie approfondie , donc les modifications apportées à un objet n'affectent pas l'autre objet.
Par exemple :
var anotherObject={ b:"b" } var anotherArray=[] var myObject={ a:'a', b:anotherObject, //引用,不是副本 c:anotherArray //另外一个引用 } anotherArray.push(anotherObject,myObject) /* 如何准确的复制 myObject? 浅复制 myObject,就是复制出 新对象中的 a 的值会复制出对象中a 的值,也就是 'a', 但是对象中的 b、c两个属性其实只是三个引用,新对象的b、c属性和旧对象的是一样的。 深复制 myObject,除了复制 myObject 以外还会复制 anotherObject 和 anotherArray。 但是这里深复制 myObject会出现一个问题,anotherArray 引用 anotherObject 和 myObject, 所以又需要复制 myObject,这样就会由于循环引用导致死循环。 后面会介绍如何处理这种情况。 */Comment implémenter une copie superficielleobjectobject.assign(), spread Operator (...)
var obj1 = {x: 1, y: 2} var obj2 = Object.assign({}, obj1); console.log(obj1) //{x: 1, y: 2} console.log(obj2) //{x: 1, y: 2} obj2.x = 2; //修改obj2.x console.log(obj1) //{x: 1, y: 2} console.log(obj2) //{x: 2, y: 2} var obj1 = { x: 1, y: { m: 1 } }; var obj2 = Object.assign({}, obj1); console.log(obj1) //{x: 1, y: {m: 1}} console.log(obj2) //{x: 1, y: {m: 1}} obj2.y.m = 2; //修改obj2.y.m console.log(obj1) //{x: 1, y: {m: 2}} console.log(obj2) //{x: 2, y: {m: 2}}Arrayslice(), concat, Array.from(), spread symbole d'opérateur (...), concat, for loop
var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice(); console.log(arr1); //[1, 2, [3, 4]] console.log(arr2); //[1, 2, [3, 4]] arr2[0] = 2 arr2[2][1] = 5; console.log(arr1); //[1, 2, [3, 5]] console.log(arr2); //[2, 2, [3, 5]]Comment implémenter la copie profondeJSON.parse(JSON.stringify(obj))Pendant le processus de sérialisation de JSON.stringify(), fonctions arbitraires non définies et les symboles Les valeurs seront ignorées lors de la sérialisation (lors de leur apparition dans les valeurs de propriété d'objets non-tableaux) ou converties en null (lors de leur apparition dans des tableaux).
var obj1 = { x: 1, y: { m: 1 }, a:undefined, b:function(a,b){ return a+b }, c:Symbol("foo") }; var obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ƒ, c: Symbol(foo)} console.log(obj2) //{x: 1, y: {m: 1}} obj2.y.m = 2; //修改obj2.y.m console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ƒ, c: Symbol(foo)} console.log(obj2) //{x: 2, y: {m: 2}}Implémentation simple de la fonction de copie profonde
function deepClone(obj){ let result = Array.isArray(obj)?[]:{}; if(obj && typeof obj === "object"){ for(let key in obj){ if(obj.hasOwnProperty(key)){ if(obj[key] && typeof obj[key] === "object"){ result[key] = deepClone(obj[key]); }else{ result[key] = obj[key]; } } } } return result; } var obj1 = { x: { m: 1 }, y: undefined, z: function add(z1, z2) { return z1 + z2 }, a: Symbol("foo"), b: [1,2,3,4,5], c: null }; var obj2 = deepClone(obj1); obj2.x.m = 2; obj2.b[0] = 2; console.log(obj1); console.log(obj2); //obj1 { a: Symbol(foo) b: (5) [1, 2, 3, 4, 5] c: null x: {m: 1} y: undefined z: ƒ add(z1, z2) } //obj2 { a: Symbol(foo) b: (5) [2, 2, 3, 4, 5] c: null x: {m: 2} y: undefined z: ƒ add(z1, z2) }
function deepClone(obj, parent = null){ // 改进(1) let result = Array.isArray(obj)?[]:{}; let _parent = parent; // 改进(2) while(_parent){ // 改进(3) if(_parent.originalParent === obj){ return _parent.currentParent; } _parent = _parent.parent; } if(obj && typeof obj === "object"){ for(let key in obj){ if(obj.hasOwnProperty(key)){ if(obj[key] && typeof obj[key] === "object"){ result[key] = deepClone(obj[key],{ // 改进(4) originalParent: obj, currentParent: result, parent: parent }); }else{ result[key] = obj[key]; } } } } return result; } // 调试用 var obj1 = { x: 1, y: 2 }; obj1.z = obj1; var obj2 = deepClone(obj1); console.log(obj1); console.log(obj2);La version finale de la fonction de copie approfondie (prend en charge les types de données de base, les chaînes de prototypes, RegExp, les types de date)
function deepClone(obj, parent = null){ let result; // 最后的返回结果 let _parent = parent; // 防止循环引用 while(_parent){ if(_parent.originalParent === obj){ return _parent.currentParent; } _parent = _parent.parent; } if(obj && typeof obj === "object"){ // 返回引用数据类型(null已被判断条件排除)) if(obj instanceof RegExp){ // RegExp类型 result = new RegExp(obj.source, obj.flags) }else if(obj instanceof Date){ // Date类型 result = new Date(obj.getTime()); }else{ if(obj instanceof Array){ // Array类型 result = [] }else{ // Object类型,继承原型链 let proto = Object.getPrototypeOf(obj); result = Object.create(proto); } for(let key in obj){ // Array类型 与 Object类型 的深拷贝 if(obj.hasOwnProperty(key)){ if(obj[key] && typeof obj[key] === "object"){ result[key] = deepClone(obj[key],{ originalParent: obj, currentParent: result, parent: parent }); }else{ result[key] = obj[key]; } } } } }else{ // 返回基本数据类型与Function类型,因为Function不需要深拷贝 return obj } return result; } // 调试用 function construct(){ this.a = 1, this.b = { x:2, y:3, z:[4,5,[6]] }, this.c = [7,8,[9,10]], this.d = new Date(), this.e = /abc/ig, this.f = function(a,b){ return a+b }, this.g = null, this.h = undefined, this.i = "hello", this.j = Symbol("foo") } construct.prototype.str = "I'm prototype" var obj1 = new construct() obj1.k = obj1 obj2 = deepClone(obj1) obj2.b.x = 999 obj2.c[0] = 666 console.log(obj1) console.log(obj2) console.log(obj1.str) console.log(obj2.str)
bind() : utilisez fn.bind() pour faire une copie complète de la fonction, mais elle ne peut pas être utilisée à cause du problème de ce pointeur
eval(fn.toString()) : ne prend en charge que les fonctions fléchées, ordinaires ; function function fn() {} n'est pas applicable ;
new Function(arg1, arg2,…,function_body) : Les paramètres et le corps de la fonction doivent être extraits ;
PS : Généralement, il n'est pas nécessaire de copier en profondeur Function.
【Recommandations associées : Tutoriel d'apprentissage Javascript】
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!