- JavaScript:Moving to ES2015
- Ved Antani Simon Timms Narayan Prusty
- 910字
- 2021-07-09 19:07:47
Build me a prototype
As previously mentioned, there was, until recently, no support for creating true classes in JavaScript. While ECMAScript-2015 brings some syntactic sugar to classes, the underlying object system is still as it has been in the past, so it remains instructive to see how we would have created objects without this sugar. Objects created using the structure in the previous section have a fairly major drawback: creating multiple objects is not only time consuming but also memory intensive. Each object is completely distinct from other objects created in the same fashion. This means that the memory used to hold the function definitions is not shared between all instances. What is even more fun is that you can redefine inpidual instances of a class without changing all of the instances. This is demonstrated in this code:
let Castle = function(name){ this.name = name; this.build = function() { console.log(this.name); }; } let instance1 = new Castle("Winterfell"); let instance2 = new Castle("Harrenhall"); instance1.build = function(){ console.log("Moat Cailin");} instance1.build(); //prints "Moat Cailin" instance2.build(); //prints "Harrenhall" to the console
Altering the functionality of a single instance or really of any already defined object in this fashion is known as monkey patching. There is some pision over whether or not this is a good practice. It can certainly be useful when dealing with library code but it adds great confusion. It is generally considered better practice to extend the existing class.
Without a proper class system JavaScript, of course, has no concept of inheritance. However, it does have a prototype. At the most basic level an object in JavaScript is an associative array of keys and values. Each property or function on an object is simply defined as part of this array. You can even see this in action by accessing members of an object using array syntax as is shown here:
let thing = { a: 7}; console.log(thing["a"]);
Tip
Accessing members of an object using array syntax can be a very handy way to avoid using the eval function. For instance, if I had the name of the function I wanted to call in a string called funcName
and I wanted to call it on an object, obj1
, then I could do so by doing obj1[funcName]()
instead of using a potentially dangerous call to eval. Eval allows for arbitrary code to be executed. Allowing this on a page means that an attacker may be able to enter malicious scripts on other people's browsers.
When an object is created, its definition is inherited from a prototype. Weirdly each prototype is also an object so even prototypes have prototypes. Well, except for the object which is the top-level prototype. The advantage to attaching functions to the prototype is that only a single copy of the function is created; saving on memory. There are some complexities to prototypes but you can certainly survive without knowing about them. To make use of a prototype you need to simply assign functions to it as is shown here:
let Castle = function(name){ this.name = name; } Castle.prototype.build = function(){ console.log(this.name);} let instance1 = new Castle("Winterfell"); instance1.build();
One thing to note is that only the functions are assigned to the prototype. Instance variables such as name
are still assigned to the instance. As these are unique to each instance there is no real impact on the memory usage.
In many ways a prototypical language is more powerful than a class-based inheritance model.
If you make a change to the prototype of an object at a later date then all the objects which share that prototype are updated with the new function. This removes some of the concerns expressed about monkey typing. An example of this behavior is shown here:
let Castle = function(name){ this.name = name; } Castle.prototype.build = function(){ console.log(this.name); } let instance1 = new Castle("Winterfell"); Castle.prototype.build = function(){ console.log(this.name.replace("Winterfell", "Moat Cailin")); } instance1.build();//prints "Moat Cailin" to the console
When building up objects you should be sure to take advantage of the prototype object whenever possible.
Now we know about prototypes there is an alternative approach to building objects in JavaScript and that is to use the Object.create
function. This is a new syntax introduced in ECMAScript 5. The syntax is as follows:
Object.create(prototype [, propertiesObject ] )
The create syntax will build a new object based on the given prototype. You can also pass in a propertiesObject
object that describes additional fields on the created object. These descriptors consist of a number of optional fields:
writable
: This dictates whether the field should be writableconfigurable
: This dictates whether the files should be removable from the object or support further configuration after creationenumerable
: This dictates whether the property can be listed during an enumeration of the object's propertiesvalue
: This dictates the default value of the field
It is also possible to assign a get
and set
functions within the descriptor that act as getters and setters for some other internal property.
Using object.create
for our castle we can build an instance using Object.create
like so:
let instance3 = Object.create(Castle.prototype, {name: { value: "Winterfell", writable: false}}); instance3.build(); instance3.name="Highgarden"; instance3.build();
You'll notice that we explicitly define the name
field. Object.create
bypasses the constructor so the initial assignment we described in the preceding code won't be called. You might also notice that writeable is set to false
. The result of this is that the reassignment of name
to Highgarden
has no effect. The output is as follows:
Winterfell Winterfell
- Extending Jenkins
- FuelPHP Application Development Blueprints
- 數據庫程序員面試筆試真題與解析
- 零基礎學Scratch少兒編程:小學課本中的Scratch創意編程
- JavaScript前端開發與實例教程(微課視頻版)
- Building Mobile Applications Using Kendo UI Mobile and ASP.NET Web API
- 精通Scrapy網絡爬蟲
- Nginx Essentials
- Java項目實戰精編
- Hands-On Automation Testing with Java for Beginners
- Django實戰:Python Web典型模塊與項目開發
- Web編程基礎:HTML5、CSS3、JavaScript(第2版)
- 嵌入式C編程實戰
- Extending Docker
- Jenkins 2.x實踐指南