There are many ways to create objects in JavaScript, so the way to create objects is very flexible. So, which way is the most appropriate way to create objects? Construction pattern, prototype pattern or object literal pattern?
But what exactly are these modes?
Before we start explaining, let us clearly introduce the basic knowledge about javascript.
Is it possible to implement object-oriented programming in javascript?
The answer is possible, javascript can create objects! Such objects can contain data and methods that can manipulate the data, and can even contain other objects. It has no classes but has constructors; it has no class inheritance mechanism, but inheritance can be achieved through prototypes.
Now it seems that we have understood the necessary components to create objects and implement object-based programming in javascript.
We all know that javascript has private variables. A variable defined through the "var" keyword can only be accessed within the function body and cannot be accessed outside the function. So, what happens if we don’t define a variable by using the “var” keyword? We won't delve into this issue now, it may be accessed through "this", I will talk about this issue in detail at another time.
Now back to the previous question. Which method is the most appropriate way to create objects?
Let’s use what we already know and try it out by creating a Person object.
var Person = {
firstName : 'John' ,
lastName : 'Cody',
fullName : '',
message : '',
createFullName : function () {
fullName = this.firstName ' ' this. lastName;
},
changeMessage : function (msg) {
this.message = msg;
},
getMessage : function () {
this .createFullName();
return this.message ' ' fullName;
}
}
Person.firstName = 'Eli';
Person.lastName = 'Flowers'
Person.changeMessage('welcome');
var message = Person.getMessage(); // welcome Eli Flowers
alert(message);
This is the original intention mode of the object ( literal pattern). This is very close to how we usually create objects. If you don't need to care about private/wrapped members, and you know no instance of this object will be created. Then this method will suit you very well. Public members can do everything private members can do, right? However, this is not a class, but an object, which cannot be instantiated and cannot be inherited.
Let’s try something else:
var Person = {
firstName : 'John',
lastName : 'Cody',
fullName : '',
message : '',
createFullName : function ( ) {
fullName = this.firstName ' ' this.lastName;
},
changeMessage : function (msg) {
this.message = msg;
},
getMessage : function () {
this.createFullName();
return this.message ' ' fullName;
}
}
Person.firstName = 'Eli ';
Person.lastName = 'Flowers'
Person.changeMessage('welcome');
var message = Person.getMessage(); // welcome Eli Flowers
alert(message);
This is an example of a construction pattern (Constructor Pattern). So, is this a class or an object? Probably both. We can use it as a Person object when making a request. After all, it is just a function. However, it is possible to create new instances using the "new" keyword.
When using this method, we need to always remember the following points: 1. Whenever this function is called, it has a special variable is called "this" and is available globally. The global scope depends on the scope of the function itself.
2. Whenever an instance of this function is created through the "new" keyword, the "this" variable points to the function itself, and this "new" operation will affect the execution of the code in the function body. This is also the construction pattern.
3. Any variables attached to the "this" variable will become public properties and any variables defined through the "var" keyword will be private properties.
4. A function attached to "this" is called a privileged function. It can access all private variables and functions and variables attached to "this".
5. Private functions can access other private variables and private functions.
6. Private functions cannot directly access variables and functions attached to "this". We can do this by creating a private variable "_that" and assigning it the value "this".
7. Any private variables and functions are available to other private functions and other functions attached to "this". This is entirely possible within the scope of JavaScript.
8. A variable: not through the "var" keyword, nor attached to the "this" variable to obtain global scope. For example, for the scope of a custom function. Once again, you need to understand scope and clustering.
This has achieved most of what we want, but sometimes the two entry variables "this" and "that" can easily cause confusion to people. Especially for those who have always insisted on pure private ownership, it is easier to be confused.
Let’s try it with a little modification.
var Person = function () {
//private
var firstName = 'John';
var lastName = 'Cody';
var fullName = '';
var message = '';
var createFullName = function () {
fullName = firstName ' ' lastName;
}
//public setters
var setMessage = function (msg) {
message = msg;
}
var setFirstName = function (fName) {
firstName = fName;
}
var setLastName = function (lName) {
lastName = lName;
}
var getMessage = function () {
createFullName();
return message ' ' fullName;
}
//functions exposed public
return {
setFirstName: setFirstName,
setLastName: setLastName,
setMessage: setMessage,
getMessage: getMessage
};
};
var person1 = new Person();
person1.setFirstName('Eli');
person1.setLastName('Flowers');
person1.setMessage('welcome');
var message = person1 .getMessage(); // welcome Eli Flowers
alert(message);
This is a Revealing Pattern. Many thanks to Christian Heilmann. The way to use this pattern is to use the request's "getters" and "setters" as properties. Many of us have found this figure from traditional Java programming and it is obvious that implementing it is not complicated. This is also a situation similar to when a class inherits from an interface.
Most aspects of this model are implemented well, with only one very minor problem. Every time an instance of a class is created. The newly created object gets a copy of its variables and functions. Now, there is no problem in copying variables. We hope that the data of each object belongs to the object itself. So, what about the member functions? They just manipulate data. So, why do you need to copy them?
This is the advantage of Prototype. In all instances, everything is created as a prototype and can be shared with each other. All we need to do is create public functions based on the prototype.
var Person = function () {
//private
var welcomeMessage = 'welcome';
var fullName = '';
var firstName = '';
var lastName = "";
var createFullName = function () {
Person.prototype.setFirstName('asdsad');
fullName = firstName ' ' lastName;
};
//constructor
var Person = function () { }; //will be created evrytime
//public
Person.prototype = {
getFullName: function () {
createFullName();
return welcomeMessage ' ' fullName;
},
setFirstName: function (fName) {
firstName = fName;
},
setLastName: function (lName) {
lastName = lName;
},
ChangeMessage: function (mesg) {
welcomeMessage = mesg;
}
}
return new Person(); // Person; //new Person();
};
var person1 = new Person();
person1.setFirstName ('Eli');
person1.setLastName('Flowers');
person1.ChangeMessage('welcome');
var message = person1.getFullName(); // welcome asdsad Flowers
alert(message);
原型模式存在的一个问题是它不能访问私有变量及私有函数,正因为这个问题,我们才会介绍闭包以及始终组织好创建类中存在的代码以使得它在全局范围内不会变得很混乱。所有都是属于 Person 类的作用范围内。
另外一个问题是每一次实例被创建时,全部的代码都被执行一遍,包括原型的绑定。对于我们中的一部分人来说,这仅仅只是一个效率问题。处理好这个问题的一种方式是仅仅在期望共有函数不可用的情况下绑定这个原型。
这样将会使得绑定原型操作只会在第一个实例被创建时执行,并且在那之后所有其他的实例都将只会进行检查操作。不幸的是,这样还是不能解决我们在上面例子中提到的问题,因为我们只有重新再来一次创建的函数用于生成一个闭包来达到这个类的效果。这样的话,至少我们减少了一部分内存的使用。
等等,还有另外一个问题是私有函数不能直接访问原型函数。
为什么你们一定得需要私有函数和私有变量呢?我知道你一定是想实现类的封装性,想确保类中的属性或者内部的数据不会被突然地修改了或者被内部的其他程序所修改,或者任何其他的操作……
你应该记住你是不能将 javascript 代码编译成二进制的,对于这种情况,你在一定程度上很恼火吧,这样代码始终都是可用的。所以,如果任何人想搅乱代码的话,不管你真正实现私有或者没有实现私有,不管你将代码给团队中的其他成员或者卖出去,他们都可以搅乱代码。实现私有化可能有那么一点点帮助吧。
另一个其他编程者使用的技术是使用约定命名,使用下划线 “_”给所有你想设成私有任何的东西加上前缀以规定它成为私有。
(function () {
var Person = function () {
this._fullName = '';
this.welcomeMessage = '';
this.firstName = '';
this.lastName = "";
_that = this;
this._createFullName = function () {
this.ChangeMessage('Namaste');
this._fullName = this.firstName ' ' this.lastName;
};
}
//Shared Functions for Code optimization
Person.prototype = {
constructor: Person,
getFullName: function () {
this._createFullName();
return this.welcomeMessage ' ' this._fullName;
},
ChangeMessage: function (mesg) {
this.welcomeMessage = mesg;
}
}
this.Person = Person;
})();
var person1 = new Person();
person1.firstName = 'Eli';
person1.lastName = 'Flowers';
person1.ChangeMessage('Welcome');
var message = person1.getFullName(); // Namaste Eli Flowers
alert(message);
I’m not saying you shouldn’t think about “private” or anything like that. You are the designer of the code, so you will know how to manage it and know what works best. Depending on your needs, you can use any one design pattern or a combination of multiple design patterns together.
No matter which design pattern you decide to adopt, always remember to do as little as possible, do not implement closures in the global scope, minimize memory leaks, optimize the code, and organize the code well. So, try to learn as much as possible about scopes, closures, and the behavior of “this”.
Finally, happy programming!
Post-translation impressions I often use javascript, and my impression of it is that it can be used directly by copying it. I recently used extjs, and its class framework is very easy to use. From this article, we can also understand the various ways to implement classes in JavaScript, and at the end of the article, we discuss the implementation of private members in classes.