Maison > interface Web > js tutoriel > le corps du texte

Analyse des différents modes de création d'objets en javascript (tutoriel graphique)

亚连
Libérer: 2018-05-21 14:15:04
original
1220 Les gens l'ont consulté

Je vais maintenant vous proposer une analyse de différents modèles de création d'objets en JavaScript. Maintenant je le partage avec vous et le donne en référence

Création d'objets en javascript

•Modèle d'usine

• Modèle de constructeur

• Modèle de prototype

• Combiner des modèles de constructeur et de prototype

• Modèle dynamique de prototype

La plupart des langages orientés objet ont le concept de classe, à travers laquelle plusieurs objets avec les mêmes méthodes et propriétés peuvent être créés. Bien que techniquement parlant, JavaScript soit un langage orienté objet, JavaScript n'a pas la notion de classes, tout est objet. Tout objet est une instance d'un certain type de référence, qui est créée via un type de référence existant ; le type de référence peut être natif ou personnalisé. Les types de référence natifs incluent : Objet, Tableau, Données, RegExp et Fonction. ! Un type référence est une structure de données qui organise les données et les fonctionnalités, souvent appelée classe. En JavaScript, qui manque du concept de classes, le problème à résoudre est de savoir comment créer efficacement des objets.

1.1.0. Méthode générale de création d'objets

var person = {}; //对象字面量表示,等同于var person = new Objcect();
person.name = 'evansdiy';
person.age = '22';
person.friends = ['ajiao','tiantian','pangzi'];
person.logName = function() {
  console.log(this.name);
}
Copier après la connexion

Basé sur le type de référence Object, un objet est créé, qui contient quatre propriétés, dont une est une méthode. Si vous avez besoin de nombreuses instances d'objets ressemblant à des personnes, il y aura beaucoup de code en double.

1.1.1. Modèle d'usine

Créez un objet via une fonction qui peut contenir les détails de l'objet, puis renvoyez l'objet.

function person(name,age,friends) {

  var o = {
    name: name,
    age: age,
    friends: friends,
    logName: function() {
      console.log(this.name);
    }
  };

  return o;

}

var person1 = person('Evansdiy','22',['ajiao','tiantian','pangzi']);
Copier après la connexion

Chaque fois que la fonction personne est appelée, un nouvel objet sera créé via l'objet o à l'intérieur de la fonction, puis renvoyé En dehors de cela, il n'y a aucun autre objet interne o qui existe à créer. utilisation de nouveaux objets. De plus, il est impossible de déterminer le type d’objet créé par le modèle d’usine.

1.1.2. Modèle de constructeur

function Person(name,age,job) {

  this.name = name;
  this.age = age;
  this.job = job;
  this.logName = function() {
    console.log(this.name);
  }

}

//通过new操作符创建Person的实例
var person1 = new Person('boy-a','22','worker');

var person2 = new Person('girl-b','23','teacher');

person1.logName(); //boy-a

person2.logName(); //girl-a
Copier après la connexion

En comparant le modèle d'usine, vous pouvez constater qu'il n'est pas nécessaire de créer des objets intermédiaires ici, et qu'il n'y en a pas. retour. De plus, l'instance du constructeur peut être identifiée comme un type spécifique, ce qui résout le problème de l'identification des objets (en vérifiant la propriété constructeur de l'instance ou en utilisant l'opérateur instanceof pour vérifier si l'instance a été créée via un certain constructeur) .

console.log(person1.constructor == Person);//constructor est situé dans le prototype du constructeur et pointe vers le constructeur, et le résultat est vrai

console.log(person1 instanceof Person); //Utilisez l'opérateur instanceof pour déterminer si person1 est une instance du constructeur Person. Mais le mode constructeur a aussi ses propres problèmes. En fait, la méthode logName sera recréée sur chaque instance. elle est créée par instanciation des méthodes et ne sont pas égales, le code suivant deviendra faux :

console.log(person1.logName == person2.logName);//false nous pouvons déplacer la méthode en dehors du constructeur. (devenir fonction globale) pour résoudre ce problème :

function logName() {
  console.log(this.name);
}

function logAge() {
  console.log(this.age);
}
Copier après la connexion

