# Analysis of vNode and DIff algorithms in Snabbdom

preface

Have you ever encountered @ + method names in front end development? When I first saw it, I was like, “What is this?”

Decorator: A Decorator is a Decorator. Decorator: A Decorator is a Decorator. Next let me tell you about ~

What is a decorator

Decorator pattern

Decorator pattern is the ability to dynamically add responsibilities to objects during program execution without changing the objects themselves. For example, a person may wear padded clothes when it is cold and short sleeves when it is hot, but whatever he wears, he is essentially the same person, only wearing different clothes.

So a Decorator is simply a design pattern that dynamically adds new behavior to a class, extends the functionality of a class at runtime, and modifies the class’s properties and methods so that they can be shared more flexibly between classes.

@ is a syntactic sugar for this design pattern, but it is currently in a phase 2 proposal and requires compilation to ES5 or ES6 using the Babel module.

How to use decorators

Tripartite library use

Babel version ≥ 7.x

If the Babel version of the project is greater than or equal to 7.x, use @babel/plugin-proposal-decorators

  • The installation

    npm install --save-dev @babel/plugin-proposal-decorators
    Copy the code
  • Configuration. The babelrc

    {
      "plugins": [["@babel/plugin-proposal-decorators", { "legacy": true}}]]Copy the code

Babel version ≤ 6.x

If less than or equal to 6.x, use babel-plugin-transform-decorators-legacy

  • The installation

    npm install --save-dev @babel/plugin-proposal-decorators
    Copy the code
  • Configuration. The babelrc

    {
        "plugins": ["transform-decorators-legacy"]}Copy the code

Method of use

Decorator is written as @ + returns the expression of the decorator function, so it can be used as follows:

@classDecorator
class TargetClass { / / class
  @fieldDecorator
  targetField = 0; // Class instance attributes

  @funDecorator
  targetFun(){}/ / class methods

  @accessorDecorator
  get targetGetFun() {}// Class accessors
}
Copy the code

If an object uses more than one decorator, what is the order of execution?

function decorator1() {
  console.log('decorator1');
  return function decFn1(targetClass) {
    console.log('decFn1');
    return targetClass;
  };
}

function decorator2() {
  console.log('decorator2');
  return function decFn2(targetClass) {
    console.log('decFn2');
    return targetClass;
  };
}
Copy the code

Order of execution:

Print result:

Based on the above, we know that the decorator is executed from the outside in and from the inside out.

Using range

Depending on how they are used, we can see that decorators can be applied to the following types:

  • Class (class)
  • Class instance properties (public, private, and static)
  • Class methods (public, private, and static)
  • Class accessors (public, private, and static)

Function decoration

When we look at the use and scope of decorators, we find that decorators cannot decorate functions, so what is the reason? The reason is that the function has a function promotion.

var num = 0;
function add () {
  num ++;
}
@add
function fn() {}
Copy the code

In this example, we want num to be equal to 1 after execution, but this is not the case because the function is promoted, and the code actually executes like this:

function add () {
  num ++;
}
@add
function fn() {}
var num;
num = 0;
Copy the code

If you must decorate the function, you can use the form of higher-order function, this article is mainly about the decorator, the higher-order function is not described here, do not understand the partners can consult the information

Decorator principle

Decorators can be divided into two categories according to the scope of their use: class decorators and class method decorators. Let me share them with you one by one.

The adornment of the class

The ginseng

Let’s start with a small example of how the decorator receives arguments:

function decorator(. args) {
  args.forEach((arg, index) = > {
    console.log(` parameters${index}`, arg);
  });
}

@decorator
class TargetClass {}console.log('targetClass:', TargetClass);
Copy the code

The print result is as follows:

As a result, we see that the decorator accepts only one parameter, the class definition itself that is being decorated.

The return value

Let’s continue with a small example of the return value:

function returnStr(targetClass) {
  return 'hello world~';
}

function returnClass(targetClass) {
  return targetClass;
}

@returnStr
class ClassA { }

@returnClass
class ClassB {}console.log('ClassA:', ClassA);
console.log('ClassB:', ClassB);
Copy the code

The results are as follows:

Based on the results, we find that whatever the decorator returns is what the output is.

