This series is based on teacher Ruan Yifeng’s “JavaScrip Language Introduction tutorial” or “JavaScript Tutorial” recording, the tutorial uses creative Commons signature – the same way sharing 3.0 protocol. This is almost one of the best tutorials for learning JS (it’s not too bad to leave one out)

Ruan Yifeng teacher and the best tutorial using open source way to share, the reason for re-recording again, one is to force yourself to read again carefully to learn again; Second, the knowledge points have their own records, deepen their understanding; Third, thanks for such a good tutorial, I hope more people read and understand

Object-oriented programming

Instance object and the new command

  1. Object Oriented Programming (OOP) abstracts objects, logical operations and complex relationships in the real world into objects. Each Object performs certain functions and is used to receive information, process data or perform operations, publish information, etc. Reuse and function extension can also be achieved through inheritance. It’s better for large projects than traditional procedural programming, which consists of a series of functions or instructions.

  2. What is an object? (1) An object is an abstraction of a single object. (2) An object is a container that encapsulates properties and methods. Properties are the state of the object, and methods are the behavior of the object (to accomplish something).

  3. When generating objects, you usually need a template that represents the common characteristics of a class of objects and then generates from the template. In C++, Java, c#, etc., there is the concept of class. A class is a template for an object, and an object is an instance of a class (a concrete object of a class). JavaScript’s object architecture is based on constructor and prototype chains.

  4. In JavaScript, constructors are templates for objects that describe the basic structure of an instance object. A constructor is a function specifically used to generate instance objects. A constructor that generates multiple instance objects, all of which have the same structure.

  5. Constructors are just like normal functions, but have their own characteristics and uses.

Here, Vehicle is the constructor. Constructor names usually begin with a capital letter (to distinguish them from normal functions).

var Vehicle = function () {
  this.price = 1000;
};
Copy the code

Constructor features:

  • The function body is used internallythisKeyword that represents the object instance to be generated.
  • Must be used when generating objectsnewCommand.
  1. newThe command executes a constructor that returns an instance object.
var Vehicle = function () {
  this.price = 1000;
};

var v = new Vehicle();
v.price / / 1000
Copy the code

If you forget the new command, the constructor is called directly as a normal function

To ensure that the constructor must use the new command, there are two solutions:

You can use strict schemas inside constructors. This will result in an error if called directly without the new command

var Vehicle = function () {
  'use strict';
  this.price = 1000;
};

var v = Vehicle();  // Uncaught TypeError: Cannot set property 'price' of undefined
Copy the code

In strict mode, this inside a function cannot refer to a global object. By default, this equals undefined, resulting in an error without calling new

2. Inside the constructor, determine whether to use the new command, if not, return an instance object based on the argument.

function Vehicle(price) {
  if(! (this instanceof Vehicle)) {
    return new Vehicle(price);
  }

  this.price = price||1000;
};

var v1 = Vehicle();
var v2 = new Vehicle();
Copy the code
  1. usenewCommand, the following functions perform the following steps.
  • Creates an empty object as an instance of the object to be returned.
  • Point the empty object’s prototype to the constructor’sprototypeProperties.
  • Assign the empty object to the this keyword inside the function.
  • Start executing the code inside the constructor.

Inside the constructor, this refers to a newly generated empty object. The purpose of a constructor is to manipulate an empty object (that is, this object) and “construct” it into what it needs to look like.

If the constructor has a return statement inside and the return is followed by an object, the new command returns the object specified by the return statement. Otherwise, this object is returned regardless of the return statement.

var Vehicle = function () {
  this.price = 1000;
  return 1000;  // Ignore non-object return statements
};

(new Vehicle()) === 1000
Copy the code

If return returns another object instead of this, the new command will return the new object

If you use the new command on ordinary functions (functions that do not have the this keyword inside them), an empty object is returned.

function getMessage() {
  return 'this is a message';
}

var msg = new getMessage();
msg / / {}
typeof msg // "object"
Copy the code

The internal process simplified by the new command can be represented in the following code.

function _new(/* Constructor */ constructor, /* Constructor argument */ params) {
  // Convert arguments objects to arrays
  var args = [].slice.call(arguments);
  // Get the constructor
  var constructor = args.shift();
  // Create an empty object that inherits the constructor's Prototype property
  var context = Object.create(constructor.prototype);
  // Execute the constructor
  var result = constructor.apply(context, args);
  If the result is an object, return it directly, otherwise return the context object
  return (typeof result === 'object'&& result ! =null)? result : context; }/ / instance
var actor = _new(Person, 'Joe'.28);
Copy the code
  1. Internal of a functionnew.targetProperties. If the current function is called with the new command,new.targetPoints to the current function, otherwiseundefined.
function f() {
  console.log(new.target === f);
}

f() // false
new f() // true
Copy the code

This property determines whether a function was called with the new command

function f() {
  if (!new.target) {
    throw new Error('Please call with the new command! ');
  }
  // ...
}

