1. Data attributes

The data properties of an object can be different, signals, and signals, and Enumerable, or Writable, or Value

1.1 Configurable

This property is configurable. The default value is true. When set to false, it is immutable, cannot be deleted, and cannot be reset to true. Setting new values is ignored. Errors will be reported in strict mode and may run differently in node and browser environments. Such as:

var person = {}

Object.defineProperty(person, 'name', {
    configurable: false.    value: "Nicholas"
}) console.log(person.name) // Nicholas Object.defineProperty(person, 'hah', {  configurable: false. value: "222" }) person.name = 'Nicholas Cho.'  console.log(person.name) // Nicholas  delete person.hah console.log(person.hah) / / 222  console.log(person) {name: 'Nicholas', 'hah': 222} Copy the code

1.2 Enumerable

Controls whether a property can be enumerated. The default is true. When set to false, it will not be enumerated for… in… Out of the

var person = {}
Object.defineProperty(person, 'text', {
    enumerable: false.    value: "222"
})
 for (let key in person) {  console.log(key) // Failed to print text }  person.text = '111' // The modification is also invalid  Copy the code

1.3 writable

Explanation: Controls whether an attribute value can be modified

1.4 the value

Explanation: attribute value

2. Accessor properties

2.1 the get

A get is triggered every time an object property is accessed

2.2 the set

Description: A set is triggered whenever an object property is set

var person = {}
Object.defineProperty(person, 'txt', {
    get: function () {
        console.log('I took the TXT')
    },
 set: function () {  console.log('I set it.')  } })  console.log(person.txt) person.txt = 1 Copy the code

The Vue2 version also makes use of accessor properties, which will be briefly described later.

3. Create an object

3.1. Object literals

var a = {}

Copy the code

3.2. The new method


var b = new Object(a)Copy the code

3.3. Factory functions

Since ES6 did not have the concept of a class before, it is possible to use a function to simulate a class that creates objects with consistent properties:

function createObj (name, age) {
    var o = new Object(a)    o.name= name
    o.age = age
    o.sayName = function () {
 console.log(this.name)  }   return o }  var a = createObj('xx'.12) var b = createObj('xx'.13)  Advantages: Can be customized,Disadvantages: Methods cannot be reused and are not traceable (cannot find the specific constructor i.einstanceofUndetectable)Copy the code

3.4. The constructor creates the object

function CreateObj (name, age) {
    this.name= name
    this.age = age
    this.sayName = function () {
        console.log(this.name)
 } }  var a = new CreateObj('xx'.12) var b = new CreateObj('xx'.13)  a.constructor === b.constructor === CreateObj // true  Disadvantages: Methods are private. The same method needs to be created for each object, wasting memoryAdvantages: custom, flexible pass parameters Copy the code

The process of new did four things:

(1) Create a new object

(2) Assign the scope of the constructor to the new object (thus this refers to the new object)

(3) Execute the code in the constructor (add properties to the new object)

(4) Return the new object

3.5. Prototype creation

Create through the prototype chain

function CreateObj () {
}
CreateObj.prototype.name = 'zhangsan'

var a = new CreateObj()
 Advantages: The shared method saves memoryDisadvantages: Cannot pass parameterCopy the code

3.6. Combining constructors

Summarizing the above problems, it is not difficult to find the shortcomings are not flexible enough, or cannot share the method; Knowing the weaknesses, we can use a combination of prototypes and constructors to solve these weaknesses;

function CreateObj (name, age) {
    this.name = name
    this.age = age
}
CreateObj.prototype = {
 constructor: CreateObj,  sayName: function () {  console.log(this.name)  } } Copy the code

4. The prototype chain

Many old drivers who have been learning for many years can’t say the prototype chain. In fact, they can only sum up some in a few words. 1. Constructors have a prototype object = obj.prototype

__proto__, instance.proto === aj.prototype

3. Prototype objects have Pointers that always point to constructor

4. Make a stereotype point to an instance of a constructor. This stereotype produces an example pointer to a superclass stereotype:


function Create() {

}

function a() {} var obj = new Create()  __proto__ === obj. Prototype obj.__proto__ === Create.prototype  // Prototype objects have Pointers that always point to constructor Create.prototype.constructor === Create // Make a stereotype point to an instance of the constructor. This stereotype produces a pointer to the superclass stereotype  a.protoType = new Create()  a.protoType.__proto__ === Create.prototype  Create.prototype.__proto__ === Object.prototype  Object.prototype.__proto__ === null  a => Create= > Object= > null  A chain is formed through the prototype Copy the code

5. Inheritance

5.1. Prototype inheritance

Refer to the previous section on the prototype chain disadvantages: It does not solve the problem of reference types, reference types are shared

5.2. Constructor inheritance

Because of the problem of prototype chain inheritance, some people have adopted constructor inheritance. The idea of constructor inheritance is to change the point to this in a subclass by calling or applying. Thus inheriting the method of the constructor.

function father (name) {
    this.name = name
    this.methods = ['get'.'post']
}

function son () {  father.call(this) }  var xiaoming = new son('xiaoming')  Copy the code

Advantages: Solves the problem of passing parameters and reference types disadvantages: reduces function reuse

5.3. Composite inheritance

The idea is to use constructors, customize private properties, and use prototypes to share properties that need to be reused.

function father (name) {
    this.name = name
    this.methods = ['get'.'post']
}

function son (name) {  father.call(this, name) } son.prototype.sayName = function () {  console.log(this.name) } var xiaoming = new son('xiaoming') var xiaoming2 = new son('xiaoming2')  xiaoming.sayName === xiaoming2.sayName // true Copy the code

Advantages: Combines the advantages of the first and second

5.4. Original type inheritance

The foundation of the original type inheritance is that you need an underlying Object to pass in, using object.create to create a new Object. Such as:

var person = {
    name: 'xiaoming'.    age: 18
}

var xiaoming = Object.create(person) var xiaoming2 = Object.create(person)  Copy the code

The essence is actually prototype chain inheritance:

var person = {
    name: 'xiaoming'.    age: 18
}
function CreateObj (o) {
 function F() {}  F.prototype = o  return new F() }  var xiaoming = CreateObj(person) var xiaoming2 = CreateObj(person) Copy the code

5.5. Parasitic inheritance

Parasitic inheritance is enhanced on the basis of the original type, the principle is also very simple. 2. Create a new object 3 based on the base object. New object addition method

var person = {
    name: 'xiaoming'.    age: 18
}
function Clone (person) {
 var a = Object.create(person)  a.sayName = function () {  console.log(this.name)  }  return a }  var xiaoming = new Clone(person) var xiaoming2 = new Clone(person) Copy the code

5.6. Parasitic composite inheritance

After looking at the previous approaches, I feel that composite inheritance is the best, which can be shared and treated differently. However, if we analyze it carefully, there will be problems, as shown in the following example 🌰 :


function sub(name) {
    this.name = name
}

function sup(name, age) {  sub.call(this, name) / / the second time  this.age = age }  sup.prototype = new sub() / / for the first time sup.prototype.constructor = sup sup.prototype.sayName = function () {  console.log(this.age) } var instance = new sup('xm'.23)  Copy the code

The sub function is called twice, so the name variable will exist on both prototype and instance

Parasitic combinatorial inheritance, in which properties are inherited by borrowing constructors, and methods are inherited by a blend of prototype chains, solves this problem precisely. The basic idea behind this is that instead of calling a supertype constructor to specify a subtype stereotype, all we need is a copy of the supertype stereotype. In essence, you use parasitic inheritance to inherit the stereotype of the supertype and then assign the result to the stereotype of the subtype.

function sub(name) {
    this.name = name
}

function sup(name, age) {
 sub.call(this, name)  this.age = age } function inherit(sup, sub) {  var o = Object.create(sup.prototype)  sub.prototype = o  o.constructor = sub }  var instance = new sup('xm'.23) Copy the code

At this time, there is no name attribute on sup’s prototype, perfect.

5.7. The class inheritance

Grammar sugar added to ES

function A(name) {
    this.name = name
}

class B extends A {
 constructor(name, age) {  super(name)  this.age = age  } } Copy the code

6. Some apis for objects

6.1 the Object. The assign

Merges one or more objects into the target object. It’s a shallow copy.

Object.assign(target, obj1, obj2....)
Copy the code

When multiple object attribute names overlap. The back one will override the front one.

Object.keys/values

Gets all the keys and values of an object

Object.entries/fromEntries

Entries: Returns an array whose elements are the reverse of fromEntries: Entries, a one-to-one array containing objects key and value

Object.freeze

The object is frozen. Properties are not allowed to be modified. IsFrozen can be used for detection. When working on a Vue project, you can freeze objects that will not be modified. The object will no longer be listened to, improving performance.

Object.defineProperty

It can be used to define the properties of an object, which is the essence of vuE2’s implementation of data listening

Attributes too much is not an introduction, the above is commonly used

7. Simple vUE implementation

7.1 the initialization

The first step of vue is initialized by new, so vue is a constructor

    // Construct a container for the virtual DOM
    function nodeContainer(node, vm, flag) {
        console.log(node)
        var flag = flag || document.createDocumentFragment()
        var child
 // Iterate over the nodes  while(child = node.firstChild) {  compile(child, vm)  flag.appendChild(child)  if (flag.firstChild) {  nodeContainer(child, vm, flag)  }  }  return flag  }  // The constructor  function Vue(options) {  this.data = options.data  observe(this.data, this)  var id = options.el  console.log(id, document.getElementById(id))  var dom = nodeContainer(document.getElementById(id), this);  document.getElementById(id).appendChild(dom)  }  // The properties in data are set to get and set  function define(obj, key, value) {  var dep = new Dep()  Object.defineProperty(obj, key, {  get: function() {  if(Dep.global){// This is the first time that the new Watcher object is added to the subscriber object when the data is initialized. After the second time, you don't need to add any more  dep.add(Dep.global);  }  return value  },  set: function(newValue) {  if(newValue === value){  return;// If the value does not change, do not trigger a new value change  }  value = newValue;// Change the value  dep.notify();  console.log("Set the latest value"+value);  }  })  }  // Set the properties in data to get and set  function observe (obj,vm){  Object.keys(obj).forEach(function(key){  define(vm,key,obj[key]);  })  }   // Compile the v-model and template syntax  function compile(node, vm) {  var res = /\{\{(.*)\}\}/g  // Node is the element  if (node.nodeType === 1) {  var attr = node.attributes  for (var i = 0; i < attr.length; i++) {  if (attr[i].nodeName === 'v-model') {  var name = attr[i].nodeValue  new Watcher(vm,node,name)  node.addEventListener('input'.function(e){  vm[name] = e.target.value  })  node.value = vm.data[name]  }  }  }  // Node is text  if (node.nodeType === 3) {  if (res.test(node.nodeValue)) {  var name = RegExp. $1  name = name.trim()  new Watcher(vm,node,name)  node.nodeValue = vm.data[name];  }  }  }   // Publisher mode  function Dep() {  this.subs = []  }  Dep.prototype = {  add: function(sub) {  this.subs.push(sub)  },  notify: function() {  this.subs.forEach(function(sub) {  sub.update()  })  }  }  / / subscriber  function Watcher(vm, node, name) {  Dep.global = this  this.name = name  this.node = node  this.vm = vm  this.update()  Dep.global = null  }  Watcher.prototype.update = function() {  this.get()  switch (this.node.nodeType) {  case 1:  this.node.value = this.value;  break;  case 3:  this.node.nodeValue = this.value  break  default: break;  }  }  Watcher.prototype.get = function() {  this.value = this.vm[this.name]  }  new Vue({  el: 'mvvm'. data: {  text: 10000  }  }) Copy the code

This article was typeset using MDNICE