Home  >  Article  >  Web Front-end  >  JavaScript object-oriented technology basic tutorial_javascript skills

JavaScript object-oriented technology basic tutorial_javascript skills

PHP中文网
PHP中文网Original
2016-05-16 18:37:251064browse

I read a lot of articles introducing JavaScript object-oriented technology and I feel confused. Why? It’s not because the writing is not good, but because it is too profound.

The objects in JavaScript have not been explained clearly yet. As soon as I started, I went straight to the topic, class/inheritance/prototype/private variables....
As a result, after reading it for a long time, I got a general understanding. After thinking about it carefully, I seemed to understand nothing...
This article is written with reference to Chapters 7, 8, and 9 of <>. I will
try to explain JavaScript according to the structure of the original book. Object-oriented technology (object/array->function-->class/constructor/prototype). For some things that I am not sure about, I will attach the original English sentences for your reference.
If no explanation is given, all English statements (except the program body) appearing in the article are quoted from <>.
---------- ---------------------------------------
Objects and Arrays
What is an object? Put some "name-attribute" combinations in a unit to form an object. We can understand that the object of
in JavaScript is a collection of "key-value" pairs ( An object is a collection of named values. These named values ​​are usually referred
to as properties of the object.--Section3.5).
"name" can only be of string type, not other types, and The type of the attribute is
arbitrary (number/string/other object...). You can use new Object() to create an empty object, or you can simply use "{}" to create an
empty object. Object, the two functions are equivalent.
Js code

var emptyObject1 = {}; //Create an empty object
var emptyObject2 = new Object(); //Create an empty object
var person = {"name":"sdcyst",
"age":18,
"sex":"male"}; //Create an object containing the initial value person
alert( person.name); //sdcyst
alert(person["age"]); //18


From the above example we can also see that accessing an object For attributes, you can simply use the object name plus "." followed by the name of the attribute. You can also use the "[]" operator to obtain it. At this time, the attribute name in [] must be enclosed in quotation marks. This is because the object The indexes in are all of string type.
The number of attributes in the javasript object is variable. After creating an object, you can assign any attribute to it at any time.
Js code

var person = {};

person.name = "sdcyst";
person["age"] = 18;
alert(person.name person.age); //sdcyst__18
var _person = {name:"balala","age":23}; //When constructing an object, the name of the attribute can be marked (name) without quotation marks,
//But it is still a string type. In When accessing, quotation marks are still required within []
alert(_person["name"] person.age); //balala__23
alert(_person[name]); //undefined

To obtain the properties of an object through the "." operator, you must know the name of the property. Generally speaking, the "[]" operator is more powerful in obtaining the properties of an object.
can be placed in [] Some expressions are used to get the value of the attribute. For example,
can be used in a loop control statement, but the "." operator does not have this flexibility.
Js code

var name = {"name1":"NAME1","name2":"NAME2","name3":"NAME3","name4":"NAME4"};

var namestring = "";
for(var props in name) { //Loop through the property names in the name object
namestring = name[props];
}
alert(namestring); / /NAME1NAME2NAME3NAME4
namestring = "";
for(var i=0; i<4; i ) {
namestring = name["name" (i 1)];
}
alert(namestring); //NAME1NAME2NAME3NAME4

The delete operator can delete a certain attribute in the object, and the "in" operator can be used to determine whether an attribute exists.
Js Code

var name = {"name1":"NAME1","name2":"NAME2","name3":"NAME3","name4":"NAME4"};

var namestring = "";
for(var props in name) { //Loop the property names in the name object
namestring = name[props];
}
alert(namestring); //NAME1NAME2NAME3NAME4
delete name.name1; //Delete name1 attribute
delete name["name3"]; //Delete name3 attribute
namestring = "";
for(var props in name) { //Loop name Property name in the object
namestring = name[props];
}
alert(namestring); //NAME2NAME4
alert("name1" in name); //false
alert( "name4" in name); //true

It should be noted that the attributes in the object are not in order.
The constructor attribute of the object
Every javascript object has A constructor attribute. This attribute corresponds to the constructor when the object is initialized (the function is also an object).
Js code

var date = new Date();
alert(date.constructor); //Date
alert(date.constructor == "Date"); //false
alert(date.constructor == Date); //true

