javascript:void($=o),javascript void o

Hello everyone, the editor will answer the question of javascript:void($=o). Many people still don’t know javascript void o, let’s take a look at it now!

JavaScript object-oriented (ES5 article)
  • 1. JavaScript object-oriented
    • 1. Several ways to create objects in JavaScript
      • 1. 1. Constructor pattern
      • 1. 2. Factory mode
      • 1. 3. Prototype mode
      • 1. 4. Combined use of constructor pattern and prototype pattern
      • 1. 5. Dynamic prototype mode
      • 1. 6. Parasitic constructor pattern
      • 1. 7. Safe constructor pattern
    • 2. Encapsulation and inheritance
      • 2.1. Packaging
      • 2.2. Inheritance
        • 2.1.1. Prototypal inheritance
        • 2.1.2. Constructor inheritance
        • 2.1.3. Combined inheritance
        • 2.1.4. Prototypal inheritance
        • 2.1.5. Parasitic inheritance
        • 2.1.6. Parasitic combined inheritance
        • 2.1.7. Inheritance implemented in Prototye.js
    • 3. Polymorphism
      • 3.1. Reloading
      • 3.2. Rewrite
      • 3.3. Polymorphism
    • 4. Static properties and methods
      • 4.1. Static attributes
      • 4.2. Static methods

1. JavaScript object-oriented

Object Oriented Programming is a programming idea. However, there is no concept of classes in JavaScript. Instead, objects are directly used to achieve Deepl weight reduction in programming.

1. Several ways to create objects in JavaScript

1. 1. Constructor pattern

The constructor pattern creates different objects by passing different parameters to the constructor and then calling the constructor.

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.say = function (something) {
        console.log(something);
    };
}
var person1 = new Person("Xiaojia",29,"Senior Java Development Engineer");
person1.say('Humble Weijia Online Reconstruction');

The advantage of using the constructor pattern to create different objects is that it can be identified as a specific type.

For example, use instanceof to detect objects

person1 instanceof Person // true
person1 instanceof Object // true

The disadvantage of using the constructor is that each method will be recreated on each instance object. Even if the method with the same name or two methods have the same effect, the methods with the same name on different instance objects are actually different, which causes A redundancy.

person1.sayname != person2.sayname
1. 2. Factory mode

The final pattern uses functions to encapsulate the details of creating objects, creating objects in functions and returning objects.

function createPerson(name, age, job){
    var person = new Object();
    person.name = name;
    person.age = age;
    person.job = job;
    person.sayName = function(){
        alert(this.name);
    };
    return person;
}
var person1 = createPerson("Xiaojia",29,"Senior Java Development Engineer");
person1.sayName();

But the factory pattern has a disadvantage, which is the object recognition problem, that is, it does not know what type of object it is.

1. 3. Prototype mode

The advantage of using a prototype object is that all object instances can share the properties and methods it contains.

If the constructor does not return a value, it will return a new object instance by default.

function Person() {}
Person.propertype.name = "Xiaojia";
Person.propertype.age = "Xiaojia";
Person.propertype.job = "Senior Java Development Engineer";
Person.prototype.sayName = function(){
        alert(this.name);
};
var person1 = new Person();
var person2 = new Person();

In this way, all properties and methods are shared by all instances, that is to say, the sayname of person1 and the sayname of person2 are the same.
When the prototype is filled, the connection between the existing prototype and any previously existing object instances is severed. They originally referenced the prototype, and the connection can be established by adding a constuctor to the prototype again.

The problem with the prototype pattern is the problem of sharing. If you change it on an instance or prototype, it will change accordingly in other instances. In this way we introduce the combined use of constructor pattern and prototype pattern.

1. 4. Use constructor pattern and prototype pattern in combination

When used in combination, the constructor pattern is used to define the properties of the instance itself, and the prototype pattern is used to define methods and shared properties.

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype = {
    constructor: Person,
    sayname: function(){
        alert(this.name);
    }
}
var person1 = new Person("Xiaojia",29,"Senior Java Development Engineer");
person1.sayname();
1. 5. Dynamic prototype mode

The above combination of constructor and prototype often confuses people, so dynamic prototype encapsulates all information into the constructor, and by initializing the prototype in the constructor, it maintains the same integrity. Both constructor and prototype patterns are used.

That is, we can decide whether we need to initialize the prototype by checking whether a method that should exist exists.

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;

if (typeof this.sayName !== "function"){
Person.prototype.sayName = function () {
alert(this.name);
}
}
\t
}
var person1 = new Person("Xiaojia",29,"Senior Java Development Engineer");
person1.sayName();

