Encapsulation in JavaScript
Encapsulation simply means that the outside world can only access the common variables and functions of the object, hiding the details and data.
There are three ways to create objects in js, namely opening the door, using naming conventions to distinguish private variables, and closures to create real private variables.
1. Open door is the most basic method to realize objects. All methods and variables are common and can be accessed by the outside world.
var Book = function(name){ if(this.check(name)){ console.log("error"); throw new Error("name null"); } this.name = name; } Book.prototype = { check:function(name){ if(!name){ return true; } }, getName:function(){ return this.name; } } var book = new Book("哈哈"); //output:哈哈 哈哈 console.log(book.name,book.getName());
This example is a typical example of an open door, where the outside world can directly access the properties and methods of the object. You can notice that properties and variables are created with "this".
2. Use naming conventions to distinguish private variables. This method is an optimized version of the open-door method. It is just distinguished by "_" in front of private variables or methods. If a programmer intends to use the _getName() method to call the method , still cannot be prevented, it is not really hiding the variables.
3. Closure creates real private variables. This method takes advantage of the fact that only functions in js have scope and defines relevant variables in the scope of the constructor. These variables can be accessed by all functions in the scope of the definition domain.
var Book2 = function(name){ if(check(name)){ console.log("error"); throw new Error("name null"); } name = name; function check(name){ if(!name){ return true; } } this.getName = function(){ return name; } } Book2.prototype = { display:function(){ //无法直接访问name return "display:"+this.getName(); } } var book2 = new Book2("哈哈"); //output:undefined "哈哈" "display:哈哈" console.log(book2.name,book2.getName(),book2.display());
As you can see, in this example, accessing name directly will return undefined results. You can see the difference between this example and the open-door type. The variables in the open-door type are created using "this", while in this example var is used to create them. The same is true for the check function, so that the name and check functions can only be created in the constructor. It is accessed within the scope of the function and cannot be directly accessed by the outside world.
This method solves the problems of the first two methods, but it also has certain drawbacks. In the open-door object creation mode, all methods are created in the prototype object, so no matter how many object instances are generated, only one copy of these methods exists in the memory. With this method, each new object generated will be Create a new copy of private variables and methods, which consumes more memory.
Inheritance in JavaScript
Book base class:
var Book = function(name){ if(this.check(name)){ console.log("error"); throw new Error("name null"); } this.name = name; } Book.prototype = { check:function(name){ if(!name){ return true; } }, getName:function(){ return this.name; } }
Inherited method:
function extend(subClz,superClz){ var F = function(){} F.prototype = superClz.prototype; subClz.prototype = new F(); subClz.prototype.constructor = subClz; subClz.superClass = superClz.prototype; if(superClz.prototype.constructor == Object.prototype.constructor){ superClz.prototype.constructor = superClz; }
Using empty function F as a bridge can avoid the additional overhead of calling the parent class's constructor when directly instantiating the parent class. Moreover, when the parent class's constructor has parameters, you want to implement it directly through subClass.prototype = new superClass(); Calling the parent class constructor and inheritance through the prototype chain are not allowed.
subClz.superClass = superClz.prototype; if(superClz.prototype.constructor == Object.prototype.constructor){ superClz.prototype.constructor = superClz; }
Adding these three sentences can prevent the subclass from inheriting the parent class and writing Book.call(this, name); instead, simply write ArtBook.superClass.Constructor.call(this, name).
And when the subclass overrides the parent class method, it can call the parent class method:
ArtBook.prototype.getName = functiion(){ return ArtBook.superClass.getName.call(this) + "!!!"; }
ArtBook subclass:
var ArtBook = function(name,price){ ArtBook.superClass.Constructor.call(this,name); this.price = price; } extend(ArtBook,Book); ArtBook.prototype.getPrice = function(){ return this.price; } ArtBook.prototype.getName = function(){ return ArtBook.superClass.getName.call(this)+"!!!"; }