JavaScript est un puissant langage de programmation orienté objet. Cependant, contrairement aux langages de programmation traditionnels, il utilise un modèle POO basé sur un prototype, ce qui rend sa syntaxe incompréhensible pour la plupart. développeurs. De plus, JavaScript traite également les fonctions comme des objets principaux, ce qui peut créer une plus grande confusion pour les développeurs qui ne sont pas familiers avec le langage. C'est pourquoi nous avons décidé de le présenter comme une brève introduction, et il peut également être utilisé comme référence pour la programmation orientée objet en JavaScript.
Ce document ne donne pas un aperçu des règles de la programmation orientée objet, mais donne un aperçu de leurs interfaces.
Avec l'émergence de plus en plus de bibliothèques, de frameworks et de dépendances Web tiers, les espaces de noms sont impératifs dans le développement de JavaScript. Nous devons essayer d'éviter les conflits entre les objets d'espace de noms globaux et. variables.
Malheureusement, JavaScript ne prend pas en charge la compilation des espaces de noms, mais nous pouvons utiliser des objets pour obtenir le même résultat. En JavaScript, nous avons de nombreux modèles pour implémenter des interfaces d'espaces de noms, mais nous couvrons les espaces de noms imbriqués, qui sont le modèle le plus couramment utilisé dans ce domaine.
Le modèle d'espace de noms imbriqué utilise des littéraux d'objet pour regrouper des fonctionnalités avec un nom spécifique pour une application spécifique.
Nous créons dans un premier temps un objet global et l'attribuons à une variable appelée MyApp.
// global namespace var MyApp = MyApp || {};
La syntaxe ci-dessus vérifiera si MyApp a été défini. S'il est déjà défini, nous nous l'attribuons simplement, mais nous créons à la place un conteneur vide pour contenir nos fonctions et variables.
Nous pouvons également utiliser la même technique pour créer des sous-espaces de noms. Par exemple :
// sub namespaces MyApp.users = MyApp.user || {};
Une fois que nous démarrons notre conteneur, nous pouvons définir nos fonctions et variables à l'intérieur (du conteneur) et les appeler dans l'espace de noms global sans risquer de conflits avec les définitions existantes.
// declarations MyApp.users = { existingUsers: '', // variable in namespace renderUsersHTML: function() { // function in namespace // render html list of users } }; // syntax for using functions within our namespace from the global scope MyApp.users.renderUsersHTML();
Un aperçu interne des modèles de dénomination en JavaScript a été présenté par Addy Osmani de Goggle dans l'article Modèles d'espacement de noms JavaScript essentiels. Si vous souhaitez explorer différents modes, ce serait un excellent point de départ.
Si vous avez déjà écrit du code JavaScript, vous avez déjà utilisé des objets. JavaScript a trois types d'objets :
Les objets natifs font partie de la spécification du langage et sont disponibles quel que soit l'environnement d'exécution dans lequel ils sont exécutés. Les objets natifs incluent : Array, Date, Math, parseInt, etc. Pour en savoir plus sur tous les objets natifs, consultez Référence des objets intégrés JavaScript
var cars = Array(); // Array is a native object
Contrairement aux objets natifs, les objets hôtes sont créés par l'environnement dans lequel le code JavaScript s'exécute. Différents environnements créent différents objets hôtes. Ces objets hôtes nous permettent d'interagir avec eux dans la plupart des cas. Si nous écrivons du code qui s'exécute sur un navigateur (qui est l'un des environnements en cours d'exécution), il y aura des objets hôtes tels que la fenêtre, le document, l'emplacement et l'historique.
document.body.innerHTML = 'Hello World!'; // document is a host object // the document object will not be available in a // stand-alone environments such as Node.js
L'objet utilisateur (ou objet implanté) est un objet défini dans notre code et créé lors de l'exécution. Il existe deux manières de créer vos propres objets en JavaScript, détaillées ci-dessous.
Dans la démonstration précédente de création d'un espace de noms, nous sommes déjà entrés en contact avec des littéraux d'objet. Clarifions maintenant la définition d'un littéral d'objet : un littéral d'objet est une liste de paires nom-valeur séparées par des virgules et entourées d'une paire d'accolades. Les littéraux d'objet peuvent avoir des variables (propriétés) et des fonctions (méthodes). Comme d’autres objets en JavaScript, il peut également être utilisé comme paramètre ou valeur de retour d’une fonction.
Définissez maintenant un littéral d'objet et affectez-le à une variable :
// declaring an object literal var dog = { // object literal definition comes here... };
Ajoutez des propriétés et des méthodes à ce littéral d'objet, puis accédez-y dans la portée globale :
// declaring an object literal var dog = { breed: 'Bulldog', // object literal property bark: function() { // object literal method console.log("Woof!"); }, }; // using the object console.log( dog.breed ); // output Bulldog dog.bark(); // output Woof!
Cela ressemble beaucoup à l'espace de noms précédent, mais ce n'est pas une coïncidence. L'utilisation la plus courante des objets littéraux consiste à encapsuler le code dans un package encapsulé pour éviter les conflits avec des variables ou des objets dans la portée globale. Il est également souvent utilisé pour transmettre des paramètres de configuration à des plugins ou à des objets pour des raisons similaires.
Si vous connaissez les Design Patterns, les littéraux d'objet sont dans une certaine mesure des singletons, c'est-à-dire un modèle avec une seule instance. Les littéraux d'objet n'ont pas par nature la capacité d'instancier et d'hériter. Ensuite, nous devons découvrir une autre façon de créer des objets personnalisés en JavaScript.
La fonction est un citoyen de première classe de JavaScript, ce qui signifie que toutes les fonctions d'opération prises en charge par d'autres entités sont prises en charge. Dans le monde de JavaScript, les fonctions peuvent être construites dynamiquement au moment de l'exécution, peuvent être utilisées comme paramètres, peuvent être utilisées comme valeurs de retour d'autres fonctions et peuvent également être affectées à des variables. De plus, les fonctions peuvent également avoir leurs propres propriétés et méthodes. La nature des fonctions en JavaScript en fait quelque chose qui peut être instancié et hérité.
Voyons comment utiliser le constructeur pour créer un objet personnalisé :
// creating a function function Person( name, email ) { // declaring properties and methods using the (this) keyword this.name = name; this.email = email; this.sayHey = function() { console.log( "Hey, I’m " + this.name ); }; } // instantiating an object using the (new) keyword var steve = new Person( "Steve", "steve@hotmail.com" ); // accessing methods and properties steve.sayHey();
创建构造函数类似于创建普通函数,只有一点例外:用 this 关键字定义自发性和方法。一旦函数被创建,就可以用 new 关键字来生成实例并赋予变量。每次使用 new 关键字,this 都指向一个新的实例。
构建函数实例化和传统面向对象编程语言中的通过类实例化并非完全不同,但是,这里存在一个可能不易被察觉的问题。
当使用 new 关键字创建新对象的时候,函数块会被反复执行,这使得每次运行都会产生新的匿名函数来定义方法。这就像创建新的对象一样,会导致程序消耗更多内存。这个问题在现代浏览器上运行的程序中并不显眼。但随着应用规则地扩大,在旧一点的浏览器、计算机或者低电耗设备中就会出现性能问题。不过不用担心,有更好的办法将方法附加给构造函数(是不会污染全局环境的哦)。
前面介绍中提到 JavaScript 是一种基于原型的编程语言。在 JavaScript 中,可以把原型当作对象模板一样来使用。原型能避免在实例化对象时创建多余的匿名函数和变量。
在 JavaScript 中,prototype 是一个非常特别的属性,可以让我们为对象添加新的属性和方法。现在用原型重写上面的示例看看:
// creating a function function Person( name, email ) { // declaring properties and methods using the (this) keyword this.name = name; this.email = email; } // assign a new method to the object’s prototype Person.prototype.sayHey = function() { console.log( "Hey, I’m " + this.name ); } // instantiating a new object using the constructor function var steve = new Person( "Steve", "steve@hotmail.com" ); // accessing methods and properties steve.sayHey();
这个示例中,不再为每个 Person 实例定义 sayHey 方法,而是通过原型模板在各实例中共享这个方法。
通过原型链,原型可以用来实例继承。JavaScript 的每一个对象都有原型,而原型是另外一个对象,也有它自己的原型,周而复始…直到某个原型对象的原型是 null——原型链到此为止。
在访问一个方法或属性的时候,JavaScript 首先检查它们是否在对象中定义,如果不,则检查是否定义在原型中。如果在原型中也没找到,则会延着原型链一直找下去,直到找到,或者到达原型链的终端。
现在来看看代码是怎么实现的。可以从上一个示例中的 Person 对象开始,另外再创建一个叫 Employee 的对象。
// Our person object function Person( name, email ) { this.name = name; this.email = email; } Person.prototype.sayHey = function() { console.log( "Hey, I’m " + this.name ); } // A new employee object function Employee( jobTitle ) { this.jobTitle = jobTitle; }
现在 Employee 只有一个属性。不过既然员工也属于人,我们希望它能从 Person 继承其它属性。要达到这个目的,我们可以在 Employee 对象中调用 Person 的构造函数,并配置原型链。
// Our person object function Person( name, email ) { this.name = name; this.email = email; } Person.prototype.sayHey = function() { console.log( "Hey, I’m " + this.name ); } // A new employee object function Employee( name, email, jobTitle ) { // The call function is calling the Constructor of Person // and decorates Employee with the same properties Person.call( this, name, email ); this.jobTitle = jobTitle; } // To set up the prototype chain, we create a new object using // the Person prototype and assign it to the Employee prototype Employee.prototype = Object.create( Person.prototype ); // Now we can access Person properties and methods through the // Employee object var matthew = new Employee( "Matthew", "matthew@hotmail.com", "Developer" ); matthew.sayHey();
要适应原型继承还需要一些时间,但是这一个必须熟悉的重要概念。虽然原型继承模型常常被认为是 JavaScript 的弱点,但实际上它比传统模型更强大。比如说,在掌握了原型模型之后创建传统模型简直就太容易了。
ECMAScript 6 引入了一组新的关键字用于实现 类。虽然新的设计看起来与传统基于类的开发语言非常接近,但它们并不相同。JavaScript 仍然基于原型。
以上就是JavaScript 中的面向对象编程的详细介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!