Only when sayName() does not exist and when the constructor is called for the first time, the code inside will be executed.

It should be noted that when using the dynamic prototype mode, you cannot use object literals to override the prototype.

1. 6. Parasitic constructor pattern

The parasitic constructor pattern is very similar to the factory pattern

function Person(name, age, job){
    var person = new Object();
    person.name = name;
    person.age = age;
    person.job = job;
    person.sayName = function(){
        alert(this.name);
    };
    return person;
}
var person1 = new Person("Xiaojia",29,"Senior Java Development Engineer");
person1.sayName();

The difference between the parasitic constructor pattern and the factory pattern is that

  • The parasitic constructor pattern uses the new keyword when creating an object, while the factory pattern does not use the new keyword.
  • The external wrapper function in parasitic mode is a constructor;

Function: The parasitic mode can create a constructor for an object under special circumstances. The reason is that we can overwrite the value of the object through the constructor and return the object instance after overwriting the call to the constructor (an instance of the created object) through return. the new value.

Example: We need a special number of additional methods, but we cannot modify the Array constructor directly, we can use the parasitic construction pattern.

function SpecialArray() {
    //Create array
    var array=new Array();
    //Add value arguments obtain actual parameters, not formal parameters, so SpecialArray() does not have formal parameters to receive the passed parameters.
    array.push.apply(array,arguments);
    array.toPipedString=function(){
        return this.join("|");
    }
    return array;
}
var colors=new SpecialArray("red","blue","black");
console.log(colors.toPipedString()); //Output: red|blue|black
1. 7. Safe constructor pattern

The concept of a safe object was proposed by Douglas Crockford. A so-called safe object refers to an object that has no public properties and other methods do not reference this. Stable objects are best suited for use in secure environments (where new and this are prohibited) or to prevent data from being modified by other applications.

The safe constructor pattern is similar to the parasitic constructor pattern, with the following differences.

  • The safe constructor pattern does not use the new operator to call the constructor;
  • Instance methods of newly created objects do not reference this;
function Person (name, age, job) {
    var person=new Object();
    person.name = name;
    person.age = age;
    person.job = job;
    person.sayName = function() {
        alert(name);
    }
    //return object
    return person;
}
var person = Person("Zhang San",22);
person.sayName(); //Using the safe constructor mode, you can only obtain the attribute values in it through the methods inside the constructor.
console.log(person.name);// undefined

2. Encapsulation and inheritance

2.1, Encapsulation

Encapsulation can encapsulate an entity’s information, functions, and responses into a single object.

From the above stable objects, we can only use methods to obtain properties, which is also a form of encapsulation.

Since JavaScript does not have keywords such as public, private, and protected, you can use the scope of variables to simulate the public and private encapsulation features.

function Person (name, age, job) {
var _name = name;
var _age = age;
var _job = job;
return {
getName: function () {
return _name;
},
getAge: function () {
return _age;
},
getJob: function () {
return _job;
}
}
}
var person = Person("Xiaojia", 29, "Senior Java Development Engineer");
console.log(person.name); //undefine;
console.log(person.getName());

The above are simply implementation methods.

2.2. Inheritance

By expanding without changing the source program, the original functions are preserved, and the word program is expanded to avoid repeated code rewriting.

2.1.1, Prototypal inheritance

Prototypal inheritance uses the prototype chain to implement inheritance. Things to note: When implementing prototypal inheritance, do not use object literals to create prototype methods, because doing so will rewrite the prototype chain.

// Parent class definition
function SuperClass() {
    this.supername = 'super';
}

SuperType.prototype.getSuperName= function(){
    return this.supername;
}

// Subclass definition
function SubClass () {
    this.subname='subname';
}

// prototypal inheritance
SubClass.prototype = new SuperClass();

SubClass.prototype.getSubName = function (){
    return this.subname;
}

var subclass = new SubClass();
console.log(subclass.getSubName());
console.log(subclass.getSuperName());

Advantages: Properties and methods defined by the prototype can be reused.
shortcoming:

  • Prototype properties of reference types are shared by all instances;
  • When creating a child object, parameters cannot be passed to the constructor of the parent object;
2.1.2. Constructor inheritance

Use the call method of the parent class constructor to implement constructor inheritance.

function SuperClass () {
    this.colors = ['red', 'green'];
}
function SubClass () {
    //Inherit SuperType
    SuperType.call(this);
}

var subclass1 = new SubClass();
subclass1.colors.push('blue');
console.log(subclass1.colors);
// red, green, blue

var subclass2 = new SubClass();
console.log(subclass2.colors);
// red, green