Array
We have already mentioned that an object is a collection of unordered data, and an array is a collection of ordered data. The data (elements) in the array pass To access by index (starting from 0),
the data in the array can be of any data type. The array itself is still an object, but due to many characteristics of arrays, arrays and objects are usually distinguished
Treat (Throughout this book, objects and arrays are often treated as distinct datatypes.
This is a useful and reasonable simplification; you can treat objects and arrays as separate types
for most of your JavaScript programming.To fully understand the behavior of objects and arrays,
however, you have to know the truth: an array is nothing more than an object with a thin layer of extra
functionality. You can see this with the typeof operator: applied to an array value, it returns
the string "object". --section7.5).
To create an array, you can use the "[]" operator, or use the Array() constructor to create a new one.

var array1 = []; //Create an empty array
var array2 = new Array(); //Create an empty array
array1 = [1,"s",[3,4],{"name1 ":"NAME1"}]; //
alert(array1[2][1]); //4 access array elements in the array
alert(array1[3].name1); //NAME1 access Objects in the array
alert(array1[8]); //undefined
array2 = [,,]; //If there is no value but only commas, the element at the corresponding index is undefined
alert( array2.length); //3
alert(array2[1]); //undefined


When using new Array() to create an array, you can specify a default size , the values ​​are undefined at this time, and you can assign values ​​to them later. However, since the length of the array in
javascript can be changed arbitrarily, and the contents of the array can also be changed arbitrarily, the initial length is actually The above
does not have any binding force on the array. For an array, if a value is assigned to an index that exceeds its maximum length, the length of the array will be changed, and undefined will be assigned to the index where no value is assigned
. See below. Example.

var array = new Array(10);
alert(array.length); //10
alert(array[4]); //undefined
array[100 ] = "100th"; //This operation will change the length of the array and set the values ​​corresponding to indexes 10-99 to undefined
alert(array.length); //101
alert(array[87] ); //undefined


You can use the delete operator to delete elements of the array. Note that this deletion only sets the element of the array at that position to undefined, and the length of the array does not change.
We have already used the length attribute of the array. The length attribute is a read/write attribute, which means that we can
change the length of the array arbitrarily by changing the length attribute of the array. If length is set to If the value of length
is greater than the length of the original array, the values ​​between them will be set to undefined.

var array = new Array("n1","n2","n3","n4","n5"); //Array of five elements
var astring = "";
for( var i=0; iastring = array[i];
}
alert(astring); //n1n2n3n4n5
delete array[ 3]; //Delete the value of the array element
alert(array.length "_" array[3]) //5_undefined
array.length = 3; //Reduce the length of the array
alert(array [3]); //undefined
array.length = 8; //Extend the length of the array
alert(array[4]); //undefined


for Other methods of arrays, such as join/reverse, etc., are not given here one by one.
Through the above explanation, we already know that the attribute value of the object is obtained through the name of the attribute (string type), and The elements of the array are obtained by indexing
(integer type 0~~2**32-1). The array itself is also an object, so the operation of object attributes is completely suitable for arrays.

var array = new Array("no1","no2");
array["po"] = "props1";
alert(array.length); //2
//For arrays Say, array[0] has the same effect as array["0"] (? Not sure, this is true during testing)
alert(array[0] "_" array["1"] "_" array.po );//no1_no2_props1


Arrays are also objects, so arrays can have their own attributes, but attributes and values ​​are not the same concept. "no1" and "no2" are both values ​​of the array, and array["po"] is added to the array. If an attribute is added, its length will of course remain unchanged.
Function
I believe everyone has written a lot of JavaScript functions, so we will just introduce them briefly here.
Create function:
function f(x) {... .....}
var f = function(x) {......}
Both of the above two forms can create a function named f(), but the latter form can create Anonymous function
can set parameters when defining the function. If the number of parameters passed to the function is not enough, they will correspond in order from the left, and the rest will be assigned undefined. If there are more parameters passed to the function
than the function definition parameters number, the extra parameters are ignored.

function myprint(s1,s2,s3) {
alert(s1 "_" s2 "_" s3);
}
myprint(); //undefined_undefined_undefined
myprint("string1","string2"); //string1_string2_undefined
myprint("string1","string2","string3","string4"); //string1_string2_string3