f() // Uncaught Error: Please call with new command!
Copy the code
  1. Object.create()Creating instance Objects

Constructors are typically used as templates to generate instance objects. However, if you have only objects without constructors, you can use the object.create () method to generate new instance objects using an Object as a template.

Below, the object Person1 is a template for Person2, which inherits its properties and methods.

var person1 = {
  name: 'Joe'.age: 38.greeting: function() {
    console.log('Hello, I am.' + this.name + '. '); }};var person2 = Object.create(person1);
person2.name;        // "/"
person2.name="Bill"  // "/"
person2.greeting()   // Hello, THIS is Li Si.

person1.greeting()  // Hello, THIS is Zhang SAN.
Copy the code

This keyword

  1. thisThe keyword always returns an object, or points to an object.
  2. thisThat’s the object where the property or method is “currently”. That is, if you change the object of an attribute or method, you can change the reference to this

Assigning an attribute of an object to another object, changing the object on which the attribute belongs, can change the direction of this.

As follows, change this by changing the object on which function f is located

function f() {
  return 'Name:'+ this.name;
}

var A = {
  name: 'Joe'.describe: f
};

var B = {
  name: 'bill'.describe: f
};

f()          // "name:"
A.describe() // "name: Zhang SAN"
B.describe() // "name: Li Si"
Copy the code

Whenever a function is assigned to another variable, the reference to this changes.

  1. In JavaScript, everything is an object. The runtime environment is also an object (in the top-level function, this refers to the Window object). Functions are run in an object, and this is the object (environment) in which the function is run. Also, the reference to this is dynamic

  2. The essence or purpose of this:

The structure of the js object in memory is such that the object exists in the heap, and when assigning an object to a variable, it is actually assigning the object’s memory address in the heap to the variable. As follows, assign the object’s reference to the variable obj

var obj = { foo:  5 };
Copy the code

The process of reading obj. Foo is to get the memory address from obj and then read the original object from that address, returning its foo property

The original object is stored in a dictionary structure, with each attribute name corresponding to an attribute description object. For example, the value of foo is stored in the value property of the property description object:

{
  foo: {
    [[value]]: 5
    [[writable]]: true
    [[enumerable]]: true
    [[configurable]]: true}}Copy the code

When the value of an attribute is a function

var obj = { foo: function () {}};Copy the code

Js stores the function separately in memory, assigning the address of the function to the value property of the foo property.

{
  foo: {[[value]]: address of the function... }}Copy the code

Because functions are separate values, they can be executed in different environments (contexts)

JavaScript allows you to reference other variables in the current environment inside the function body.

As follows, the function body uses a variable x provided by the runtime environment.

var f = function () {
  console.log(x);
};
Copy the code

Since functions can be executed in different runtime environments, a mechanism is needed to get the current runtime context from within the function body. So this is designed to refer, inside the function body, to the environment in which the function is currently running.

As follows, this.x in the function body refers to x of the current running environment.

var f = function () {
  console.log(this.x);
}
Copy the code
  1. thisThe use of
  • Global environment usagethis, refers to the top-level objectwindow.
  • Constructorthis, referring to the instance object.
  • Object method containingthis.thisPoints to the object on which the method is run. That method, assigned to another object, changesthisPointing to.

The direction of this is not easy to grasp, as in the following example

var obj ={
  foo: function () {
    console.log(this); }}; obj.foo()// obj
Copy the code

As above, by calling method foo on the boj object, output this as the current obj object. However, if you use the following form, you will change the direction of this

/ / a
(obj.foo = obj.foo)() // window
/ / 2
(false || obj.foo)() // window
/ / is three
(1, obj.foo)() // window
Copy the code

In the above code, obj.foo is called after it has been retrieved, which is equivalent to a value that is called when the runtime environment has changed from obj to global, and this has changed to window

Inside the JS engine, the obj object and the obj.foo function are stored at two memory addresses, called address one and address two. When obj.foo() is called, address two is called from address one, so address two is run at address one, and this refers to obj. In each of the above cases, the call is made directly from address two, in which case the runtime environment is the global environment, and this refers to the global environment. The above three cases are equivalent to the following code:

/ / a
(obj.foo = function () {
  console.log(this); }) ()/ / is equivalent to
(function () {
  console.log(this); }) ()/ / 2
(false || function () {
  console.log(this); }) ()/ / is three
(1.function () {
  console.log(this); }) ()Copy the code

If the method of this is not in the first layer of the object, this refers to the object of the current layer and does not inherit from the layer above.

var a = {
  p: 'Hello'.b: {
    m: function() {
      console.log(this.p); }}}; a.b.m()// undefined
Copy the code
  1. thisPoints to note in use:
  • To avoid multiplethis. Used forthisPointer to mutable, try not to include multiple layers of this in functions

Use multiple layers of this by adding a variable to this