conclusion

From the above two examples, we can draw the following conclusion:

@decorator
class TargetClass {}/ / is equivalent to

class TargetClass { }
TargetClass = decorator(TargetClass) || TargetClass;
Copy the code

So, the first argument to the decorator is the class to decorate, and its function is to process the class.

Use of class decorators

  • Add attributes

    Since the argument received by the decorator is the class definition itself, we can add attributes to the class:

    function addAttribute(targetClass) {
      targetClass.isUseDecorator = true;
    }
    
    @addAttribute
    class TargetClass {}console.log(TargetClass.isUseDecorator); // true
    Copy the code

    In this example, we defined the addAttribute decorator to add isUseDecorator flags to TargetClass, much like annotations in Java, just to mark the target type.

  • Returns an expression for the decorator function

    A decorator function can be an expression that returns a decorator function. It can also be an expression that returns a decorator function.

    function addAttribute(content) {
      return function decFn(targetClass) {
        targetClass.content = content;
        return targetClass;
      };
    }
    
    @addAttribute('This is the content ~ ~ ~')
    class TargetClass {}console.log(TargetClass.content); // This is the content ~ ~ ~
    Copy the code

    We saw that TargetClass added the content attribute via the addAttribute decoration, and that it was possible to assign a value to the Content attribute by passing a parameter to addAttribute, making the decorator more flexible.

  • Adding a prototype method

    In the previous examples we added static properties of the class, but since the decorator accepts the class definition itself, it can also add or modify prototype methods by accessing the class’s Prototype property:

    function decorator(targetClass) {
      targetClass.prototype.decFun = function () {
        console.log('Here is the prototype method added by the decorator decFun~');
      };
    }
    
    @decorator
    class TargetClass {}const targetClass = new TargetClass();
    
    console.log(targetClass);
    targetClass.decFun();
    Copy the code

    The results are as follows:

Class decorators can also be used to statically mark types and extend methods. Class decorators can also be used to static mark types and extend methods. For example, React-Redux’s Connect is a class decorator, and Antd’s form. create is also a class decorator.

// connect
class App extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(App);

/ / is equivalent to

@connect(mapStateToProps, mapDispatchToProps)
export default class App extends React.Component {}

// Form.create
const WrappedApp = Form.create()(App);

/ / is equivalent to

@Form.create()
class App extends React.Component {}
Copy the code

Class method decoration

The ginseng

The reason we put class instance properties, class methods, and class accessors in this category is because they are all attributes of an object (instance properties, stereotype methods, and instance accessors), which means they take similar parameters:

function decorator(. args) {
  args.forEach((arg, index) = > {
    console.log(` parameters${index}`, arg);
  });
  console.log('* * * * * * * * * * * * * * * *');
}

class TargetClass {
  @decorator
  field = 0;

  @decorator
  fn() { }

  @decorator
  get getFn() {}}const targetOne = new TargetClass();
console.log(targetOne.field, Object.getOwnPropertyDescriptor(targetOne, 'field'));
Copy the code

The results are as follows:

Based on the results, we see that the class method decorator takes three parameters: the class definition object, the instance property/method/instance accessor property name, and the property operator. It looks familiar, and yes, it looks like the argument received by Object.defineProperty().

Object.defineProperty(obj, props, descriptor)

Object.defineproperty () simply defines a new property directly on an Object, or modifies an existing property of an Object, and returns the Object. The method takes three arguments in total:

  • Object to define attributes (obj)
  • The name of the property or Symbol (props) to define or modify
  • Property descriptors to define or modify

There are two main types of attribute descriptors in objects: data descriptors and access descriptors. A data descriptor is a property with a value, which can be writable or unwritable; Access descriptors are properties described by getter and setter functions. A descriptor can only be one of these two, not both.

They share the following optional key values:

  • configurable

    Property can be deleted and redefined. The default value is false

  • enumerable

    Whether to appear in an enumeration property of an object. Default is false

Data descriptor specific key values:

  • value

    The default value of this property is undefined

  • writable

    Whether it can be changed. The default value is false