Therefore, for a defined function, we cannot expect the caller to pass in all the parameters. Those parameters that must be used should be detected in the function body
(Use ! operator), or set the default value and perform the or (||) operation with the parameters to obtain the parameters.

function myprint(s1,person) {
var defaultperson = { //Default person Object
"name":"name1",
"age":18,
"sex":"female"
};
if(!s1) { //s1 is not allowed Empty
alert("s1 must be input!");
return false;
}
person = person || defaultperson; //Accept person object parameter
alert(s1 "_ " person.name ":" person.age ":" person.sex);
};
myprint(); //s1 must be input!
myprint("s1"); //s1_name1 :18:female
myprint("s1",{"name":"sdcyst","age":23,"sex":"male"}); //s1_sdcyst:23:male


The arguments attribute of the function
Inside each function body, there is an arguments identifier, which represents an Arguments object. The Arguments object is very similar
to Array (array) Objects, for example, all have a length attribute. To access its value, use the "[]" operator to access the parameter value using an index. However, the two are completely different
things, and they only have similarities on the surface (for example Modifying the length property of the Arguments object does not change its length).

function myargs() {
alert(arguments.length);
alert(arguments[0]);
}
myargs(); //0 --- undefined
myargs("1",[1,2]); //2 --- 1


The Arguments object has a callee attribute, which indicates the method in which the current Arguments object is located. You can use it to implement internal recursive calls of anonymous functions.

function(x) {
if (x <= 1) return 1;
return x * arguments.callee(x-1);
} (section8.2)


Method--Method
Method is a function. We know that every object contains 0 or more attributes, and the attributes can be of any type, including objects of course. The function itself is a
object, so we can put a function into an object. , this function becomes a method of the object. If you want to use this method later,
you can use the "." operator through the object name.

var obj = {f0:function( ){alert("f0");}}; //The object contains a method
function f1() {alert("f1");}
obj.f1 = f1; //Add a method to the object
obj.f0(); //f0 f0 is a method of obj
obj.f1(); //f1 f1 is a method of obj
f1(); //f1 f1 is also a function, You can call
f0() directly; //f0 is only a method of obj, which can only be called through an object. The call of


method requires the support of the object, so how to do it in the method? What about getting the properties of an object? This! We are already familiar with the this keyword. In the JavaScript method
, we can use this to get a reference to the method caller (object), thereby getting the various attributes of the method caller. Attribute.

var obj = {"name":"NAME","sex":"female"};
obj.print = function() { //Add methods to the object
alert(this.name "_" this["sex"]);
};
obj.print(); //NAME_female
obj.sex = "male";
obj.print (); //NAME_male


Let’s take a more object-oriented example.

var person = {name:"defaultname",
setName:function (s){
this.name = s;
},
"printName":function(){
alert(this.name);
}}
person.printName (); //defaultname
person.setName("newName");
person.printName(); //newName


In the above example, you can use person.name=.. to directly change the name attribute of person. Here we just want to show what we just mentioned.
Another way to change person The attribute method is: define a function that receives two parameters, one is the person and the other is the value of the name. It looks like this:
changeName(person, "newName"). Which method is better? It's obvious. , the method in the example is more vivid and intuitive, and it seems to have a little shadow of
object-oriented.
Let me emphasize again, the method (Method) itself is a function (function), but the use of the method More restricted. In the following pages, if functions are mentioned, then the content mentioned in
also applies to methods, but not vice versa.
Prototype attribute of function
Each function contains a prototype (Prototype) attribute, this attribute forms the core foundation of object-oriented JavaScript. We will discuss in detail later

classes, constructors, prototypes

Let’s explain one point first :As mentioned in the above content, each function contains a prototype property, which points to a prototype object (Every
function has a prototype property that refers to a predefined prototype object --section8.6.2). Be careful not to confuse
.

Constructor: The
new operator is used to generate a new object. New must be followed by a function, which is what we often call a constructor. How does the constructor work?
Let’s look at an example first:

function Person(name,sex) {
this.name = name;
this. sex = sex;
}
var per = new Person("sdcyst","male");
alert("name:" per.name "_sex:" per.sex); //name :sdcyst_sex:male