Cependant, la fonction globale créée sous la fonction globale ne peut en réalité être appelée que par l'instance créée par Person, qui est un peu mal nommée s'il y en a ; de nombreuses méthodes, vous devez définir une par une, manque d'encapsulation.

1.1.3. Mode prototype

Chaque fonction en JavaScript contient un pointeur vers l'attribut prototype (la plupart des navigateurs peuvent transmettre l'attribut interne __proto__ access), la propriété prototype est un objet qui contient des propriétés et des méthodes partagées par toutes les instances créées par un certain type de référence.

function Person() {}

Person.name = 'evansdiy';

Person.prototype.friends = ['ajiao','jianjian','pangzi'];

Person.prototype.logName = function() {
  console.log(this.name);
}

var person1 = new Person();

person1.logName();//'evansdiy'
Copier après la connexion

Le code ci-dessus fait les choses suivantes :

1. Définit une fonction constructeur Personne. La fonction Personne obtient automatiquement un attribut prototype, qui par défaut ne contient qu'un pointeur vers Personne. attribut constructeur ;

2. Ajoutez trois propriétés via Person.prototype, dont l'une est une méthode

3. Créez une instance de Person, puis appelez la méthode logName() ; exemple. !

Ce qui doit être noté ici, c'est le processus d'appel de la méthode logName() :

1. Recherchez la méthode logName() sur l'instance person1 et constatez qu'il n'existe pas de méthode de ce type, alors remontez au prototype de person1

2. Trouvez la méthode logame() sur le prototype de person1 Il existe cette méthode, donc l'appel de cette méthode est basé sur un tel processus de recherche. instance d'accéder au prototype en définissant la propriété du même nom dans le prototype sur l'instance. Il convient de noter que cela ne supprimera pas les attributs du même nom sur le prototype, mais. empêche uniquement l'accès à l'instance.

var person2 = new Person();

person2.name = 'laocai'; Si nous n'avons plus besoin des attributs sur l'instance, nous pouvons les supprimer via l'opérateur delete.

delete person2.name ; Utilisez une boucle for-in pour énumérer tous les attributs accessibles par l'instance (que l'attribut existe dans l'instance ou dans le prototype) :

for(i in person1) {
  console.log(i);
}
Copier après la connexion

En même temps, vous pouvez également utiliser la méthode hasOwnProperty() pour déterminer si une propriété existe sur l'instance ou dans le prototype. Ce n'est que lorsque la propriété existe dans l'instance qu'elle retournera true :

.

console.log(person1.hasOwnProperty('name'));//true!hasOwnProperty来自Object的原型,是javascript中唯一一个在处理属性时不查找原型链的方法。[via javascript秘密花园] 另外,也可以通过同时使用in操作符和hasOwnProperty()方法来判断某个属性存在于实例中还是存在于原型中:

console.log(('friends' in person1) && !person1.hasOwnProperty('friends'));先判断person1是否可以访问到friends属性,如果可以,再判断这个属性是否存在于实例当中(注意前面的!),如果不存在于实例中,就说明这个属性存在于原型中。 前面提到,原型也是对象,所以我们可以用对象字面量表示法书写原型,之前为原型添加代码的写法可以修改为:

Person.prototype = {

  name: 'evansdiy',
  friends: ['ajiao','jianjian','pangzi'],
  logName: function() {
    console.log(this.name);
  }

}
Copier après la connexion

由于对象字面量语法重写了整个prototype原型,原先创建构造函数时默认取得的constructor属性会指向Object构造函数:

//对象字面量重写原型之后
console.log(person1.constructor);//Object不过,instanceof操作符仍会返回希望的结果:

//对象字面量重写原型之后
console.log(person1 instanceof Person);//true当然,可以在原型中手动设置constructor的值来解决这个问题。

Person.prototype = {

  constructor: Person,
  ......

}
Copier après la connexion

如果在创建对象实例之后修改原型对象,那么对原型的修改会立即在所有对象实例中反映出来:

function Person() {};

var person1 = new Person();

Person.prototype.name = 'evansdiy';

console.log(person1.name);//'evansdiy'
Copier après la connexion