It should be noted that after calling the constructor of the parent object, define properties for the subtype, otherwise they will be overridden.

Disadvantages: Methods need to be defined in the constructor, making it difficult to reuse functions. Moreover, methods defined on the prototype of the parent object are not visible to subtypes.

2.1.3. Combined inheritance

Combined inheritance, as the name suggests, is to combine two modes to realize JavaScript inheritance, with the help of prototype chain and constructor. In this way, defining methods on the prototype realizes the reuse of functions, and ensures that each instance has its own attributes.

function SuperClass (name) {
    this.name = name;
    this.con = [];
}

SuperClass.prototype.getName = function() {
    return this.name;
}

function SubClass (name, age) {
    SuperClass.call(this, name);
    this.age = age;
}

SubClass.prototype = new SuperClass();
SubClass.prototype.constructor = SubClass;
SubClass.prototype.getAge = function() {
    return this.age;
};

var subclass1 = new SubClass('li', 18);
subclass1.con.push('test1');
console.log(subclass1.con); // test1
console.log(subclass1.getAge()); // 18
console.log(subclass1.getName()); // li

var subclass2 = new SubClass('hang', 18);
console.log(subclass2.con); // test1
console.log(subclass2.getAge()); // 18
console.log(subclass2.getName()); // hang
  • Advantages: Makes up for the shortcomings of prototypal inheritance and constructors;
  • Disadvantages: The parent class constructor is called twice;
2.1.4, Prototypal inheritance

Prototypal inheritance does not have a constructor in the strict sense. With the help of prototypes, new objects can be created based on existing objects.

function createObject(obj) {
    function newOrient () {};
    newOrient.prototype = obj;
    return new newOrient();
}

For the above function, a forward copy is performed on the passed in object. There is a new method in ES5, Object.create, which functions the same as the above function, but only supports IE9 and above.

var Person = {
    name: 'Xiaojia',
    age: 29
}
var Student = Object.create(Person);
Student.name= 'Humble Little Jia';
Student.job = 'Senior Java Development Engineer';
console.log(Student.job);

Object.create also supports passing in the second parameter. The parameter has the same format as the Object.defineProperties() method and will overwrite the property of the same name on the prototype.

2.1.5, Parasitic inheritance

Parasitic inheritance is very similar to prototypal inheritance. The difference is that parasitic inheritance creates a function that does everything, such as adding properties and methods to new objects.

function createWorker(obj) {
    var clone = Object.create(o);
    clone.job = 'Senior Java Development Engineer';
    return clone;
}
var Person = {
    name: 'Xiaojia',
    age: 29
}
var worker = createWorker(person);
console.log(worker.job);
2.1.6, Parasitic combined inheritance

Combined inheritance calls the constructor of the object’s parent object twice, and there are two sets of properties of the parent type, one on the instance and one on the prototype of subClass. The solution to this problem is parasitic combinatorial inheritance.

function inheritPrototype(SubClass, SuperClass){
    //Inherit the prototype of the parent class
    var prototype = Object.create(SuperClass.prototype);
    // Rewrite the tainted construct
    prototype.constructor = SubClass;
    // Override the prototype of the subclass
    SubClass.prototype = prototype;
}

function SuperClass(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperClass.prototype.sayName = function(){
    alert(this.name);
};

function SubClass(name, age) {
    SuperClass.call(this, name);
    this.age = age;
}

inheritPrototype(SubClass, SuperClass);

SubClass.prototype.sayAge = function(){
    alert(this.age);
};


var subclass = new SubClass('hello', 18);
console.log(subclass.__proto__.constructor == SubClass)

can be seen

  • Subclasses can inherit the properties and methods of the parent class, and the properties are not created on the prototype chain, so multiple subclasses will not share a property;
  • Subclasses can dynamically pass parameters to parent classes;
  • The parent class constructor is only executed once;

If a subclass adds a method to the prototype, it must be added after inheritance, otherwise it will overwrite the method on the prototype, but this will not work if the two classes are already existing classes.

solution:

function inheritPrototype(SubClass, SuperClass){
    //Inherit the prototype of the parent class
    var prototype = Object.create(SuperClass.prototype);
    // Rewrite the tainted construct
    prototype.constructor = SubClass;
    // Override the prototype of the subclass
    SubClass.prototype = Object.assign(prototype, SubClass.prototype);
}

Although copying through Object.assign solves the problem of overriding methods of prototype types, Object.assign can only copy enumerable methods. If the subclass itself inherits a class, this method will not work.

2.1.7, inheritance implemented in Prototye.js

Prototye.js implements inheritance in JavaScript by extending the two static methods Object.extend(destination, source) to the Object object. From a semantic perspective, it actually only implements a holographic copy of the source object to the target object. The essence of this method is similar to JQuery’s $.extend() and underscore library _.extend() functions.

But you can also think of it this way: Since the target object has all the characteristics of the source object, it looks like the target object inherits (and extends) the source object.

Object.extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property]; //Using the characteristics of dynamic languages, dynamically add properties and methods through assignment.
}
return destination;
}