The following explains the steps of this work:
Start by creating a function (not a method, just an ordinary function). Notice the use of the this keyword. Previously we mentioned The this keyword indicates the object that calls the method, that is to say, when the "method" is called through the object, the this keyword will point to the object (without using the object to directly call the function, this will point to the entire script domain) , or the domain where the function is located (we will not discuss it in detail here
). When we use the new operator, JavaScript will first create an empty object, and then this object will be used by the this of the method (function) after new Keyword reference! Then in the method
by operating this, the newly created object is assigned the corresponding attributes. Finally, the processed object is returned. In this way, the above example is very clear: first create an empty object, Then
calls the Person method to assign it, and finally returns the object, and we get a per object.

prototype (prototype)-"Prototype object" and "prototype" will be mentioned repeatedly here Attribute", pay attention to distinguishing these two concepts.
In JavaScript, each object has a prototype attribute, which points to a prototype object.
We mentioned above the process of using new to create an object. In fact, in this process, when an empty object is created, new will then operate the prototype attribute of the object just generated.
Each method has a prototype attribute (because the method itself is also an object), and the new operator generates The prototype attribute value of the new object is consistent with the prototype attribute value of the constructor. The prototype attribute of the constructor
points to a prototype object. This prototype object initially has only one attribute constructor, and this constructor attribute points to prototype. In the previous section, I showed that the new operator creates a new, empty object and then invokes a constructor function as a method of that object. This is not the complete story, however . After creating the empty object,
new sets the prototype of that object. The prototype of an object is the value of the prototype property of its
constructor function. All functions have a prototype property that is automatically created and initialized when
the function is defined. The initial value of the prototype property is an object with a single property. This property
is named constructor and refers back to the constructor function with which the prototype is associated. this is why every
object has a constructor property. Any properties you add to this prototype object will appear to be properties of
objects initialized by the constructor. -----section9.2)
It’s a bit confusing, look at the following Figure:


In this way, when a new object is created using a constructor, it will obtain all the attributes of the prototype object pointed to by the prototype attribute of the constructor. For the prototype object corresponding to the constructor
Any operation done will be reflected on the objects it generates. All these objects share the properties (including methods) of the prototype object corresponding to the constructor. Let’s look at a specific example:

function Person(name,sex) { //Constructor
this.name = name;
this.sex = sex;
}
Person.prototype.age = 12; // Assign values ​​to the attributes of the prototype object corresponding to the prototype attribute
Person.prototype.print = function() { //Add method
alert(this.name "_" this.sex "_" this.age);
};
var p1 = new Person("name1","male");
var p2 = new Person("name2","male");
p1.print(); / /name1_male_12
p2.print(); //name2_male_12
Person.prototype.age = 18; //Change the attribute value of the prototype object. Note that the prototype attribute of the constructor is operated
p1.print() ; //name1_male_18
p2.print(); //name2_male_18


So far, we have simulated the implementation of a simple class. We have a constructor and With class attributes and class methods, you can create "instances".
In the following article, we will use the name "class" to replace the constructor method, but this is just a simulation, not a true object-oriented "Class".
Before the next introduction, let's first take a look at the precautions for changing the prototype attribute of the object and setting the prototype attribute:
Give an explanation that is not very appropriate, which may help us Understanding: When we new an object, the object will obtain the prototype attribute of the constructor (including functions and variables). It can be considered that the constructor (class) inherits the prototype object corresponding to its prototype attribute. Functions and variables, that is to say, the
prototype object simulates the effect of a super class. It sounds a bit confusing, let’s look at an example directly:

function Person(name,sex) { //Person Class constructor

this.name = name;
this.sex = sex;
}
Person.prototype.age = 12; //The prototype object corresponding to the prototype attribute of the Person class Attribute assignment,
//Equivalent to adding attributes to the parent class of Person class
Person.prototype.print = function() { //Add method to the parent class of Person class
alert(this.name " _" this.sex "_" this.age);
};
var p1 = new Person("name1","male"); //The age attribute of p1 inherits the parent class of the child Person class ( That is prototype object)
var p2 = new Person("name2","male");
p1.print(); //name1_male_12
p2.print(); //name2_male_12
p1 .age = 34; //Change the age attribute of the p1 instance
p1.print(); //name1_male_34
p2.print(); //name2_male_12
Person.prototype.age = 22; // Change the age attribute of the super class of the Person class
p1.print(); //name1_male_34 (the age attribute of p1 does not change with the change of the prototype attribute)
p2.print(); //name2_male_22( The age attribute of p2 has changed)
p1.print = function() { //Change the print method of the p1 object
alert("i am p1");
}
p1.print( ); //i am p1 (p1's method has changed)
p2.print(); //name2_male_22 (p2's method has not changed)
Person.prototype.print = function() { // Change the print method of Person super class
alert("new print method!");
}
p1.print(); //i am p1 (p1's print method is still its own method)
p2.print(); //new print method! (p2’s print method changes with the change of the super class method)