var o = {
  f1: function() {
    console.log(this);
    var that = this;
    var f2 = function() {
      console.log(that); } (); } } o.f1()// Object
// Object
Copy the code

In strict JavaScript mode, an error is reported if this inside a function refers to a top-level object.

  • Avoid array handling (mapandforeachParameter functions in a methodthis

This in the map/foreach callback refers to the window object. The solution is to fix this with an intermediate variable, or use this as the second argument to the map/foreach methods

// Intermediate variable
var o = {
  v: 'hello'.p: [ 'a1'.'a2'].f: function f() {
    var that = this;
    this.p.forEach(function (item) {
      console.log(that.v+' '+item);
    });
  }
}

o.f()
// hello a1
// hello a2

// The second argument this
var o = {
  v: 'hello'.p: [ 'a1'.'a2'].f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    }, this);
  }
}

o.f()
// hello a1
// hello a2
Copy the code
  • Avoid using it in callback functionsthis(tends to change direction).
  1. thisDynamic switching, not only reflects the flexibility, but also makes programming difficult and fuzzy. Js providescall,apply,bindMethod to switch/fixthisPointing to.
  2. Function.prototype.call():The function instancethecallMethod that you can specify inside a functionthisRefers to the scope in which the function is executed, and then calls the function in the specified scope

As follows, use call to change scope 6

var obj = {};

var f = function () {
  return this;
};

f() === window // true
f.call(obj) === obj // true
Copy the code

The first argument to the call method should be an object. If the arguments are null, null, or undefined, this points to the global object.

var n = 123;
var obj = { n: 456 };

function a() {
  console.log(this.n);
}

a.call() / / 123
a.call(null) / / 123
a.call(undefined) / / 123
a.call(window) / / 123
a.call(obj) / / 456
Copy the code

The first argument to the Call method is a raw value, which is automatically converted to the corresponding wrapper object and passed to the Call method.

var f = function () {
  return this;
};

f.call(5)   // Number {[[PrimitiveValue]]: 5}
Copy the code

In the call method, except for the first argument, which indicates the scope of the calling function, the other arguments are passed as a list of the arguments to which the function is executed

func.call(thisValue, arg1, arg2, ...)
Copy the code

One application of the call method is the native method of calling an object.

var obj = {};
obj.hasOwnProperty('toString') // false

// Override the inherited hasOwnProperty method
obj.hasOwnProperty = function () {
  return true;
};
obj.hasOwnProperty('toString') // true

Object.prototype.hasOwnProperty.call(obj, 'toString') // false
Copy the code
  1. Function.prototype.apply():applyThe function of method is also changethisPoint to, and then call the function. But it takes an array as an argument to the function,
func.apply(thisValue, [arg1, arg2, ...] )Copy the code

As with call, the first argument is the object to which this points. Null or undefined represents a global object. The second argument, an array, represents the arguments passed to the original function

Apply array, call list

Find the largest element in the array

By default, js does not have a function that finds the largest element of an array

var a = [10.2.4.15.9];
Math.max.apply(null, a) / / 15
Copy the code

(2) Change an empty element of the array to undefined

Use the apply and Array constructors to change an empty element of an Array to undefined.

Array.apply(null['a'.'b'])   // [ 'a', undefined, 'b' ]
Copy the code

Loop methods such as forEach skip empty elements, but not undefined

(3) Convert an array-like object

Using the slice method of array objects, you can turn an array-like object (such as the Arguments object) into a real array.

Array.prototype.slice.apply({0: 1.length: 1}) / / [1]
Array.prototype.slice.apply({0: 1}) / / []
Array.prototype.slice.apply({0: 1.length: 2}) / / empty [1]
Array.prototype.slice.apply({length: 1}) / / / empty
Copy the code

(4) The object bound to the callback function

You can modify the this reference in callback functions such as event methods by binding the objects called by the Apply/Call method

var o = new Object(a); o.f =function () {
  console.log(this === o);
}

var f = function (){
  o.f.apply(o);
  / / or O.F.C all (o);
};

// jQuery
$('#button').on('click', f);
Copy the code

Because the apply()/call() methods execute the function immediately while binding to the object on which the function executes, you need to write the binding statement inside a function body.

  1. Function.prototype.bind():bind()Method Take the function inside thethisBind to an object and return a new function.

Here is an example of an assignment that causes the this pointer inside a function to change.

var d = new Date(a); d.getTime()/ / 1596621203097

var print = d.getTime;
print() // Uncaught TypeError: this is not a Date object.
Copy the code

When d. goettime is assigned to print, this inside the method is changed from referring to the Date object instance to the window object. Print () fails.

Using the bind() method to bind the function’s this pointer solves this problem.

var print = d.getTime.bind(d);
undefined
print()   / / 1596621203097
Copy the code

Bind () can take more arguments and bind them to the arguments of the original function.

var add = function (x, y) {
  return x * this.m + y * this.n;
}

