Many of the JavaScript puzzles are caused by this. This is a confusing thing because his semantics are very different from the lexical scope rules of other variables. The object referenced by this is often completely unrelated to a function's lexical scope. So we often see this little trick:
function blah ({var that = this; somethingthatrebindsthings ( ({ That. Whatever}) ;"
If you have ever done some JavaScript development, then you must understand the pain. Imagine how good it would be if we didn't need this. Is that possible? It sounds like an unlikely look! Let's see if we can reach that goal now.
Why do you want to use this?
Our motivation to use this is often related to the most useful abstraction in an object-oriented programming paradigm: State and behavior complement each other. This is especially true when objects have many properties and methods. You might think that if we don't use this, we might lose this powerful abstraction. If you do not use this, how do these objects refer to its methods and properties? Perhaps you have guessed the answer: closures.
If you think about it, closures are another way to make states and objects mutually reinforcing. Let's now replace the traditional code containing this with some code that contains closures. Let's implement a car type using native javascript:
functionCar(numberofdoors){This. numberofdoors= Numberofdoors; This. numberofwheels=4; This. Describe=function(){Return"I have"+ This. numberofwheels+"Wheels and"+ This.numberofdoors + "doors." }}var sportscar Span class= "token operator" >= new car (2. Log (Sportscar. Describe
If we use closures, we can use the following code to achieve the same purpose:
functionCreatecar(numberofdoors){var numberofwheels=4;functionDescribe(){Return"I have"+ Numberofwheels+"Wheels and"+ numberofdoors+"Doors." return {describe< Span class= "token punctuation" >: Describe };}var SUV = createcar4 ;console.< Span class= "token function" >log (Suv.describe
In the above code, we have achieved our purpose through a constructor function called Createcar. This constructor function defines all the states and methods of the car type, and returns an object that exposes only a common behavior. Everything defined in this constructor function cannot be accessed externally, but because of closures, everything defined in the constructor function can be accessed from one another. Each call to the constructor function creates a new closure that creates a new small package that contains the state and behavior.
Inherited
What happened in the inheritance? In general, prototype inheritance implies the use of this. But we don't want to use this now, so let's use another way to implement inheritance:
functionCreateminivan(Capacity){var car=Createcar(4); Car. capacity=function(){Return"I have a box for"+ Capacity+"Passengers.";};return car;}var minivan=createminivan (7;console.log (Minivan.describe;console.< Span class= "token function" >log (Minivan.capacity ("
In the example above, I created a new minivan type, which inherits all the common methods from the car type and adds the capacity method. This is similar to the concept of mixed classes used in other languages such as Clos and Ruby. One potential disadvantage of this approach is that it does not allow subclasses or superclass to access the underlying state and behavior-in other words, we do not see the concept of "protection" in this way.
Polymerization
Here we use aggregations to add a new behavior to a type:
functionCreateodometer(){var mileage=0;functionIncrement(Numberofmiles){Mileage+= Numberofmiles;}functionReport(){return mileage;}Return{Increment: Increment, report: report}}functionCreatecarwithodometer(numberofdoors){var odometer=Createodometer();var car=Createcar(numberofdoors); Car. Drive=function(Numberofmiles){Odometer.Increment(Numberofmiles Car.mileage = span class= "token keyword" >function ({return "car has driven" + odometer. Report (+ "Miles" return car;
In the Createcarwithodometer constructor function, we create a odometer and then use the function of the odometer to implement some additional methods. Next, we create a basic car instance and mix the new behavior into this instance. The last we get is a new type, which uses the odometer feature to extend the car type. The above code does not use the prototype inheritance at all, or this.
Is it really useful?
This approach is useful for several reasons:
- First, it allows us to avoid the chaotic situations that we encounter when we use this.
- It is a good way to aggregate our types and a temporary type within the constructor function. It allows us to use the useful parts of multiple inheritance, but also to remove dependencies related to it.
- Finally, the biggest benefit is that we can provide a well-controlled API for each type, and all nonpublic functionality is safely hidden inside the closure of the constructor function. This is very helpful in maintaining a huge code base.
This article is translated from JavaScript without the This, the original address http://programming.oreilly.com/2014/03/javascript-without-the-this.html
No JavaScript with this