I read an article that the prototype attribute of an object in JavaScript is equivalent to a static variable in Java and can be shared by all objects
under this class. The above example seems to indicate that the actual situation is not Like this:
In JS, when we use the new operator to create an instance object of a class, its methods and attributes do inherit the prototype attributes of the class, and the methods and attributes defined in the prototype attributes of the class
, indeed can be directly referenced by these instance objects. However, when we reassign or define the attributes and methods of these instance objects, then
the attributes or methods of the instance objects no longer point to the attributes defined in the prototype attribute of the class and methods. At this time, even if the corresponding method or
attribute in the prototype attribute of the class is modified, it will not be reflected on the instance object. This explains the above example:
Initially, use new The operator generated two objects p1 and p2. Their age attribute and print method all come from (inherited from) the prototype attribute of the Person class. Then, we
modified the age attribute of p1, and then faced the prototype of the Person class The age in the attribute is reassigned (Person.prototype.age = 22). The age attribute of p1 will not
change accordingly, but the age attribute of p2 will change accordingly, because the age attribute of p2 is still quoted from The prototype attribute of the Person class. The same situation is also reflected in the
print method later.
Through the above introduction, we know that the prototype attribute simulates the role of the parent class (super class) in JavaScript. Reflecting the object-oriented idea in js, the prototype attribute
is very critical.
Class variables/class methods/instance variables/instance methods
First, let me add the previously written methods:
In JavaScript, all methods have a call method and an apply method. These two methods can simulate object calling methods. Its first parameter is the object, and the following
parameters indicate when the object calls this method. The arguments of ECMAScript specifies two methods that are defined for all functions, call()
and apply(). These methods allow you to invoke a function as if it were a method of some other object. The first
argument to both call() and apply() is the object on which the function is to be invoked; this argument becomes
the value of the this keyword within the body of the function. Any remaining arguments to call() are the values
that are passed to the function that is invoked). For example, we define a method f(), and then call the following statement:
f.call(o, 1, 2);
The effect is equivalent In
o.m = f;
o.m(1,2);
delete o.m;
For example:

function Person(name,age) { //Definition method
this.name = name;
this.age = age;
}
var o = new Object(); //Empty object
alert(o.name "_" o.age ); //undefined_undefined
Person.call(o,"sdcyst",18); //Equivalent to calling: o.Person("sdcyst",18)
alert(o.name "_" o. age); //sdcyst_18
Person.apply(o,["name",89]);//The apply method works the same as call, the difference is that the form of passing parameters is to use an array to pass
alert( o.name "_" o.age); //name_89


Instance variables and instance methods are obtained by adding the "." operator to the instance object and then followed by the attribute name or method name to access, but we can also set methods or variables for the class,
In this way, we can directly use the class name plus the "." operator and then follow the attribute name or method name to access it. It is very easy to define class attributes and class methods. Simple:

Person.counter = 0; //Define class variables, the number of Person instances created
function Person(name,age) {
this.name = name;
this.age = age;
Person.counter; //No instance is created, the class variable counter is incremented by 1
};
Person.whoIsOlder = function(p1,p2) { //Class method, judgment Who is older
if(p1.age > p2.age) {
return p1;
} else {
return p2;
}
}
var p1 = new Person("p1",18);
var p2 = new Person("p2",22);
alert("Now there is" Person.counter "Person"); //Now there are 2 Person
var p = Person.whoIsOlder(p1,p2);
alert(p.name "older"); //p2 is older


Application of prototype attribute:
The following example is adapted from the original book.
Suppose we define a Circle class with a radius attribute and area method, and the implementation is as follows:

function Circle (radius) {
this.radius = radius;
this.area = function() {
return 3.14 * this.radius * this.radius;
}
}
var c = new Circle(1);
alert(c.area()); //3.14