var obj = {
  m: 2.n: 2
};

var newAdd = add.bind(obj, 5);
newAdd(5) / / 20
Copy the code

As shown above, the bind() method, in addition to this, also binds add() to its first argument x of 5, and returns a new function, newAdd(), which takes an additional argument y to run.

If the first argument of bind() is null or undefined, this is bound to the global object (window).

  1. bind()Method specific:
  • Return a new function each time

As a result, if you use bind() directly to bind an event, it will bind to an anonymous function, making it impossible to unbind the event

element.addEventListener('click', o.m.bind(o));
// The following cancellations are invalid
element.removeEventListener('click', o.m.bind(o));
Copy the code

Correct way to write:

var listener = o.m.bind(o);
element.addEventListener('click', listener);
/ /...
element.removeEventListener('click', listener);
Copy the code
  • Used in conjunction with callback functions. Treating a method containing this as a callback directly causes the function to change the reference to this during execution, resulting in an error. The solution is to use the bind() method to bind this object to the callback function. Of course, you can also fix this with an intermediate variable

  • Used in conjunction with the call() method. Rewrite the use of some JS native methods

Slice method for the following array

[1.2.3].slice(0.1) / / [1]
/ / is equivalent to
Array.prototype.slice.call([1.2.3].0.1) / / [1]
Copy the code

call()Methods are essentially callsFunction.prototype.call()Methods.

// The above is equivalent to
var slice = Function.prototype.call.bind(Array.prototype.slice);
slice([1.2.3].0.1) / / [1]
Copy the code

Function.prototype.call (array.prototype. slice)

Similarly written:

var push = Function.prototype.call.bind(Array.prototype.push);
var pop = Function.prototype.call.bind(Array.prototype.pop);

var a = [1 ,2 ,3];
push(a, 4)
a // [1, 2, 3, 4]

pop(a)
a / / [1, 2, 3]
Copy the code

Further calls to bind can also be rewritten: call the call method on function.prototype. bind (which returns a new method) with the argument (this object, the bind method argument). The end result is that the bind method is executed on this object and the parameters are passed. (Somewhat devious)

function f() {
  console.log(this.v);
}

var o = { v: 123 };
var bind = Function.prototype.call.bind(Function.prototype.bind);
bind(f, o)() / / 123
Copy the code

Object inheritance

  1. Object inheritance enables code reuse
  2. Traditional JavaScript inheritance is implemented through “prototype objects”. That is, js prototype chain inheritance.ES6 introduces the class syntax to implement class-based inheritance
  3. Disadvantages of constructors: the constructor passes thethisObject property assignment, which makes it easy to define instance object properties. This way, however, attributes cannot be shared between multiple instances of the same constructor.
function Cat(name, color) {
  this.name = name;
  this.color = color;
  this.features = {
    species:'the cat'.habits:'Nocturnal carnivorous animals'
  };
  this.meow = function () {
    console.log('meow meow');
  };
}

var cat1 = new Cat('heavy'.'white');
var cat2 = new Cat('二毛'.'black');

cat1.meow === cat2.meow   // false
cat1.features === cat2.features   // false
Copy the code

Cat1 and cat2 are two instances of the same constructor, and because all MEOW methods and features have the same behavior and attributes for all instances, new methods and attributes should be shared rather than created for each instance, unnecessarily wasting system resources.

Prototype object (prototype) to share attributes between instances.

  1. The JavaScript inheritance mechanism is designed with the idea that all properties and methods of the prototype object can be shared by the instance object
  2. JavaScript states that each function has a Prototype property that points to an object.
function f() {}
typeof f.prototype // "object"
Copy the code

Normal functions rarely use the Prototype attribute

When a constructor generates an instance, the constructor’s Prototype property automatically becomes the prototype of the instance object.

function Cat(name, color) {
  this.name = name;
}
Cat.prototype.color = 'white';
Cat.prototype.features = {
    species:'the cat'.habits:'Nocturnal carnivorous animals'
  };
Cat.prototype.meow = function () {
    console.log('meow meow');
  };
var cat1 = new Cat('heavy');
var cat2 = new Cat('二毛');
Copy the code

Properties of the stereotype object are not properties of the instance object itself. The change is reflected in all instance objects.

When the instance object does not have a property or method itself, it goes to the prototype object to find that property or method. If the instance object has a property or method of its own, the prototype object is no longer searched for that property or method.

The purpose of a stereotype object is to define properties and methods shared by all instance objects. This is why they are called prototype objects. Instance objects can be considered child objects derived from prototype objects.

  1. JavaScript dictates that all objects have their own prototype object. Any object can serve as a prototype for other objects; And since a stereotype object is also an object, it has its own stereotype. This creates a “prototype chain” : object to prototype, prototype to prototype…

  2. All Object prototypes can eventually be traced back to Object.prototype, the Prototype property of the Object constructor. All objects inherit the properties of Object.prototype.

