Http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/ 001434499763408e24c210985d34edcabbca944b4239e20000 creating objects with object-oriented programming
JavaScript sets a prototype for each object that is created, pointing to its prototype object.
When we obj.xxx
access the properties of an object, the JavaScript engine looks for the property on the current object, and if it is not found, it is found on its prototype object, and if it is not found, it is traced back to the Object.prototype
object, and finally, if it is not found, it can only be returned undefined
.
For example, create an Array
object:
var arr = [1, 2, 3]; // its prototype chain is: NULL
Array.prototype
Defines, and so on, indexOf()
shift()
so you can Array
call these methods directly on all objects.
The function is also an object, and its prototype chain is:
Null
Because Function.prototype
apply()
such methods are defined, all functions can invoke apply()
methods.
It is easy to think that if the prototype chain is long, then accessing an object's properties will become slower because it takes more time to find it, so be careful not to make the prototype chain too long.
constructor function
In addition to { ... }
creating an object directly, JavaScript can also create objects using a constructor method. The use of it is to define a constructor first:
function Student (name) { this. Name = name; This function () { alert (this. Name + '! ') ); }}
Like a normal function, but in JavaScript, you can new
call this function with a keyword and return an object:
var New Student (' Xiao Ming'// ' Xiao Ming '// Hello, Xiaoming!
Note that if you do not write new
, this is a normal function that returns undefined
. However, if new
it is written, it becomes a constructor that binds to the this
newly created object and returns it by default this
, that is, it does not need to be written at the last point return this;
.
The newly created xiaoming
prototype chain is:
Null
In other words, xiaoming
the prototype points to Student
the prototype of the function. If you create again, xiaohong
the xiaojun
prototypes of these objects xiaoming
are the same:
xiaoming Xiaohong-→student.prototype----> object.prototype---->nullXiaojun
new Student()
the created object also obtains a property from the prototype constructor
, which points to the function Student
itself:
// true // true // true instanceof // true
Using a graph to show that these messy relationships are:
The red Arrow is the prototype chain. Notice that the Student.prototype
object that is pointing to is the xiaoming
xiaohong
prototype object, and the prototype object itself has a property constructor
that points to the Student
function itself.
In addition, the function Student
has exactly prototype
a xiaoming
prototype object pointing to the property, xiaohong
but xiaoming
xiaohong
these objects may not have prototype
this property, but can be __proto__
viewed in this non-standard usage.
Now we think that xiaoming
xiaohong
these objects are "inherited" from Student
.
However, there is a small problem, pay attention to observation:
// ' Xiao Ming ' // ' Little Red ' // Function:Student.hello () // Function:Student.hello () // false
xiaoming
It's right to be xiaohong
different from each name
other, otherwise we can't tell who is who.
xiaoming
and xiaohong
each hello
is a function, but they are two different functions, although the function name and code are the same!
If we new Student()
create a lot of objects, the functions of these objects hello
actually only need to share the same function, which can save a lot of memory.
To let the created object share a hello
function, according to the object's property lookup principle, we just hello
move the function to the xiaoming
xiaohong
Common prototype of these objects, that is Student.prototype
:
Modify the code as follows:
function Student (name) { this.name =function () { alert (this . Name + '! ' );};
It's new
so easy to create a prototype-based JavaScript Object!
Forget to write new what to do
What if a function is defined as the constructor used to create the object, but when the call forgets to write new
?
In strict mode, this.name = name
will be error, because the this
binding is undefined
, in the non-strict mode, this.name = name
no error, because the this
binding is window
, then inadvertently created a global variable name
, and return undefined
, this result is worse.
So, call the constructor and never forget to write new
. In order to distinguish between ordinary functions and constructors, by convention, the initial letter of the constructor should be capitalized, and the first letter of the ordinary function should be lowercase, so that some grammar checking tools such as JSLint will be able to help you detect the missing write new
.
Finally, we can also write a createStudent()
function that encapsulates all the operations internally new
. A common programming pattern is like this:
function Student (props) { this . Name = Props.name | | ' Anonymous '; // this . Grade = Props.grade | | 1; // }student.prototype.hello = function Span style= "color: #000000;" () {alert ( ' Hello, ' + function Createstudent (props) { return new Student (Props | |
This createStudent()
function has several great advantages: one is not required new
to call, the other is very flexible parameters, can not pass, can also be transmitted:
var xiaoming = createstudent ({name: ' xiaoming '// 1
If you create an object that has many properties, we only need to pass some of the required properties, and the rest of the properties can be used as default values. Since the parameter is an object, we do not need to memorize the order of the parameters. If you happen JSON
to get an object from it, you can create it directly xiaoming
.
Prototype inheritance
In traditional class-based languages such as Java and C + +, the essence of inheritance is to extend an existing class and generate new subclass.
Because such languages strictly differentiate between classes and instances, inheritance is actually an extension of the type. However, because of the prototype inheritance of JavaScript, we cannot extend a class directly because there is no such type as class.
But there are some ways. Let's review the Student
constructors first:
function Student (props) { this. Name = Props.name | | ' Unnamed 'function () { alert (this. Name + '! ') );}
and Student
the prototype chain:
Now, based on the Student
extension PrimaryStudent
, we can first define PrimaryStudent
:
function primarystudent (props) { // Call Student constructor, bind this variable: student.call (This , props); this. Grade = Props.grade | | 1;}
However, the constructor that was called Student
does not equal inheritance Student
, and the prototype of the PrimaryStudent
created object is:
New NULL
We must find a way to modify the prototype chain to:
New NULL
In this way, the prototype chain is right, and the inheritance relationship is right. The new creation-based PrimaryStudent
object can invoke not only the PrimaryStudent.prototype
defined method, but also Student.prototype
the defined method.
If you want to do this in the simplest and most brutal way:
Primarystudent.prototype = Student.prototype;
It's not going to work! If so, PrimaryStudent
and Student
share a prototype object, what do you define PrimaryStudent
?
We must use an intermediate object to achieve the correct prototype chain, the prototype of this intermediate object to point to Student.prototype
. To achieve this, refer to the Code of the Master (that is, the Douglas that invented JSON), which can be implemented with an empty function F
:
//Primarystudent Constructor:functionprimarystudent (props) {Student.call ( This, props); This. grade = Props.grade | | 1;}//empty function f:functionF () {}//point the prototype F to Student.prototype:F.prototype =Student.prototype;//to point the Primarystudent prototype to a new F object, the prototype of the F object points to Student.prototype:Primarystudent.prototype =NewF ();//Fix the Primarystudent prototype constructor to Primarystudent:PrimaryStudent.prototype.constructor =primarystudent;//continue to define the method on the Primarystudent prototype (that is, the new F () object):PrimaryStudent.prototype.getGrade =function () { return This. grade;};//Create Xiaoming:varXiaoming =Newprimarystudent ({name:' Xiao Ming ', Grade:2}); xiaoming.name; //' Xiao Ming 'Xiaoming.grade;//2//Validating prototypes:xiaoming.__proto__ = = = Primarystudent.prototype;//truexiaoming.__proto__.__proto__ = = = Student.prototype;//true//To validate an inheritance relationship:XiaominginstanceofPrimarystudent;//trueXiaominginstanceofStudent;//true
Use a graph to represent the new prototype chain:
Note that the function is F
only for bridging, we have created only one new F()
instance, and there is no Student
prototype chain that changes the original definition.
If you enclose the inherited action in a inherits()
function, you can also hide F
the definition and simplify the code:
function inherits (Child, Parent) { varfunction () {}; = Parent.prototype; New F (); = Child ;}
This inherits()
function can be reused:
functionStudent (props) { This. Name = Props.name | | ' Unnamed ';} Student.prototype.hello=function() {alert (' Hello, ' + This. Name + '! ');}functionprimarystudent (props) {Student.call ( This, props); This. grade = Props.grade | | 1;}//To implement a prototype inheritance chain:inherits (Primarystudent, Student);//to bind other methods to the Primarystudent prototype:PrimaryStudent.prototype.getGrade =function () { return This. grade;};
Summary
JavaScript's prototype inheritance is implemented in the following way:
Define a new constructor, and internally call()
invoke the constructor that you want to "inherit" and bind to it this
;
F
through the intermediate function to realize the prototype chain inheritance, it is best to complete the encapsulated inherits
function;
Continue to define new methods on the prototype of the new constructor.
Class inheritance
In the above chapters we see the JavaScript object model is based on the prototype implementation, the feature is simple, the disadvantage is more difficult to understand than the traditional class-instance model, the biggest disadvantage is that the implementation of the inheritance needs to write a large number of code, and the need to correctly implement the prototype chain.
New keywords class
are formally introduced into JavaScript from ES6. class
The goal is to make it easier to define classes.
Let's review the methods implemented with functions Student
:
function Student (name) { this. Name =function () { alert (this). Name + '! ' );}
If you write with a new class
keyword Student
, you can write it like this:
class Student { constructor (name) { this. Name= name; } Hello () { alert (this. Name + '! ') ); }}
By comparison, you can see that class
the definition contains constructors constructor
and functions defined on the prototype object hello()
(note that there are no function
keywords), thus avoiding Student.prototype.hello = function () {...}
such scattered code.
Finally, creating an Student
object code is exactly the same as the previous chapter:
var New Student (' Xiao Ming '); Xiaoming.hello ();
Class inheritance
class
another great benefit of defining an object is that inheritance is more convenient. Think about Student
PrimaryStudent
The amount of code we derive from a need to write. Now, the prototype inherits the intermediate object, the prototype object constructor and so on all need not consider, directly through extends
to realize:
class Primarystudent extends Student { constructor (name, grade) { // Remember to call the constructor of the parent class with Super! this . grade = grade; } Mygrade () { alert (this. grade); }}
Note that PrimaryStudent
the definition is also implemented by the Class keyword, which means that the extends
prototype chain object comes from Student
. The constructor for a subclass may not be the same as the parent class, for example, PrimaryStudent
requires name
and grade
two arguments, and you need to super(name)
invoke the constructor of the parent class, otherwise the properties of the parent class are name
not initialized properly.
PrimaryStudent
The method of the parent class has been automatically obtained Student
hello
, and we have defined the new method in the subclass myGrade
.
class
What is the difference between the ES6 introduced and the original JavaScript prototype inheritance? In fact, they do not make any difference, class
the role is to let the JavaScript engine to achieve the original need to write our own prototype chain code. In short, class
the advantage is that the prototype chain code is greatly simplified.
You must ask, class
so good, can you use it now?
It's a little early because not all mainstream browsers support ES6 's class. If you must use it now, you need a tool to class
convert the code into traditional prototype
code, and you can try Babel the tool.
JavaScript Object-Oriented programming