Access-operator-specific keys:

  • get

    Property getter, undefined if there is no getter; The default value is undefined

  • set

    Property, or undefined if there is no setter; The default value is undefined

Now that we’re done with Object.defineProperty(), let’s see how to use it

Use of class method decorators

Let’s take a look at an example:

function readonly(target, name, descriptor) {
  descriptor.writable = false;
  return descriptor;
}

class Person {
  @readonly
  name = 'zhangsan';
}

const person = new Person();
console.log(person.name, Object.getOwnPropertyDescriptor(person, 'name'));
Copy the code

The print result is as follows:

As the code above shows, the decorator modifies the property’s description object, which is then used to define the property.

conclusion

From this we can draw the conclusion that:

function changeName(target, name, descriptor) {
  descriptor.value = 'lisi';
  return descriptor;
}
class Person {
  @changeName
  name = 'zhangsan';
}
const person = new Person();

/ / is equivalent to

class Person {
  name = 'zhangsan';
}
const person = new Person();
Object.defineProperty(person, 'name', {
  value: 'lisi'});Copy the code

The application of decorators

In a React project, several components use the same backend interface to obtain data, but the parameters are different. In some cases, each component uses the backend interface manually when writing code.

.export default class CompOne extends Component {... getData =async() = > {// Call the back-end interface
    const data = await request('/xxx', {
      params: {
        id: '123'.// Different components send different parameters}});this.setState({ data });
  }
  render(){...return (
      <div>. I am component one: {data}...</div>)}}Copy the code

In this case, we can use decorators to solve the problem

/ / a decorator
function getData(params) {
  return (Comp) = > {
    class WrapperComponent extends Component {... getData =async() = > {const data = await request('/xxx', {
          params,
        });
        this.setState({ data });
      }
      render(){...return (
          <Comp data={data} />)}}returnComp; }}/ / component. @getData({id: '123'
})
export default class index extends Component {...render(){...const data = this.props.data; // Get the desired data directly from this.props
    return (
      <div>. I am component one: {data}...</div>)}}Copy the code

conclusion

Well, today’s sharing is about to end here, oh, I hope that through this article you can have a certain understanding of the decoration, if you have different opinions, welcome to comment in the comment section! Let the storm come more fierce!

Refer to the link

A decorator

ES7 Proposal: Decorators

Object.defineProperty()

babel-plugin-transform-decorators-legacy

Recommended reading

Analysis of VNode and DIff algorithm in Snabbdom

How to use SCSS to achieve one key skin change

Why is index not recommended as key in Vue

Brief analysis of Web screen recording technology scheme and implementation

Open source works

  • Political cloud front-end tabloid

Open source address www.zoo.team/openweekly/ (wechat communication group on the official website of tabloid)

  • Item selection SKU plug-in

Open source addressGithub.com/zcy-inc/sku…

, recruiting

ZooTeam, a young passionate and creative front-end team, belongs to the PRODUCT R&D department of ZooTeam, based in picturesque Hangzhou. The team now has more than 60 front-end partners, with an average age of 27, and nearly 40% of them are full-stack engineers, no problem in the youth storm group. The members consist of “old” soldiers from Alibaba and NetEase, as well as fresh graduates from Zhejiang University, University of Science and Technology of China, Hangzhou Electric And other universities. In addition to daily business docking, the team also carried out technical exploration and practice in material system, engineering platform, building platform, performance experience, cloud application, data analysis and visualization, promoted and implemented a series of internal technical products, and continued to explore the new boundary of front-end technology system.

If you want to change what’s been bothering you, you want to start bothering you. If you want to change, you’ve been told you need more ideas, but you don’t have a solution. If you want change, you have the power to make it happen, but you don’t need it. If you want to change what you want to accomplish, you need a team to support you, but you don’t have the position to lead people. If you want to change the pace, it will be “5 years and 3 years of experience”; If you want to change the original savvy is good, but there is always a layer of fuzzy window… If you believe in the power of believing, believing that ordinary people can achieve extraordinary things, believing that you can meet a better version of yourself. If you want to be a part of the process of growing a front end team with deep business understanding, sound technology systems, technology value creation, and impact spillover as your business takes off, I think we should talk. Any time, waiting for you to write something and send it to [email protected]