For example, all objects have valueOf and toString methods that are inherited from Object.prototype

The Object. Prototype prototype is null. The end of the prototype chain is NULL

Null has no properties, no methods, and no prototype of its own

Object.getPrototypeOf(Object.prototype)  // null
Copy the code
  1. Now, if an object and its archetype both define a primary property of the same name, we get precedence over looking at things on the object itself, and that’s called Overriding.

  2. The Prototype object has a constructor property, which by default points to the constructor of the Prototype object.

function P() {}
P.prototype.constructor === P // true
Copy the code

The constructor property lets you know which constructor produces an instance object. In addition, the constructor attribute enables you to create another instance from one instance object.

function Constr() {}
var x = new Constr();

var y = new x.constructor();
y instanceof Constr // true
Copy the code

Constructor allows you to call its own constructor in an instance method

Constr.prototype.createCopy = function () {
  return new this.constructor();
};
Copy the code
  1. constructorProperty indicates the relationship between the stereotype object and the constructor. So if you modify the prototype object, you generally need to modify it at the same timeconstructorattribute
function Person(name) {
  this.name = name;
}

Person.prototype.constructor === Person // true

Person.prototype = {
  method: function () {}}; Person.prototype.constructor === Person// false
Person.prototype.constructor === Object // true
Copy the code

When modifying a prototype object, you generally modify it at the same timeconstructorAttribute pointing

// Bad writing
C.prototype = {
  method1: function (.) {... },// ...
};

// Good way to write it
C.prototype = {
  constructor: C,
  method1: function (.) {... },// ...
};

// A better way to write it
C.prototype.method1 = function (.) {... };Copy the code
  1. The name attribute of the constructor property returns the name of the constructor.

  2. Instanceof indicates whether the object is an instanceof a constructor. Instanceof checks to see if the constructor’s prototype on the right is on the prototype chain of the instance on the left.

v instanceof Vehicle
/ / is equivalent to
Vehicle.prototype.isPrototypeOf(v)
Copy the code

Instanceof checks the entire prototype chain, so it is possible to return multiple constructor prototype objects on the prototype chain of the instance object when using instanceof judgment

var d = new Date(a); dinstanceof Date // true
d instanceof Object // true
Copy the code

Any Object (except null) is an instance of Object.

var nullObj=null;
typeof nullObj === 'object' && !(nullObj instanceof Object);  // true
Copy the code

If an object’s prototype is null, instanceof’s judgment is distorted.

Instanceof solves the problem of forgetting to add new when calling the constructor

  1. Constructor inheritance

A subclass inherits its parent class altogether

Call the parent class constructor from the subclass constructor

function Sub(value) {
  Super.call(this); // Inherits the attributes of the parent instance
  this.prop = value;
}

// Or use another way of writing
function Sub() {
  this.base = Super;
  this.base();
}
Copy the code

Make the subclass’s prototype point to the parent class’s prototype, inheriting the parent class’s prototype

Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method = '... ';
Copy the code

Use object.create (super.prototype) to assign to the prototype of a subclass to prevent reference assignments. Subsequent changes affect the prototype of the parent class.

This is the correct or more precise way to write it. A more crude way to write this is to assign an instance of a parent class directly to the prototype of a child class

Sub.prototype = new Super();
Copy the code

This approach inherits the methods of the instance of the parent class in a subclass (which may not normally require instance methods of the parent class) and is not recommended

A single method that inherits from a parent class in a subclass

ClassB.prototype.print = function() {
  ClassA.prototype.print.call(this);
  // self code
}
Copy the code
  1. Multiple inheritance: JavaScript does not provide multiple inheritance, which means that an object cannot inherit multiple objects simultaneously.

However, multiple inheritance can be achieved indirectly by merging the archetypes of two parent classes

function M1() {
  this.hello = 'hello';
}

function M2() {
  this.world = 'world';
}

function S() {
  M1.call(this);
  M2.call(this);
}

/ / M1 inheritance
S.prototype = Object.create(M1.prototype);
// add M2 to the inheritance chain
Object.assign(S.prototype, M2.prototype);

// Specify the constructor
S.prototype.constructor = S;

var s = new S();
s.hello // 'hello'
s.world // 'world'
Copy the code

This subclass S inherits the pattern of both M1 and M2, also known as Mixin

  1. JavaScriptIt’s not a modular programming language,ES6Support for “classes” and “modules”. But you can use objects to achieve the effect of modules
  2. A module is an encapsulation of a set of properties and methods that implement a particular function. So the simplest way to implement a module is to write a module as an object in which all module members reside
  • Write a module as an object
var module1 = new Object({_count : 0.m1 : function (){/ /...},m2 : function (){/ /...}});Copy the code

Functions M1, m2, and attribute _count are encapsulated in the Module1 object. Call the properties of this object directly.