Suppose we define 100 instance objects of the Circle class, then each Instance objects have a radius attribute and area method.
In fact, except for the radius attribute, the area method of each instance object of the Circle class is the same. In this case, we can
extract the area method and define it In the prototype attribute of the Circle class, all instance objects can call this method,
to save space.

function Circle(radius) {
this.radius = radius;
}
Circle.prototype.area = function() {
return 3.14 * this.radius * this.radius;
}
var c = new Circle(1);
alert(c.area()); //3.14


Now, let’s use the prototype attribute to Simulate class inheritance: first define a Circle class as the parent class, and then define the subclass
PositionCircle.

function Circle(radius) { //Define the parent class Circle
this. radius = radius;
}
Circle.prototype.area = function() { //Define the parent class method area to calculate the area
return this.radius * this.radius * 3.14;
}
function PositionCircle(x,y,radius) { //Define class PositionCircle
this.x = x; //Attribute abscissa
this.y = y; //Attribute ordinate
Circle. call(this,radius); //Calling the method of the parent class is equivalent to calling this.Circle(radius) and setting the
//radius attribute of the PositionCircle class
}
PositionCircle.prototype = new Circle( ); //Set the parent class of PositionCircle to the Circle class
var pc = new PositionCircle(1,2,1);
alert(pc.area()); //3.14
//PositionCircle class The area method inherits from the Circle class, and the
//area method of the Circle class inherits from the prototype object corresponding to its prototype attribute
alert(pc.radius); //1 The radius attribute of the PositionCircle class inherits from Circle class
/*
Note: Earlier we set the prototype attribute of the PositionCircle class to point to a Circle object,
so the prototype attribute of pc inherits the prototype attribute of the Circle object, and the constructor attribute of the Circle object
property (that is, the constructor attribute of the prototype object corresponding to the Circle object) points to Circle, so the
that pops up here is Circle.
*/
alert(pc.constructor); //Circle
/*For this reason, after we design the inheritance relationship of the class, we also need to set the constructor attribute of the subclass, otherwise it will point to the constructor attribute of the parent class

*/
PositionCircle.prototype .constructor = PositionCircle
alert(pc.constructor); //PositionCircle


Scope, closure, simulated private properties
Let’s keep it simple first Let’s talk about variable scope. We are all familiar with these things, so we won’t introduce them in detail.

var sco = "global"; //Global variable
function t() {
var sco = "local"; //Local variable inside the function
alert(sco); //local calls local variables first
}
t(); //local
alert(sco); //global cannot use local variables within functions


Note that there is no block-level scope in javascript, which means that in java or c/c we can
surround a block with "{}" to define local variables within the block, in Outside the "{}" block, these variables no longer work.
At the same time, local variables can also be defined in control statements such as for loops, but this feature is not available in JavaScript:

function f( props) {
for(var i=0; i<10; i ) {}
alert(i); //10 Although i is defined in the control statement of the for loop, it is in the function
/ The variable can still be accessed from other locations in /.
if(props == "local") {
var sco = "local";
alert(sco);
}
alert( sco); //Similarly, the function can still refer to the variables defined in the if statement
}
f("local"); //10 local local


in the function Be extra careful when defining local variables internally:

var sco = "global";
function print1() {
alert(sco); //global
}
function print2 () {
var sco = "local";
alert(sco); //local
}
function print3() {
alert(sco); //undefined
var sco = "local";
alert(sco); local
}
print1(); //global
print2(); //local
print3(); //undefined local


The first two functions are easy to understand, but the key is the third one: the first alert statement does not display the global variable "global", but
is undefined , this is because in the print3 function, we defined the sco local variable (no matter where it is), then the global
sco attribute will not work inside the function, so the sco in the first alert is actually the local sco. Variable, equivalent to:

function print3() {
var sco;
alert(sco);
sco = "local";
alert(sco);
}


From this example we can conclude that when defining local variables inside a function, it is best to define the required variables at the beginning to avoid errors.
The scope of the function has been determined when the function is defined, for example:

var scope = "global" //Define global variables
function print() {
alert(scope) ;
}
function change() {
var scope = "local"; //Define local variables
print(); //Although the print function is called within the scope of the change function,
//But when the print function is executed, it still works according to the scope when it was defined
}
change(); //golbal