实例和原型之间的连接仅仅是一个指针,而不是一个原型的拷贝,在原型实际上是一次搜索过程,对原型对象的所做的任何修改都会在所有对象实例中反映出来,就算在创建实例之后修改原型,也是如此。 如果在创建对象实例之后重写原型对象,情况又会如何?

function Person() {};

var person1 = new Person1();//创建的实例引用的是最初的原型

//重写了原型
Person.prototype = {
  friends: ['ajiao','jianjian','pangzi']
}

var person2 = new Person();//这个实例引用新的原型

console.log(person2.friends);

console.log(person1.friends);
Copier après la connexion

以上代码在执行到最后一行时会出现未定义错误,如果我们用for-in循环枚举person1中的可访问属性时,会发现,里头空无一物,但是person2却可以访问到原型上的friends属性。 !重写原型切断了现有原型与之前创建的所有对象实例的联系,之前创建的对象实例的原型还在,只不过是旧的。

//创建person1时,原型对象还未被重写,因此,原型对象中的constructor还是默认的Person()
console.log(person1.constructor);//Person()

//但是person2的constructor指向Object()
console.log(person2.constructor);//Object()
Copier après la connexion

需要注意的是,原型模式忽略了为构造函数传递参数的过程,所有的实例都取得相同的属性值。同时,原型模式还存在着一个很大的问题,就是原型对象中的引用类型值会被所有实例共享,对引用类型值的修改,也会反映到所有对象实例当中。

function Person() {};

Person.prototype = {
  friends: ['ajiao','tiantian','pangzi']
}

var person1 = new Person();

var person2 = new Person();

person1.friends.push('laocai');

console.log(person2.friends);//['ajiao','tiantian','pangzi','laocai']
Copier après la connexion

修改person1的引用类型值friends,意味着person2中的friends也会发生变化,实际上,原型中保存的friends实际上只是一个指向堆中friends值的指针(这个指针的长度是固定的,保存在栈中),实例通过原型访问引用类型值时,也是按指针访问,而不是访问各自实例上的副本(这样的副本并不存在)。

1.1.4.结合构造函数和原型模式创建对象

结合构造函数和原型模式的优点,弥补各自的不足,利用构造函数传递初始化参数,在其中定义实例属性,利用原型定义公用方法和公共属性,该模式应用最为广泛。

function Person(name,age) {

  this.name = name;
  this.age = age;
  this.friends = ['ajiao','jianjian','pangzi'];

}

Person.prototype = {

  constructor: Person,
  logName: function() {
    console.log(this.name);
  }

}

var person1 = new Person('evansdiy','22');

var person2 = new Person('amy','21');

person1.logName();//'evansdiy'

person1.friends.push('haixao');

console.log(person2.friends.length);//3
Copier après la connexion

1.1.5.原型动态模式

原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。

function Person(name,age) {

  this.name = name;
  this.age = age;

  if(typeof this.logName != 'function') {
    Person.prototype.logName = function() {
      console.log(this.name);
    };
    Person.prototype.logAge = function() {
      console.log(this.age);
    };
  };

}

var person1 = new Person('evansdiy','22');//初次调用构造函数,此时修改了原型

var person2 = new Person('amy','21');//此时logName()方法已经存在,不会再修改原型
Copier après la connexion

需要注意的是,该模式不能使用对象字面量语法书写原型对象(这样会重写原型对象)。若重写原型,那么通过构造函数创建的第一实例可以访问的原型对象不会包含if语句中的原型对象属性。

function Person(name,age) {

  this.name = name;
  this.age = age;

  if(typeof this.logName != 'function') {
    Person.prototype = {
      logName: function() {
        console.log(this.name);
      },
      logAge: function() {
        console.log(this.Age);
      }
    }
  };

}

var person1 = new Person('evansdiy','22');

var person2 = new Person('amy','21');

person2.logName();//'amy'

person1.logName();//logName()方法不存在
Copier après la connexion

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

详细解读JavaScript设计模式开发中的桥接模式(高级篇)

详细解读在JavaScript中实现设计模式中的适配器模式的方法(图文教程)

设计模式中的facade外观模式在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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!