However, this writing exposes all module members, and the internal state can be overwritten externally. For example, overwrite the internal _count value externally: module1._count = 5;

  • Use constructors to encapsulate private variables

As follows, the instance’s private variables are encapsulated by a constructor

function StringBuilder() {
  var buffer = [];

  this.add = function (str) {
     buffer.push(str);
  };

  this.toString = function () {
    return buffer.join(' ');
  };
}
Copy the code

As shown below, the private variable buffer is in the instance object and is not directly accessible externally.

However, this approach encapsulates private variables in constructors, which remain in memory with the instance object and cannot be cleaned up after use. The constructor is used to generate instance objects and to store instance objects’ data, violating the principle of data separation between constructors and instance objects. It also occupies memory.

  • Constructor sets private variables to instance properties
function StringBuilder() {
  this._buffer = [];
}

StringBuilder.prototype = {
  constructor: StringBuilder,
  add: function (str) {
    this._buffer.push(str);
  },
  toString: function () {
    return this._buffer.join(' '); }};Copy the code

This puts the private variable in the instance object. But private variables can still be read and written externally

  • Encapsulate private variables by executing functions immediately

The immediately-Invoked Function Expression (IIFE) returns the method and property of a “closure” and wraps the property and method in a Function scope. The property in the Function is not exposed as a private member.

This is the basic way to write js modules:

var module1 = (function () {var _count = 0;var m1 = function () {/ /...};var m2 = function () {/ /...};return{m1: m1,m2: m2}; }) ();Copy the code
  • Zoom mode of the module

Augmentation can be applied when a module is large and must be divided into several parts, or when one module needs to inherit from another.

Add a new method for module Module1 and return the new module1 module as follows

var module1 = (function (mod){mod. M3 =function () {/ /...};return mod;
})(module1);
Copy the code
  • “Wide zoom mode “(Loose augmentation)

Add an empty object to the argument of the immediately executed function to prevent an error or accident from loading a nonexistent object

var module1 = (function (mod) {/ /...
 returnmod; }) (window.module1 || {});
Copy the code
  • Input to a global variable

The most important thing about modules is “independence”. So in order to call (use) global variables within a module, other variables must be explicitly entered into the module.

For example, if the following module1 uses the jQuery library (module), you can enter it as a parameter for module1. Ensure module independence and show dependencies between modules

var module1 = (function ($) {/ /...
})(jQuery);
Copy the code

Executing functions immediately can also act as namespace-like functions

ObjectObject methods

  1. Object.getPrototypeOfMethod returns the prototype of the parameter object. This is the standard way to get a prototype object.

Several special prototypes:

// The empty Object's prototype is object.prototype
Object.getPrototypeOf({}) === Object.prototype // true

// Object. Prototype is null
Object.getPrototypeOf(Object.prototype) === null // true

// The Function prototype is function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype // true
Copy the code
  1. Object.setPrototypeOfMethod sets the stereotype for the parameter object and returns the parameter object.Object.setPrototypeOf(obj,prototypeObj)

The new command can be emulated using the object. setPrototypeOf method.

var F = function () {
  this.foo = 'bar';
};
var f = new F();

/ / is equivalent to
var f = Object.setPrototypeOf({}, F.prototype);
F.call(f);
Copy the code
  1. Object.createMethod is modeled on an object and returns an instance object. This instance fully inherits the properties of the prototype object.
// Prototype objects
var A = {
  print: function () {
    console.log('hello'); }};// Instance object
var B = Object.create(A);

Object.getPrototypeOf(B) === A // true
B.print() // hello
B.print === A.print // true
Copy the code

The implementation of the object.create method can be replaced with the following code

if (typeof Object.create ! = ='function') {
  Object.create = function (obj) {
    function F() {}
    F.prototype = obj;
    return new F();
  };
}
Copy the code

Generates a new empty object. The following four are equivalent

var obj1 = Object.create({});
var obj2 = Object.create(Object.prototype);
var obj3 = new Object(a);var obj4 = {};
Copy the code

Object. Create takes a null argument to generate an Object that inherits no attributes (no toString and valueOf methods)

var obj = Object.create(null);
Copy the code

The object. create method must specify an Object as an argument, otherwise an error is reported. Object.create creates an Object whose prototype is a reference assignment, that is, a dynamically inherited prototype.

The second argument accepted by the object.create method is the property description Object, whose properties are added to the instance Object’s own properties.

var obj = Object.create({}, {
  p1: {
    value: 123.enumerable: true.configurable: true.writable: true,},p2: {
    value: 'abc'.enumerable: true.configurable: true.writable: true,}});/ / is equivalent to
var obj = Object.create({});
obj.p1 = 123;
obj.p2 = 'abc';
Copy the code

The object.create method generates an Object that inherits the constructor of its prototype Object.

  1. Object.prototype.isPrototypeOf(): of the instance objectisPrototypeOfMethod to determine whether the object is a prototype in the parameter object prototype chain.

