Home  >  Article  >  Web Front-end  >  Detailed explanation of the steps for using interfaces in JS

Detailed explanation of the steps for using interfaces in JS

php中世界最好的语言
php中世界最好的语言Original
2018-05-24 13:38:107933browse

This time I will bring you a detailed explanation of the steps for using interfaces in JS. What are the precautions for using interfaces in JS. Here are practical cases, let’s take a look.

This is the README of js-interface. Although it is not a very complicated thing, if anyone can read it, I will write down the source code ideas ORZ

Introduction

When working on a project with separate front and back, I have some headaches about how to manage things like APIs. When reading the book "JavaScript Design Patterns", the second chapter mentioned that in ## The concept of simulated interface (interface) in #JavaScript is used to facilitate the use of many design patterns, so I tried to simulate an interface. Since I am a back-end Java developer, I hope that interface default implementation, interface inheritance, can be added to this simulation layer Method overloading and other capabilities, although these things will inevitably be sacrificed in performance, but for me it can improve some development experience (I knowTypeScript, Just wanted to get a wheel and try it out :P).

Use

Since the original intention is to facilitate the management of Api, then make a demo about Api.

Create an interface

const config = {
    // 接口的名字
    name: 'IApi', 
    // 是否打开此接口的 debug 开关
    // 开发时必须打开,否则不会启动 (方法声明、方法实现等)入参的类型检查。
    // 打开这个的情况下,还会获得一些调试用的信息。
    debug: true,          
}
let IApi = new Interface(config)

Declaration method

The simplest way to declare:

IApi.method({name: 'getName'})
// 等价于
IApi.method({name: 'getName', args: undefined})
This declares the

IApi interface contains A getName method has no parameters and no default implementation. This requires that any subsequent IApi sub-interface or implementation class must implement this method, otherwise an exception will be thrown. .


If you want to specify the parameter list of the method:

IApi.method({ name: 'getName', args: null })

Attention! When

args is null, it means that the method can accept any number of any parameters. If a method is overloaded (for details, please refer to the following about overloading) (Instructions contained):

// 声明一个空参方法
IApi.method({ id: 0, name: 'getName', args: null })
// 重载上面的方法,使其有且只有一个 'string' 类型,名为 name 的参数
IApi.method({ id: 1, name: 'getName', args: [
    {name: 'name', type: 'string', support: val => typeof val === 'string'}
] })

Attention!

In the parameter description, the

type attribute is just a string value, which does not really represent the actual type of the parameter. Like the name attribute, it only provides information for debugging, so you can fill in any string value you think is appropriate enough to mark some information about the parameter.

What really determines whether the method accepts this parameter is the

support attribute. When it returns true, the next parameter will be checked until all parameters have been checked or at a certain position. Parameter not accepted.

If necessary, you can perform special processing on the actual input parameters in

support, such as converting objects, checking specific attributes, etc.


If you want to provide a default implementation for the method:

IApi.method({ 
    name: 'getName', 
    // 默认实现,不能为箭头函数!
    implement: function() {
        return "IApi"   
    }
})

Go back to our demo and use it comprehensively:

// 声明两个方法,它们都没有参数,也不需要重载因此这样就可以了
IApi
  .method({ name: 'getName'  })
  // 项目中使用 Axios,因此这里需要一个方法来获取 axios 实例
  .method({ name: 'getAxios' })
// 声明四个请求方式对应的方法
const methods = ['get', 'post', 'put', 'delete']
methods.forEach(method => {
  IApi.method({
    name: method,
    args: null,
    implement: function() {
      // 处理了 this 指向问题,放心用吧
      return this.getAxios()[method].apply(this, arguments)
        .then(responseHandler)
        .catch(errorHandler)
    }
  })
})
Inherited interface

Suppose we want to create interface A and inherit interfaces B, C, D, E, etc., use the following statement:

const A = new Interface({
    name: 'A',
    debug: true
}).extends([B, C, D, E])

extends The method will pass in the interface held by All method declarations (that is, those declared via Interface.method(config)) are copied to interface A, including the default implementation of those method declarations.

Notice!

Generally speaking, the same method signature will not be overridden in multiple interfaces, but if you really have such a need, you can set the

id rules yourself, such as :

const B = new Interface(...)
  .method({ id: 'B00', name: 'getName', args = [...] })
  .method({ id: 'B01', name: 'getName', args = [...] })
                
const C = new Interface(...)
  .method({ id: 'C00', name: 'getName', args = [...] })
Then specify which statement to implement when implementing the method:

// 注意!如果一个方法被重载,则不能在 class 中声明该方法。
class AImpl { ... } 
const AInstance = new AImpl(...)
B.implement({
    object: AInstance,
    id: 'B00', // 指定要实现的方法声明
    name: 'getName'
})

Go back to our demo again and use it comprehensively:

const IAuthenticationApi = new Interface({
  name: 'IAuthentication',
  debug: true
})
   // 指明 IAuthenticationApi 继承自 IApi 接口
   .extends(IApi)
IAuthenticationApi
  // 重载方法 login
  // loin (username :string, password :string)
  .method({
    id: 0,
    name: 'login',
    args: [
      {name: 'username', type: 'string', support: val => typeof val === 'string'},
      {name: 'password', type: 'string', support: val => typeof val === 'string'}
    ]
  })
  // login()
  .method({
    id: 1,
    name: 'login'
  })
Implement the interface

// 编写一个实现类
class AuthenticationApi {
  constructor(axios) { this.axios = axios }
  // 直接实现 getName 方法  
  getName() { return "AuthenticationApi" }
  // 直接实现 getAxios 方法
  getAxios() { return this.axios }
}
// 实现重载方法
IAuthenticationApi
  .implement({
    // 指定挂载实现到 AuthenticationApi 上
    object: AuthenticationApi,
    // 指定此实现是对应 id 为 0 的方法声明
    id: 0,
    name: 'login',
    implement: function(username, password) {
      console.log('带参数的 login')
      // 还记得我们在 IApi 接口中定义了 get 方法(包括默认实现)吗?
      this.get('https://www.baidu.com')
      return Promise.resolve('hello')
    }
  })
  .implement({
    object: AuthenticationApi,
    id: 1,
    name: 'login',
    implement: function () {
      console.log('无参数的 login')
    },
  })
IAuthenticationApi.ensureImplements(AuthenticationApi)

Use the interface to implement the class

    let authenticationService = new AuthenticationApi(axios)
    // 挂载代理函数到实例上,否则会提示
    // Uncaught TypeError: authenticationService.login is not a function
    IAuthenticationApi.ensureImplements(authenticationService)
    authenticationService
        .login('sitdownload', '1498696873')
        // login(string, string) 会返回一个 Promise 还记得吗 :P
        .then(str => alert(`${str} world!`))
    authenticationService.login()

About the log

First make sure that the debug switch is turned on when creating the interface (

{ debug: true }).

If the above demo runs normally, you will get the following log:

// 注册方法
Interface 注册方法: IApi.getName()
Interface 注册方法: IApi.getAxios()
Interface 注册方法: IApi.get(any)
Interface 注册方法: IApi.post(any)
Interface 注册方法: IApi.put(any)
Interface 注册方法: IApi.delete(any)
Interface 注册方法: IAuthentication extends IApi.getName()
Interface 注册方法: IAuthentication extends IApi.getAxios()
Interface 注册方法: IAuthentication extends IApi.get(any)
Interface 注册方法: IAuthentication extends IApi.post(any)
Interface 注册方法: IAuthentication extends IApi.put(any)
Interface 注册方法: IAuthentication extends IApi.delete(any)
Interface 注册方法: [0]IAuthentication.login(username :string, password :string)
Interface 注册方法: [1]IAuthentication.login()
// 实现方法
Interface 实现方法: 保存 [0]IAuthentication.login(...) 实现:
ƒ implement(username, password)
Interface 实现方法: 保存 [1]IAuthentication.login(...) 实现:
ƒ implement()
// 匹配方法
Interface 方法匹配: 精准匹配
IAuthentication.login({ username: "sitdownload" } :string, { password: "1498696873" } :string).
// 在控制台这行是可以打开实现的具体位置的
ƒ implement(username, password)
// 方法输出
AuthenticationApi.js?7b55:25 带参数的 login
// 匹配方法
Interface 方法匹配: 无法精准匹配 IAuthentication.get("https://www.baidu.com"),使用 any 实现匹配:
ƒ implement()
Interface 方法匹配: 精准匹配 IAuthentication.login().
ƒ implement()
// 方法输出
AuthenticationApi.js?7b55:35 无参数的 login
// AuthenticationApi.login(username, password) 中请求了 'https://www.baidu.com'
Failed to load https://www.baidu.com/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1' is therefore not allowed access.
// IApi.get(any) 中将异常直接向下抛了
Uncaught (in promise) {type: "network", payload: Error: Network Error
    at createError (webpack-internal:///./node_modules/_axios@0.18.0@axios/lib/…}
Follow-up

If you want to release the version, make sure that all interface methods are implemented correctly. You can turn off debug, so that there will be no internal parameter checking and debugging output of

Interface.

I believe you have mastered the method after reading the case in this article. For more exciting information, please pay attention to other related articles on the php Chinese website!

Recommended reading:

Analysis of real front-end interview questions

##Detailed explanation of the steps of combining React with TypeScript and Mobx

The above is the detailed content of Detailed explanation of the steps for using interfaces in JS. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn