Constructor
The method of defining classes by keyword class and then creating objects according to classes introduced in the previous blog is the syntax in ES6. At present, many browsers do not support ES6 very well, so we should also learn to create objects by constructor (build function)
Ask? Since the browser's support for ES6 is not very good, should we not use ES6 syntax when writing code? (after reading this article, you will have the answer)
1. Constructors and prototypes
1.1 three ways to create objects - Review
-
Literal mode
var obj = {};
-
new keyword
var obj = new Object();
-
Constructor mode
function Person(name,age){ this.name = name; this.age = age; } var obj = new Person('zs',12);
explain:
Constructor is a special function, which is mainly used to initialize objects, that is, to initialize the values of object members. It is used together with new to create objects
The constructor mentioned here is different from the constructor in the class mentioned earlier. The constructor in the class is mainly to assign values to the attributes in the class. The constructor here can either package attributes or contain methods, which is closer to the concept of the class mentioned above. It can be regarded as a transition in the process of J S's complete transformation to object-oriented
Therefore, when writing the constructor, you can refer to the definition of the class, abstract some public properties and methods of the object, and then encapsulate them into this function
As shown below, the instance object is generated by using the class in ES6 and the constructor in ES5 respectively
/* *ES6 Method for creating objects in: first create a class using the class keyword, and then create the class object using the new class name () */ class Person { constructor(name, age) { this.name = name this.age = age } speak(){ console.log('Whoa, whoa, whoa, whoa') } } // Create an object of class var p1 = new Person('Li Bai', 20) // Accessing properties in a class console.log(p1.name) p1.speak() console.log('---------------------') /* *ES5 Method of creating an object in: first create a constructor, and then create the object of this function by using the new function name () */ function Star(name, gender) { this.name = name this.gender = gender this.sing=function(){ console.log('Little, little Erlang') } } // Creating objects through constructors var s1 = new Star('Du Fu', 'male') console.log(s1.gender) s1.sing()
graphic
Pay attention to two points
1) The constructor is capitalized, just like creating a class using class
2) Use with the new keyword, which is more like class
3) The most important point is that the writing method of a class is more like a syntax sugar. The purpose is to enable us to write a class quickly, comfortably and gracefully, but in essence, a class is actually a function. Beginners may not feel the advantages of class definition over constructor: 1) they do not feel the pain of inheritance through constructor, so they cannot understand the advantages of inheritance through extensions in ES6; 2) I haven't seen the traditional face turn into language
console.log(typeof Person); console.log(typeof FPerson);
result
new explanation
Create a new empty object in memory
Let this point to this object, so using this in the code is to use this object. This has nothing to do with the class
Execute the code in the constructor to add properties and methods to the object, but the code in the method will not be executed
1.2 static members and instance members
1.2.1 instance members
Instance members are members added through this inside the constructor. For example, in the following code, name age sing is an instance member, and instance members can only be accessed through instantiated objects
/*Members added through this are instance members 1)Instance members can only be accessed through object members 2)Instance members are related to each object, that is, the values of members of each object are different */ function Star(name, gender) { this.name = name this.gender = gender this.sing = function () { console.log('Little, little Erlang') } } // Creating objects through constructors var s1 = new Star('Du Fu', 'male') var s2 = new Star('Cai Xukun', 'female') console.log(s1.gender) console.log(s2.gender) // Instance members cannot be accessed through [constructor name. Member] // console.log(Star.gender) // undefined
This is the same as the class created by class in ES6
class Star { constructor(uname, age) { this.uname = uname this.age = age } sing() { console.log('I can sing') } } var ldh=new Star('Lau Andy',17) console.log(ldh.uname)
1.2.2 static members
A static member is a member added to the constructor itself. For example, the following code is a static member. Static members can only be accessed through the constructor
This is the same as when defining a class through the class keyword
Summary:
Instance members belong to objects, so the values of instance members of the two objects are different
Static members belong to the constructor itself, and each object belongs to this constructor, so multiple objects share a static member
1.3 constructor problems
Constructor method is easy to use, but there is a problem of wasting memory.
1.4 constructor prototype
The function allocated by the constructor through the prototype is shared by all objects.
JavaScript stipulates that each constructor has a prototype attribute that points to another object. Note that this prototype is an object called a prototype object
The same is true for the class in ES6, because we said that the class is also a function in essence
function Star(name, gender) { this.name = name this.gender = gender this.sing = function () { console.log('Little, little Erlang') } } console.log(Star.prototype)
All the properties and methods of this object will be owned by the constructor
function Star(name, gender) { this.name = name this.gender = gender this.sing = function () { console.log('Little, little Erlang') } } // Add a method to the prototype object of Star (equivalent to adding a method to the parent class of Star) Star.prototype.cry=function(){ console.log('i want cry,cry,cry,cry,cry') } Star.prototype.dance=function(){ console.log('Step by step, like the steps of the devil') } // Through the output, it is found that there is indeed a cry method on the prototype object console.log(Star.prototype) // Then the Star constructor, as a subclass of the prototype object, naturally has the cry method var s1 = new Star('Du Fu', 'male') s1.cry() s1.dance() var s2 = new Star('Cai Xukun', 'female') s2.cry() s2.dance()
You can also add multiple methods to the prototype in the form of objects
We can define those invariant methods directly on the prototype object, so that all object instances can share these methods.
Dispel doubts:
1) This prototype is similar to the base class in other languages....
2) Not only the objects defined by constructors or classes, but also the methods of built-in objects in JS are actually defined on the prototype object of this object
var arr=[] // View the prototype of an object__ proto__ attribute console.log(arr.__proto__) // To view the prototype object of a constructor or class, use the prototype property console.log(Array.prototype) // Summary: of objects__ proto__ Property and the proptype property of a class or constructor point to the same object
1.5 object prototype
Constructor prototype Property gets the prototype object of the current constructor Of an instance of the constructor__proto__Property gets the object prototype of the current object These two are one object, that is, the prototype object of the constructor and the object prototype of the instance of this constructor are the same object
function Star(name, gender) { this.name = name this.gender = gender this.sing = function () { console.log('Little, little Erlang') } } // Add a method to the prototype object of Star (equivalent to adding a method to the parent class of Star) Star.prototype.cry = function () { console.log('i want cry,cry,cry,cry,cry') } Star.prototype.dance = function () { console.log('Step by step, like the steps of the devil') } // Through the output, it is found that there is indeed a cry method on the prototype object console.log(Star.prototype) // Then the Star constructor, as a subclass of the prototype object, naturally has the cry method var s1 = new Star('Du Fu', 'male') // s1.cry() // Of s1 object__ proto__ Property gets the object prototype of the s1 object console.log(s1.__proto__) // Verify that the prototype object of the constructor is an object with the strength of the object prototype console.log(Star.prototype===s1.__proto__)
1.6 constructor
Both proto and prototype objects have an attribute constructor attribute (because the two are actually one thing). Constructor is called constructor because it refers to the constructor itself.
The following is understood through the code
function Star(name, gender) { this.name = name this.gender = gender this.sing = function () { console.log('Little, little Erlang') } } var s1 = new Star('Du Fu', 'male') // Prototype object of output constructor console.log(Star.prototype) // Object prototype of output object console.log(s1.__proto__)
Through the above code, we can see that the value of the constructor property is indeed the constructor corresponding to this object
Not only can the constructor of the prototype object be obtained through this attribute, but also the constructor attribute can make the prototype object point to the original constructor again
In general, the methods of the object are set in the prototype object of the constructor.
As follows
// Add the speak method to the prototype object of the constructor Person.prototype.speak=function(){ console.log('Human speech') }
However, if multiple methods are added, it is more troublesome to use the above method
function Star(name, gender) { this.name = name this.gender = gender } // Add sing method like prototype Star.prototype.sing = function () { console.log('The Red Star glittered'); } // Add dance method to prototype Star.prototype.dance = function () { console.lo('Devil's pace') } // Add fly to prototype Star.prototype.fly = function () { console.log('Slippers when you get on the plane') }
Like the above, if you want to add multiple methods, we can assign values to the prototype object in the form of objects, as shown in the following code
Star.prototype = { sing: function () { console.log('The Red Star glittered'); }, dance: function () { console.lo('Devil's pace') }, fly: function () { console.log('Slippers when you get on the plane') } }
However, this will overwrite the original content of the constructor prototype object, so that the modified prototype object constructor will no longer point to the current constructor
At this point, we can add a constructor to the modified prototype object to point to the original constructor.
result
Summary: if we modify the original prototype object and assign an object to the prototype object, we must manually use the constructor to refer back to the original constructor, such as:
Complete code
function Star(name, gender) { this.name = name this.gender = gender } Star.prototype = { construcotr:Star, sing: function () { console.log('The Red Star glittered'); }, dance: function () { console.lo('Devil's pace') }, fly: function () { console.log('Slippers when you get on the plane') } } console.log(Star.prototype)
1.7 prototype chain
Each instance object has another__ proto__ Property that points to the prototype object of the constructor. The prototype object of the constructor is also an object__ proto__ Attribute, so looking up layer by layer forms the prototype chain.
It can be compared with the base class, which is Object
In fact, the top-level Object prototype of all custom or system built-in constructors or classes is Object
1.8 triangular relationship between constructor instance and prototype object
1. The prototype attribute of the constructor points to the constructor prototype object, and the constructor attribute of the constructor prototype object points to the constructor
function Star(name, age) { this.name = name this.age = age } // Gets the prototype object of the output constructor console.log(Star.prototype) // Gets and outputs the constructor of the prototype object console.log(Star.prototype.constructor) // Prove that the constructor property of the prototype object does get the corresponding constructor console.log(Star.prototype.constructor===Star)
2. The instance object is created by the constructor__ proto__ Property points to the prototype object of the constructor
// Instance objects are created by constructors var s1=new Star('Xiao Zhan',18) // Instance object__ proto__ Property points to the prototype object of the corresponding constructor console.log(s1.__proto__)
3. The constructor attribute of the prototype object of the constructor points to the constructor. The prototype of the instance object is the prototype object of the constructor. The constructor attribute in this object also points to the constructor
Important note: the above theory is also applicable to ES6
class Star { constructor(name){ this.name=name } } var s=new Star('yhb') console.log(Star.prototype) console.log(s.__proto__)
1.9 prototype chain and member search mechanism
Any object has a prototype object, that is, the prototype attribute. Any prototype object is also an object, and the object has__ proto__ Attributes, looking up layer by layer, form a chain, which we call prototype chain;
When accessing an object's properties (including methods), first find out whether the object itself has the property. If not, find its prototype (that is __proto__directive prototype Prototype object). If not, find the prototype of the prototype object( Object Prototype object). And so on Object Until( null). __proto__The significance of object prototype is to provide a direction, or a route, for the object member search mechanism.
1.10 this point in prototype object
Both this in the constructor and this in the prototype object point to the instance object we created new
1. this in the constructor points to the new object
function Star(name, age) { this.name = name this.age = age console.log(this) } var s1=new Star('Li Bai',20) var s2=new Star('Du Fu',17)
2. this on the prototype object of the constructor also points to the object from new
function Star(name, age) { this.name = name this.age = age console.log(this) } Star.prototype.sing=function(){ console.log(this) } var s1=new Star('Li Bai',20) var s1=new Star('Du Fu',17)
Through the following code, you can also compare whether the two objects only want new objects
function Star(name, age) { this.name = name this.age = age } var that = null // this in the prototype object of the constructor Star.prototype.sing = function () { that = this } var s1 = new Star('Li Bai', 20) // Han bingxu said: the sing method must be called, otherwise the assignment operation cannot be performed s1.sing() console.log(that === s1)
1.11 extend built-in methods for arrays through prototypes
View the prototype of the array
console.log(Array.prototype);
An array extension and a method that calculates the sum of elements in an array
var numbers = new Array(1, 2, 3, 4, 5) // Traditional method of summation // var sum = 0 // for (var i = 0; i < numbers.length; i++) { // sum += numbers[i] // } // By changing the prototype Array.prototype.sum = function () { var sum = 0 for (var i = 0; i < this.length; i++) { sum += this[i] } return sum } console.log(numbers.sum()) // Create another Array, which is also an instance of the Array class created in [] mode var arr=[2,3,4,7] console.log(arr.sum()) console.log(Array.prototype)
2. Succession
Before ES6, there was no extend keyword to implement class inheritance. You need to simulate inheritance through constructor + prototype object. This method is called composite inheritance
2.1call()
- call() can call a function
- Call() can modify the point of this. When using call(), parameter 1 is the modified point of this. Parameter 2, parameter 3 (normal parameters)... Use commas to separate the connection
The following code simply calls the function
function f1() { console.log(this) //window } f1.call()
The following code modifies the direction of this
function f1() { /* *1)By default, this=window *2)After using call, this=p */ console.log(this) } f1.call() // Output window // Create object p var p={} // Modify this point of function f1 to object p f1.call(p) // Output p
The first parameter of the call method above is the new object referenced by this, and the following parameters are used as ordinary parameters of function f1
Code demonstration
2.2 the child constructor inherits the properties in the parent constructor
Let's use the above knowledge to realize the inheritance of constructors (the so-called inheritance is to let one class have properties and methods in another class, in other words, to replace the host of properties and methods in class A with the object of B)
The steps are as follows
- Define a parent constructor first
- Define a sub constructor
- The child constructor inherits the properties of the parent constructor (using the call method)
The above conclusion is proved by debugging
The above case only demonstrates the inheritance of attributes, and the inheritance of methods is the same
2.3 borrowing prototype object inheritance method
In the above way, we can inherit the methods in the constructor (for simplicity, we will call it class later), but as mentioned earlier, in actual development, we prefer to register the methods on the prototype of the class
function Father(name, age) { this.name = name this.age = age } Father.prototype.speak = function () { console.log('hello') } function Son(gender) { // Note ① Father.call(this, 'Zhang San', 20) this.gender = gender } var f=new Father('yhb',30) console.log(f) var s = new Son('female') console.log(s)
Output results
Therefore, there is no speak method in Son's object
In fact, the reason is very simple. If the speak method is added to the prototype object of Father, then Father will inherit this method. However, at present, Son has nothing to do with Father and the prototype of Father. We just skillfully use its name and age attributes through the call method, so naturally there is no speak method in Son
How to solve it?
We can modify Son's prototype to Father's prototype, so Son has the speak method
Output results
We found that the speak method does exist in Son
However, the problem also arises. Because the prototype object of Father and Son is the same at this time, if we want to add a method to the prototype object of Son at this time
Son.prototype.run=function(){ console.log('run') }
Then output two objects respectively
This violates the principle of inheritance: only the son can inherit from the father, but now the father can also inherit from the son
Solution: put the following code
Son.prototype=Father.prototype
Replace with the following
Son.prototype=new Father()
That is, let the prototype object of Son point to the object instance of Father. The proto attribute of this instance points to the object prototype of Father, so it has the speak method. But this is only an instance object. I want to copy a copy from the Father class. Modifying the prototype of this object will not affect the object of the ther class. Therefore, modifying this instance will not affect the prototype object of Father
A slight problem is that at this time, Son's constructor points to Father's constructor
console.log(s.constructor)
Use the following code to point its constructor back to Son's constructor
Son.prototype.constructor=Son
Complete code
/* Using call to realize the inheritance of constructor*/ function Father(name, age) { this.name = name this.age = age } Father.prototype.speak = function () { console.log('hello') } function Son(gender) { // Note ① Father.call(this, 'Zhang San', 20) this.gender = gender } Son.prototype=new Father() // Modify the constructor of Son to Son Son.prototype.constructor=Son // Add a method to the prototype object like Son Son.prototype.run=function(){ console.log('run') } //var f=new Father('yhb',30) // console.log(f) var s = new Son('female') console.log(s) console.log(s.constructor)
Illustration:
3.ES5 new method
About the relationship between ECMAScript and JS, as well as various versions of ES, you can baidu by yourself. Xiaobian will not explain here
ES6 is upgraded on the basis of ES5, so learn the new features of ES5 first, and then learn the new features of ES6 later
3.1 array method forEach traversal array
This method is used to facilitate the array. The parameter is a function
If you want to facilitate the array in the future, you don't have to write your own loop
var numbers = [1, 3, 5, 7, 9] numbers.forEach(function (item, index, ary) { console.log('element:' + item); console.log('Indexes:' + index); console.log('Array itself:' + ary); })
Case: array summation
var sum=0 numbers.forEach(function(item){ sum+=item }) console.log(sum)
3.2 array filtering method filter array
This method has a return value, which is used to receive all elements that meet the filtering conditions. The type of the return value is array
var numbers = [1, 2, 3, 4, 5, 6] /*The following code filters out all elements > 4 from the array numbers, and then puts them into the new array result Note: you must have the return keyword */ var result = numbers.filter(function (item, index) { return item > 4 }) console.log(result);
Output results
3.3 array method some
some Find whether there are elements in the array that meet the conditions var arr = [10, 30, 4]; var flag = arr.some(function(item,index,array) { //Parameter 1: array element //Parameter 2 is the index of array elements //Parameter 3: current array return item < 3; }); console.log(flag);//false the return value is a Boolean value. As long as an element satisfying the condition is found, the loop will be terminated immediately
**The some() * * method tests whether at least one element in the array has passed the provided function test. It returns a value of type Boolean.
If you test with an empty array, it returns false in any case.
Syntax:
arr.some(callback(element[, index[, array]])[, thisArg])
1) The return value is Boolean
2) If the element that meets the condition is found, the loop will be terminated and the backward search will not be continued
You can use this function to query whether a value exists in the array
var numbers = [1, 2, 3, 4, 5, 6] function checkAvailability(arr, val) { var res = arr.some(function (element, index) { return element == val }) return res } console.log(checkAvailability(numbers, 1))
3.4 finding fruit cases
First, define the data in the array, and then facilitate the rendering of the data in the array to the table. Then, you can query the fruit you want according to the price or name
-
Define array object data
var fruits = [ { id: 001, title: 'Apple', price: 5 }, { id: 001, title: 'Apple', price: 5 }, { id: 002, title: 'Pear', price: 3 }, { id: 003, title: 'Banana', price: 6 }, { id: 004, title: 'Sugar orange', price: 2 } ]
-
Use forEach to traverse the data and render it to the page
var tbody = document.querySelector('tbody') fruits.forEach(function (item) { var tr = ` <tr> <td>${item.id}</td> <td>${item.title}</td> <td>${item.price}</td> </tr>` tbody.insertAdjacentHTML('beforeend',tr) })
-
Filter data by price
Re render the filtered data to the table
function setData(ary) { // Delete the previous data first tbody.innerHTML = '' ary.forEach(function (item) { var tr = ` <tr> <td>${item.id}</td> <td>${item.title}</td> <td>${item.price}</td> </tr>` tbody.insertAdjacentHTML('beforeend', tr) }) } // Filter items by price var btnPrice = document.querySelector('#btnPrice') var min_price = document.querySelector('#min_price') var max_price = document.querySelector('#max_price') btnPrice.addEventListener('click', function () { var result = fruits.filter(function (item) { return item.price >= min_price.value && item.price <= max_price.value }) // Re render data setData(result) })
- Search data by name
// Search by name var btnTitle = document.querySelector('#btnTitle') var title = document.querySelector('#title') btnTitle.addEventListener('click', function () { var result = fruits.filter(function (item) { return item.title == title.value }) // Re render table setData(result) })
In the above array, the fruit name is unique
Using filter will facilitate each object, and then compare, the query efficiency is relatively low
The find method will stop as long as it finds a qualified one, so it is relatively efficient
btnTitle.addEventListener('click', function () { // The find method returns not an array but an object, so to use foreach, you need to // The returned object is placed in the array var result = fruits.find(function (item) { console.log(item) return item.title == title.value }) var arr = [] arr.push(result) // Re render table setData(arr) })
Complete code
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .box { width: 1000px; margin: 50px auto; } table, th, td { border: 1px solid #ccc; } table { width: 800px; border-collapse: collapse; text-align: center; margin-top: 20px; } th, td { padding: 5px 10px; } </style> </head> <body> <div class="box"> <label for="">Price</label> <input type="text" id="min_price"> <span>-</span> <input type="text" id="max_price"> <button id="btnPrice">search</button> <label for="">name</label> <input type="text" id="title"> <button id="btnTitle">search</button> <table> <thead> <tr> <th>number</th> <th>name</th> <th>Price</th> </tr> </thead> <tbody> </tbody> </table> </div> <script> var fruits = [ { id: 001, title: 'Apple', price: 5 }, { id: 002, title: 'Peach', price: 10 }, { id: 003, title: 'Pear', price: 3 }, { id: 004, title: 'Banana', price: 6 }, { id: 005, title: 'Sugar orange', price: 2 } ] // Get tbody var tbody = document.querySelector('tbody') setData(fruits) // Render the data from the array to the table function setData(ary) { // Delete the previous data first tbody.innerHTML = '' ary.forEach(function (item) { var tr = ` <tr> <td>${item.id}</td> <td>${item.title}</td> <td>${item.price}</td> </tr>` tbody.insertAdjacentHTML('beforeend', tr) }) } // Filter items by price var btnPrice = document.querySelector('#btnPrice') var min_price = document.querySelector('#min_price') var max_price = document.querySelector('#max_price') btnPrice.addEventListener('click', function () { var result = fruits.filter(function (item) { return item.price >= min_price.value && item.price <= max_price.value }) // Re render data setData(result) }) // Search by name var btnTitle = document.querySelector('#btnTitle') var title = document.querySelector('#title') btnTitle.addEventListener('click', function () { // The find method returns not an array but an object, so to use foreach, you need to // The returned object is placed in the array var result = fruits.find(function (item) { console.log(item) return item.title == title.value }) var arr = [] arr.push(result) // Re render table setData(arr) }) </script> </body> </html>
3.5 difference between some and forEach
- If the only element in the array is queried, some method is more appropriate. If return true is encountered in some, the traversal is terminated, and the iteration efficiency is higher
- In forEach and filter, return will not terminate the iteration
3.6 trim method removes spaces at both ends of the string
var str = ' hello ' console.log(str.trim()) //hello remove spaces at both ends var str1 = ' he l l o ' console.log(str.trim()) //He l o remove spaces at both ends
3.7 get the attribute name of the object
Object. Keys (object) gets the property name in the current object, and the return value is an array
var obj = { id: 1, pname: 'millet', price: 1999, num: 2000 }; var result = Object.keys(obj) console.log(result)//[id,pname,price,num]
3.8Object.defineProperty
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.defineProperty sets or modifies properties in an object
Object.defineProperty(Object, modified or added property name,{ value:The value of the modified or added property, writable:true/false,//If the value is false, this property value is not allowed to be modified enumerable: false,//enumerable if the value is false, traversal is not allowed configurable: false //Configurableif false, this attribute is not allowed to be deleted. Can the attribute be deleted or can the attribute be modified again })
Using the above method, we can associate the value of the text box with an attribute in the object without adding an event to the text box
var username=document.querySelector('#username') var data = {} Object.defineProperty(data, "title", { get: function () { return username.value }, set: function (newValue) { username.value=newValue }, enumerable: true, configurable: true })