Object.prototype is on the prototype chain of all objects except those that inherit directly from NULL.

Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false
Copy the code
  1. about__proto__Properties.__proto__Properties are properties of the instance object that represent the prototype of the instance object (read and write). Instance objects (or non-function objects) cannot passprototypeProperty gets the stereotype (only parameters have itprototypeAttributes), while__proto__Properties should be private by default, should not be read or written, and__proto__Properties need to be deployed only by the browser. Therefore, the correct way to read and write a prototype is to useObject.getPrototypeOf()andObject.setPrototypeOf()

Obj can set the prototype directly with __proto__

  1. about__proto__andprototypeattribute

Here is a comparison of __proto__ and Prototype in constructors, instance objects, and normal objects

/** Constructor __proto__ and prototype **/
var P=function(){}

P.prototype
/ / {constructor: ƒ}

P.__proto__
ƒ () {[native code]}

P.__proto__===P.prototype
// false

P.__proto__===P.constructor.prototype
// true

P.__proto__===Object.getPrototypeOf(P)
// true

P.__proto__===Function.prototype
// true

P.constructor===Function
// true

/** __proto__ and prototype **/ for instance objects 
var p=new P()

p.prototype
// undefined
p.__proto__
/ / {constructor: ƒ}
p.__proto__===Object.getPrototypeOf(p)
// true

p.__proto__===P
// false
p.__proto__===P.prototype
// true

p.constructor===P
// true

/** __proto__ and prototype **/ for instance objects
var obj={}

obj.prototype
// undefined

obj.__proto__===Object.getPrototypeOf(obj)
// true

obj.__proto__===Object.prototype
// true

obj.constructor===Object
// true

var nullObj=Object.create(null)

nullObj.__proto__
// undefined
nullObj
// {} has no attributes
Copy the code

A few conclusions:

  • In JS, the object’s prototype is obtained through the __proto__ attribute, thus forming the prototype chain and the inheritance of the prototype chain.

  • __proto__ is a built-in attribute of an object. All objects have a __proto__ attribute except for null and objects whose prototype object is null. Functions are objects, so functions also have a __proto__ attribute

  • Prototype properties are function-specific. Each function has a Prototype property object that shares properties and methods between instance objects. So prototype is only used in constructors, representing the prototype object of the instance object. Inheritance in object orientation is thus implemented.

  • The __proto__ property refers to the prototype object of the current object, the prototype property of the constructor.

  • The constructor property represents the current object’s constructor

  • Functions are also objects and therefore also have a __proto__ attribute that points to the prototype attribute of the current function’s constructor. A Function’s constructor is Function and __proto__ is function.prototype

  1. __proto__Property refers to the prototype object of the current object, that is, the constructorprototypeProperties.
var obj = new Object(a); obj.__proto__ ===Object.prototype
// true
obj.__proto__ === obj.constructor.prototype
// true
Copy the code
  1. Get an objectobjObject, there are three ways:
  • obj.__proto__
  • obj.constructor.prototype
  • Object.getPrototypeOf(obj)

But the __proto__ attribute needs to be deployed only in the browser environment. Obj. Constructor. The prototype in manual change the prototype object, may fail

After changing the prototype object of the constructor C to P, see below. The instance object c.constructor. Prototype does not point to p. Object.getprototypeof (obj) Correctly obtaining prototype objects is the recommended method for obtaining prototype objects

var P = function () {};
var p = new P();

var C = function () {};
C.prototype = p;
var c = new C();

c.constructor.prototype === p // false

c.constructor.prototype === P.prototype   // true

Object.getPrototypeOf(c) === p  // true
Copy the code

The above method of changing the prototype object is incorrect. When modifying prototype, you usually set the constructor property as well.

C.prototype = p;
C.prototype.constructor = C;

var c = new C();
c.constructor.prototype === p // true
Copy the code
  1. Object. GetOwnPropertyNames () returns the attributes of the Object itself all keys array (including traversal and not traverse all of the attributes).

  2. Keys returns an array of all traversable property names of the Object itself

  3. Object. The prototype. The hasOwnProperty () returns whether an attribute is the attribute of Object itself

The hasOwnProperty method is the only JavaScript method that does not iterate through the prototype chain when processing object properties

  1. inThe operator indicates whether an object has a property. That is, to check whether an attribute exists.
'length' in Date // true
'toString' in Date // true
Copy the code

for… The in loop retrieves all traversable properties of an object (both its own and inherited properties)

Generally, the following method is used to traverse the properties of the object itself

for ( var name in object ) {
  if ( object.hasOwnProperty(name) ) {
    /* loop code */}}Copy the code
  1. Gets all attributes of an object (including self and inherited, enumerable and non-enumerable attributes)
function inheritedPropertyNames(obj) {
  var props = {};
  while(obj) {
    Object.getOwnPropertyNames(obj).forEach(function(p) {
      props[p] = true;
    });
    obj = Object.getPrototypeOf(obj);
  }
  return Object.getOwnPropertyNames(props);
}
Copy the code
  1. Object copy