3. Polymorphism

3.1, reloading

Overloading is a manifestation of polymorphism. Overloading is multiple implementations of a method with the same name, which are distinguished and identified by the type and number of parameters. However, in js, the parameters of a function have no type, and the number of parameters is arbitrary.

We can use arguments object to implement variable parameters.

function add(){
 var sum = 0;
 for(var i=0; i<arguments.length; i + + ) {
  if(typeof arguments[i] === 'number') {
   sum + = arguments[i];
  }
 }
 return sum;
}

Example overloading

function overridable() {
  return {
    functions: [],

    add: function(fn) {
      if (typeof fn !== 'function') { return false; }

      const functionLength = fn.length;
      this.functions[functionLength] = fn;

      return {
        functions: this.functions,
        add: this.add,
        result: this.result,
      }
    },

    result: function() {
      const functions = this.functions;

      return function() {
        const functionLength = arguments.length;

        if (functions[functionLength]) {
          return functions[functionLength].call(this, ...arguments);
        } else {
          throw new Error('There is no function match ' + functionLength + ' arguments.');
        }
      };
    },
  };
};

const foo = overridable()
  .add(function(a, b, c) {
    return a + b + c;
  })
  .add(function(a) {
    return Math.pow(a, 2);
  })
  .result();

console.log(foo(1, 2, 3)); // 6
console.log(foo(2)); // 4

The above code is strictly tested and should not be used in a real production environment.

3.2, Rewriting

When judging the reference type, we usually do not want to use the toString method directly. We should use the Object.prototype.toString.call method to judge.

It is precisely because some classes (such as Array) will override the toString method to facilitate programmers to get the desired string instead of the boring [object Object].

The rewriting mechanism of JavaScript is very convenient. In single-page applications, we usually use window.history.pushState to manage front-end routing. Unfortunately, this method does not trigger any events. But we can still use rewriting to implement monitoring during route transformation:

window.history.pushState = function(state, title) {
var pushStateEvent = new Event('pushstate');
window.dispatchEvent(pushStateEvent);
}

window.addEventLisnter('pushstate', function(){
console.log('push state!!');
});

history.pushState('/test', 'test');
3.3, Polymorphism

JavaScript itself does not support polymorphism, but we can implement polymorphism. The idea of polymorphism is actually to separate “what you want to do” and “who does it”. The most fundamental function of polymorphism is to eliminate these conditional branches by converting procedural conditional branch statements into object polymorphism. statement.

Example: Using conditional branching

var googleMap = {
    show: function () {
        console.log('Start rendering Google Maps');
    }
};
varbaiduMap = {
    show: function () {
        console.log('Start rendering Baidu map');
    }
};
var renderMap = function (type) {
    if (type === 'google') {
        googleMap.show();
    } else if (type === 'baidu') {
        baiduMap.show();
    }
};
renderMap('google'); // Output: Start rendering Google Maps
renderMap( 'baidu' ); // Output: Start rendering Baidu map

Although the renderMap function maintains a certain degree of flexibility, this flexibility is very fragile. Once it needs to be replaced with another interface, renderMap will undoubtedly need to be modified.
We can maintain object polymorphism by using inheritance.

var renderMap = function( map ){
    if (map.show instanceof Function){
        map.show(); }
};
renderMap( googleMap ); // Output: Start rendering Google Maps
renderMap( bdMap ); // Output: Start rendering Baidu map

4. Static properties and methods

Methods and properties defined directly on the constructor are static properties, while methods and properties defined on the prototype and instance of the constructor are non-static.

4.1. Static attributes
function ClassA(){ //Define the constructor
   this.name=1;
};
ClassA.funcName='classA'

var instance = new ClassA();
instance.funcName; // undefined
instance.name; // 1
ClassA.funcName; //'classA'
4.2, static method
function ClassA(){ //Define the constructor
};
ClassA.func = function(){ //Add an attribute on the constructor (because functions are also objects)
    console.log("This is a static method");
}
var instance = new ClassA(); //Create a new instance
ClassA.func(); //This is a static method
instance.func(); //Error: instance.func is not a function