OOPinJavascript
I've written a few articles on getting started with Vue, so today I'll write something else to relax and talk briefly about the face object in javascript.
In object-oriented languages, there is the concept of class, of course, es6 in the beginning of javascript also has the concept of class, here to es5 as the basis for the beginning of the explanation, after all, even if the current writing of es6 code, generally or through babel and other transcoders to translate to es5 to perform.
While there is no concept of a class in js, we can create objects, and there are two general ways to create objects (in this case, custom objects).
1. Use the constructor
function Person(){ } var p=new Person();
2. Use of literal quantities
var p={ // Various attributes }
Here is a focus on the constructor approach to object creation; take the above code as an example, function Person () {}, what is the difference between this and a normal function? In fact, apart from the naming convention (initial capitalization is recommended) there is no difference in the declarations, the main difference is in the way the call is made, the constructor call uses the new operator and the call to the constructor using the new operator goes through four main steps.
1). create a new object.
2), pointing this to the new object.
(3), add properties to the object
4), return the new object
A little simple modification to our code above.
function Person(){ this.name= "zhangsan"; this.age=10; }; var p=new Person(); console.log(p.name,p.age) ;//'zhangsan 10'
Compare this to the process of calling the constructor using the new operator above, and it's easy to understand the output.
As I said earlier, the constructor is exactly the same as a normal function call, so does that mean you can make a normal call to the constructor? Of course, our example can be modified again to.
function Person(){ this.name= "zhangsan"; this.age=10; }; //var p=Person(); Person(); console.log(window.name,window.age) ;//'zhangsan 10'
Not using the new operator call, will not go through the above four steps of implicit processing, so this time there will be no new object creation and this pointing to the change, then this at this time points to the global object, in the browser that is window object, so you can use window.name to access, get the correct output.
The three main features of OOP: encapsulation, inheritance, and polymorphism; this is only about how to do inheritance in javascript (es5 only).
Inheritance is just a means of code reuse, so how do you implement inheritance in js?
Prototype-based inheritance
First of all, functions are also objects, because all functions are instances of Function objects, function function name, this way of defining a function is just a shortcut, theoretically equivalent to var function name = new Function(p1,body), from this point on the function name is actually a pointer to the function, but the difference is that creating a function by new Function will be interpreted twice by the js interpreter, once when it is declared and a second time when the body part is parsed.
Second, any function that is created has a prototype object such as :
Declare a Person function, then we can use Person.prototype to print its prototype object, you can see that its prototype object is an Object type, which includes a property (not counting __proto__, this term internal variable, is a pointer from the instance to the prototype) constructor, pointing to the function Person; in addition the prototype object itself is an instance of another object (which is an instance of the Object function, = new Object ()), any instance of an object, contains an internal variable __proto__(chrome browser) (except for objects created by Object.create(null)), pointing to the prototype of the type that created the object instance, here __prop__ points to Object.prototype. and you can see several methods (toString, valueOf, etc.) contained on Object.prototype.
As stated above, any instance of an object contains an internal variable that points to its constructor prototype, so we create an instance of Person.
You can see that it is the same, so we can summarize the relationship between constructors, instances, and constructor prototypes as follows.
It's hard to draw, but I think it should get across what I'm trying to say too, huh?
In summary, the prototype of the constructor is an object, which by default is an instance of the Object object; as the access, the lookup rule is as follows: first look up the instance property of the current object, and return if found, otherwise, look up the property of the same name on the prototype object pointed by __proto__, and return if found, otherwise continue with the property of the same name on the object pointed by __proto__ of the prototype object, until the __proto__ of the Object instance, that is, Object.prototype, and the above link constructed by __proto__ is called the prototype chain.
Please see the following code.
function Person(){ this.name="zhangsan"; this.myFriends=["zhangsan","lisi"] } Person.prototype.getName=function(){ return this.name; } function Student(){ } Student.prototype=new Person(); var s1=new Student(); var s2=new Student(); s1.myFriends.push("wangwu"); console.log(s1.myFriends);?? console.log(s2.myFriends);??
The code above I implemented a simple inheritance based on the prototype pattern, So what is the output from above? Tests can be performed, The output was found to be all["zhangsna","lisi","wangwu"]; Why this result, It is not difficult to analyze, We provideStudent The prototype of the constructor redesignates the new object, Then at this point the object(Person an actual example) Then it becomesStudent Prototype object of the constructor, then its instance property becomesStudent Prototype properties of constructor, So we're going throughStudent Instances access their prototypes in Reference type attributes The above output occurs when sharing is generated in the
This output structure does not match our expectation, how to deal with this problem, according to our lookup rules, we will not look up the prototype object if we find the corresponding property on this object, based on this, we just need to override the object on the prototype, and the easiest way is to borrow the constructor, modify our code as follows.
function Person(){ this.name="zhangsan"; this.myFriends=["zhangsan","lisi"] } Person.prototype.getName=function(){ return this.name; } function Student(){ Person.call(this);//key call, note that this is a normal call, not a constructor call, this call, by calling changes this to point to an instance of Student } Student.prototype=new Person(); var s1=new Student(); var s2=new Student(); s1.myFriends.push("wangwu"); console.log(s1.myFriends); console.log(s2.myFriends);
Use one normal method call, pass this, and then dynamically create the name and myFriends properties on this so that the instance doesn't look up the properties on the prototype when outputting, solving the problem of output not matching expectations.
But what else is wrong with the above code when analyzed carefully?
1), Student.prototype.constructor points to Person
2), the Person method is called twice, once as a constructor call and once as a normal call
3), the borrowed constructor approach, is to create new instance properties to override the prototype properties, which creates additional properties.
Modifying our code again to handle the above.
function inherit(child,parent){ function F(){} F.prototype=parent.prototype;//as long as the content on the prototype, not the instance, so as to avoid the properties on the instance and inherit only the properties (methods) on the prototype F.prototype.constructor=child;// Here is forcing the constructor property to point to the child type child.prototype=F.prototype; } function Person(){ this.name="zhangsan"; this.myFriends=["zhangsan","lisi"] } Person.prototype.getName=function(){ return this.name; } function Student(){ Person.call(this);//key call, note that this is a normal call, not a constructor call, this call, by calling changes this to point to an instance of Student } //Student.prototype=new Person(); inherit(Student,Person) var s1=new Student(); var s2=new Student(); s1.myFriends.push("wangwu"); console.log(s1.myFriends); console.log(s2.myFriends);
Of course the above code is still a bit imperfect, first of all Student.prototype.constructor, should be unenumerable, we are here is but can. There are still many details that may not be fully considered, and the details are recommended to nibble on the bible, "javascript Advanced Programming", so much for this one.