To copy an object, do the following:

  • Make sure that the copied object has the same prototype as the original object.
  • Make sure that the copied object has the same instance properties as the original object.

The following is the implementation of object copy:

function copyObject(orig) {
  var copy = Object.create(Object.getPrototypeOf(orig));
  copyOwnPropertiesFrom(copy, orig);
  return copy;
}

function copyOwnPropertiesFrom(target, source) {
  Object
    .getOwnPropertyNames(source)
    .forEach(function (propKey) {
      var desc = Object.getOwnPropertyDescriptor(source, propKey);
      Object.defineProperty(target, propKey, desc);
    });
  return target;
}
Copy the code

Using ES2017 introduced Object. GetOwnPropertyDescriptors can be more easy to achieve

function copyObject(orig) {
  return Object.create(
    Object.getPrototypeOf(orig),
    Object.getOwnPropertyDescriptors(orig)
  );
}
Copy the code

Strict mode (strict mode)

  1. JavaScript provides a second mode of code execution: strict mode. Strict mode was introduced from ES5 with the main purpose of:
  • Explicitly prohibit some unreasonable, not strict syntax, reduce the JavaScript language some weird behavior.
  • Add more error reporting occasions, eliminate some unsafe code operation, ensure the safety of code operation.
  • Improve compiler efficiency and speed.
  • Set the stage for future versions of JavaScript syntax.
  1. Enable strict mode: Add a line to the code header'use strict';Can. Older engines ignored it as a normal string. The new version of the engine goes into strict mode.
  2. use strictPlaced in the first line of the script file, the entire script will run in strict mode. Not in the first row is invalid.
  3. use strictPlaced on the first line of the function body, the entire function runs in strict mode.
  4. Sometimes you need to combine different script files into one file. At this point, if one is in strict mode and the other is not, the combined result will be incorrect. The solution is to put the entire script file in an anonymous function that executes immediately:
(function () {
  'use strict';
  // some code here}) ();Copy the code
  1. Explicit error reporting in strict mode

In strict mode, JS syntax is more strict, and many error codes that would not be reported in normal mode will be reported explicitly

The following operations will generate an error in strict mode:

  • Read-only attributes are not writable; For example, the length property of a string

  • Non-configurable attributes cannot be deleted (non-configurable)

  • Only properties of the valuer are set to be unwritable

  • Objects that cannot be extended are not extensible

  • Eval and arguments cannot be used as identifier names

In normal mode, arguments[I] can be used to read functions that have multiple arguments with the same name. Strict mode is a syntax error.

  • Functions cannot have arguments with the same name

  • Disallow octal prefix 0 representation. Octal is represented by the digit 0 and the letter O

  1. Security restrictions in strict mode
  • Global variables are explicitly declared
  • banthisThe keyword points to a global object. Avoid inadvertently creating global variables
// Normal mode
function f() {
  console.log(this= = =window);
}
f() // true

// Strict mode
function f() {
  'use strict';
  console.log(this= = =undefined);
}
f() // true
Copy the code

In strict mode, when a function is called directly, the internal this means undefined, so you can use call, apply, and bind to attach any value to this. In normal mode, this refers to a global object. If the bound value is not an object, it is automatically converted to an object and bound to it. Null and undefined, which cannot be converted to an object, are ignored.

  • Internal functions such as fn.callee and fn.caller are prohibited

  • Arguments. callee, arguments.caller is prohibited

Arguments. callee and arguments.caller are two historical variables that were never standardized and have now been eliminated

  • Do not delete variables. Use in strict modedeleteCommand to delete a variable, an error is reported. Only the properties of the object, and the properties describe the properties of the objectconfigurableProperty set totrueTo bedeleteCommand to delete.
  1. Static binding
  • Disallow the with statement

  • Create the eval scope

In normal mode, the JavaScript language has two types of variable scope: global scope and function scope. The strict pattern creates a third scope: the eval scope.

Variables generated by eval can only be used inside eval.

(function () {
  'use strict';
  var x = 2;
  console.log(eval('var x = 5; x')) / / 5
  console.log(x) / / 2}) ()Copy the code

The eval statement uses strict patterns:

/ / way
function f1(str){
  'use strict';
  return eval(str);
}
f1('undeclared_variable = 1'); / / an error

2 / / way
function f2(str){
  return eval(str);
}
f2('"use strict"; undeclared_variable = 1')  / / an error
Copy the code
  • argumentsParameter changes are no longer tracked. Parameter modification in strict mode,argumentsNo longer linkage follows change
  1. orientedECMAScript 6
  • ES5’s strict mode only allows functions to be declared in global scope or function scope.
  • Reserved words. Some reserved words have been added to strict mode:implements,interface,let,package,private,protected,public,static,yieldEtc.