Closure
Closure is an expression with variables, code and scope. In JavaScript, a function is a combination of variables, code and function scope, so all
functions All JavaScript functions are a combination of code to be executed and the scope in which to
execute them. This combination of code and scope is known as a closure in the computer science literature.
All JavaScript functions are closures). It seems quite simple. But what exactly does closure do? Let’s look at an example.
We want to write a method to get an integer every time. This integer is increased by 1 each time. Without thinking, we write immediately:

var i = 0;
function getNext () {
i;
return i;
}
alert(getNext()); //1
alert(getNext()); //2
alert(getNext ()); //3


Always use the getNext function to get the next integer, and then accidentally or deliberately set the value of global variable i to 0, and then call getNext again,
You will find that it starts from 1 again... At this time, you will think, how nice it would be to set i as a private variable, so that it is
possible to change it only within the method. There is no way to modify it outside the function. The following code is based on this requirement, and we will discuss it in detail later.
For the convenience of explanation, we call the following code demo1.

function temp() {
var i = 0;
function b() {
return i;
}
return b;
}
var getNext = temp();
alert(getNext()); //1
alert(getNext()); //2
alert(getNext()); //3
alert(getNext()); //4


Because most of the javascript we usually talk about is It refers to under the client (browser), so this is no exception.
When the JavaScript interpreter starts, it will first create a global object, which is the object referenced by "window".
Then all the global properties and methods we define will become this object. Properties.
Different functions and variables have different scopes, thus forming a scope chain. Obviously, when the JavaScript interpreter starts,
this scope chain has only one object: window (Window Object, global object).
In demo1, the temp function is a global function, so the scope chain corresponding to the scope (scopr) of the temp() function is the scope chain when the js interpreter is started. , there is only one window object.
When temp is executed, first create a call object (active object), and then add this call object to the front of the scope chain corresponding to the temp function. This is the scope corresponding to the temp() function
The chain contains two objects: the window object and the call object (active object) corresponding to the temp function. Then, because we defined the variable i in the temp function,
defined the function b(), these will become call object's properties. Of course, before this, the arguments attribute will be added to the call object first, saving the parameters passed by
when the temp() function is executed. At this time, the entire scope chain is as shown in the figure below:

In the same way, we can get the entire scope chain when function b() is executed:



Note that in the scope chain of b(), the call object corresponding to the b() function has only one argument attribute and no i attribute. This is because in the definition of b(), it is not used. Use the var keyword to
declare the i attribute. Only attributes declared with the var keyword will be added to the corresponding call object.
When the function is executed, first check whether the corresponding call object has the required attributes. If If not, search one level higher until you find it. If it cannot be found, it is undefined.

In this way, let’s take a look at the execution of demo1. We used getNext to reference the temp function, and the temp function returned function b, so the getNext function is actually a reference to the b function.
When getNext is executed once, the b() function is executed once. Because the scope of function b() depends on function temp, the temp function will always exist in memory. When function b is executed, it first searches for
i, which is not found in the call object corresponding to b, so it goes up a level and finds it in the call object corresponding to the temp function, so its value is increased by 1, and then this value is returned. .
In this way, as long as the getNext function is valid, the b() function will always be valid. At the same time, the temp function that the b() function depends on will not disappear, nor will the variable i, and this variable is in the temp function
It cannot be accessed from the outside at all, it can only be accessed inside the temp() function (b is of course possible).

Let’s look at an example of using closures to simulate private properties:

function Person(name, age) {
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
this. getAge = function() { return age; };
this.setAge = function(newAge) { age = newAge; };
}

var p1 = new Person("sdcyst",3 );
alert(p1.getName()); //sdcyst
alert(p1.name); //undefined because Person('class') does not have a name attribute
p1.name = "mypara" //Display the name attribute to p1
alert(p1.getName()); //sdcyst but it will not change the return value of the getName method
alert(p1.name); //mypara displays p1 The name attribute of the object
p1.setName("sss"); //Change the private "name" attribute
alert(p1.getName()); //sss
alert(p1.name); //A Person class is still defined for mypara

, with two private attributes name and age, respectively defining corresponding get/set methods.
Although the name and age attributes of p1 can be set explicitly, this displayed setting will not change the "name/age" private attribute that we
simulated during the initial design.

Explaining closures is indeed not an easy task. Many people on the Internet also use examples to illustrate closures. If something is wrong, please correct me.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn