>  기사  >  웹 프론트엔드  >  Javascript의 연산자 오버로딩에 대한 자세한 설명

Javascript의 연산자 오버로딩에 대한 자세한 설명

亚连
亚连원래의
2018-05-26 14:15:471614검색

이 기사에서는 Javascript에서 연산자 오버로딩을 구현하는 방법을 요약하고 소개합니다. 구현 아이디어는 매우 간단합니다. 필요한 친구들은 한 번 살펴보세요.

저는 최근에 Mat, Vector와 같은 일부 데이터 구조를 사용자 정의했습니다. 예를 들어 덧셈, 뺄셈, 곱셈, 나눗셈 등 4가지 산술 연산을 반복적으로 정의해야 하는데, 자바스크립트에는 C++나 C#과 같은 함수인 연산자 오버로딩이 없습니다. 정말 짜증나서 "나라를 구하고 싶다"고 자동으로 번역 코드에 연산자 오버로딩을 구현한다는 아이디어는 사실 매우 간단하다. 인터프리터를 작성하고 코드를 컴파일하면 된다. 예:

S = A + B (B - C.fun())/2 + D


`S로 번역됨 = 교체(replace(A, '+', 교체(replace(B) , '',(replace(B,'-',C.fun())))),'/',2),'+',D)`

replace 함수에서 우리는 다음의 해당 연산자를 호출합니다. 객체 함수, 대체 함수 코드는 다음과 같습니다:

/**
 * 转换方法
 * @param a
 * @param op
 * @param b
 * @returns {*}
 * @private
 */
export function __replace__(a,op,b){
  if(typeof(a) != 'object' && typeof(b) != 'object'){
    return new Function('a','b','return a' + op + 'b')(a,b)
  }
  if(!Object.getPrototypeOf(a).isPrototypeOf(b)
    && Object.getPrototypeOf(b).isPrototypeOf(a)){
    throw '不同类型的对象不能使用四则运算'
  }
  let target = null
  if (Object.getPrototypeOf(a).isPrototypeOf(b)) {
    target = new Function('return ' + b.__proto__.constructor.name)()
  }
  if (Object.getPrototypeOf(b).isPrototypeOf(a)) {
    target = new Function('return ' + a.__proto__.constructor.name)()
  }
  if (op == '+') {
    if (target.__add__ != undefined) {
      return target.__add__(a, b)
    }else {
      throw target.toString() +'\n未定义__add__方法'
    }
  }else if(op == '-') {
    if (target.__plus__ != undefined) {
      return target.__plus__(a, b)
    }else {
      throw target.toString() + '\n未定义__plus__方法'
    }
  }else if(op == '*') {
    if (target.__multiply__ != undefined) {
      return target.__multiply__(a, b)
    }else {
      throw target.toString() + '\n未定义__multiply__方法'
    }
  } else if (op == '/') {
    if (target.__pide__ != undefined) {
      return target.__pide__(a, b)
    }else {
      throw target.toString() + '\n未定义__pide__方法'
    }
  } else if (op == '%') {
    if (target.__mod__ != undefined) {
      return target.__mod__(a, b)
    }else {
      throw target.toString() + '\n未定义__mod__方法'
    }
  } else if(op == '.*') {
    if (target.__dot_multiply__ != undefined) {
      return target.__dot_multiply__(a, b)
    }else {
      throw target.toString() + '\n未定义__dot_multiply__方法'
    }
  } else if(op == './') {
    if (target.__dot_pide__ != undefined) {
      return target.__dot_pide__(a, b)
    }else {
      throw target.toString() + '\n未定义__dot_pide__方法'
    }
  } else if(op == '**') {
    if (target.__power__ != undefined) {
      return target.__power__(a, b)
    }else {
      throw target.toString() + '\n未定义__power__方法'
    }
  }else {
    throw op + '运算符无法识别'
  }
}

교체 구현은 너무 많은 설명 없이 매우 간단하며, 중요한 부분은 코드를 컴파일하는 방법입니다. 대학에서 데이터 구조를 공부할 때 네 가지 산술 연산을 구현하는 것이 이 번역의 기초이지만 약간의 차이가 있습니다. 프로세스를 간략하게 설명하세요.

1. 표현식을 분할하고 변수와 연산자를 추출하여 메타배열 A
2를 얻습니다. 메타배열을 탐색합니다.

요소가 연산자 덧셈, 뺄셈, 곱셈 및 나눗셈인 경우 스택에서 이전 요소를 팝합니다. 그리고 변환합니다.replace(마지막 연산자입니다.
요소가 ')'이면 요소가 스택에서 팝되고 '('를 만날 때까지 연결되어 스택에 푸시됩니다. 여기서 주의할 점은 '(' 요소 앞에 함수 호출 또는 교체가 있는지 확인하고, 함수 호출 또는 교체인 경우 계속해서 데이터를 앞으로 팝하고 교체 함수를 닫아야 합니다.
일반 요소인 경우 여부를 확인하세요. 이전 요소가 교체되면 ')'을 연결하여 교체 기능을 닫아야 합니다.

3. 2단계에서 얻은 스택 시퀀스를 결합하여 컴파일된 표현식을 얻으세요.

위 프로세스에 따라 코드를 구현합니다.

/**
 * 表达式转换工具方法
 * @param code
 */
export function translate (code) {
  let data = []
  let tmp_code = code.replace(/\s/g,'')
  let tmp = []
  let vari = tmp_code.split(/["]+[^"]*["]+|[&#39;]+[^&#39;]*[&#39;]+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|\}|=|%|\.\/|\.\*|,/g)
  let ops = tmp_code.match(/["]+[^"]*["]+|[&#39;]+[^&#39;]*[&#39;]+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|\}|=|%|\.\/|\.\*|,/g)
  for (let i = 0,len = ops.length; i < len; i++) {
    if (vari[i] != &#39;&#39;) {
      tmp.push(vari[i])
    }
    if (ops[i] != &#39;&#39;) {
      tmp.push(ops[i])
    }
  }
  tmp.push(vari[ops.length])
  for (let i = 0; i < tmp.length; i++){
    let item = tmp[i]
    if(/\*\*|\+|-|\*|\/|%|\.\/|\.\*/.test(tmp[i])) {
      let top = data.pop()
      let trans = &#39;__replace__(&#39; + top + &#39;,\&#39;&#39; + tmp[i] + &#39;\&#39;,&#39;
      data.push(trans)
    }else{
      if (&#39;)&#39; == tmp[i]) {
        let trans0 = tmp[i]
        let top0 = data.pop()
        while (top0 != &#39;(&#39;) {
          trans0 = top0 + trans0
          top0 = data.pop()
        }
        trans0 = top0 + trans0
        let pre = data[data.length - 1]
        while(/[_\w]+[\.]?[_\w]+/.test(pre)
        && !/^__replace__\(/.test(pre)
        && pre != undefined) {
          pre = data.pop()
          trans0 = pre + trans0
          pre = data[data.length - 1]
        }
        pre = data[data.length - 1]
        while(pre != undefined
        && /^__replace__\(/.test(pre)){
          pre = data.pop()
          trans0 = pre + trans0 + &#39;)&#39;
          pre = data[data.length - 1]
        }
        data.push(trans0)
      }else {
        let pre = data[data.length - 1]
        let trans1 = tmp[i]
        while(pre != undefined
        && /^__replace__\(/.test(pre)
        && !/\*\*|\+|-|\*|\/|\(|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|=|\}|%|\.\/|\.\*/.test(item)
        && !/^__replace__\(/.test(item)) {
          if(tmp[i + 1] == undefined){
            pre = data.pop()
            trans1 = pre + trans1 + &#39;)&#39;
            break;
          }else{
            pre = data.pop()
            trans1 = pre + trans1 + &#39;)&#39;
            pre = data[data.length - 1]
          }

        }
        data.push(trans1)

      }
    }
  }
  let result = &#39;&#39;
  data.forEach((value, key, own) => {
    result += value
  })
  return result
}

표현식 컴파일이 작성되고, 다음 단계는 작성된 코드를 번역기로 번역하는 방법입니다. 즉, 컨테이너가 필요합니다. 두 가지 방법: 하나는 클래스 생성자를 사용하여 메서드 속성을 재정의하는 것이고, 다른 하나는 사용자 지정 메서드에서 코드를 매개변수로 사용하는 것입니다. 다음으로 클래스 생성자에서 재정의 메서드를 소개합니다.

위에서 볼 수 있듯이 생성자에서 Object.defineProperty를 사용하여 재정의하고,translate_block은 전체 코드 블록을 나누어 번역합니다.

export default class OOkay {
  constructor () {
    let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(this))
    protos.forEach((proto, key, own) => {
      if(proto != &#39;constructor&#39;){
        Object.defineProperty(this, proto, {
          value:new Function(translate_block(proto, this[proto].toString())).call(this)
        })
      }
    })
  }
}

새 클래스의 경우 OOkay 클래스만 상속한 다음 클래스에서 연산자 오버로딩을 사용하면 됩니다. OOOkay가 아닌 클래스에서 상속하는 경우 방법은 다음과 같습니다.

/**
 * 类代码块转换工具
 * @param name
 * @param block
 * @returns {string}
 */
export function translate_block (name , block) {
  let codes = block.split(&#39;\n&#39;)
  let reg = new RegExp(&#39;^&#39; + name + &#39;$&#39;)
  console.log(reg.source)
  codes[0] = codes[0].replace(name,&#39;function&#39;)
  for(let i = 1; i < codes.length; i++) {
    if (codes[i].indexOf(&#39;//&#39;) != -1) {
      codes[i] = codes[i].substring(0,codes[i].indexOf(&#39;//&#39;))
    }
    if(/\*\*|\+|-|\*|\/|%|\.\/|\.\*/g.test(codes[i])){
      if (codes[i].indexOf(&#39;return &#39;) != -1) {
        let ret_index = codes[i].indexOf(&#39;return &#39;) + 7
        codes[i] = codes[i].substring(0,ret_index) + translate(codes[i].substring(ret_index))
      }else {
        let eq_index = codes[i].indexOf(&#39;=&#39;) + 1
        codes[i] = codes[i].substring(0,eq_index) + translate(codes[i].substring(eq_index))
      }
    }
  }
  return &#39;return &#39; + codes.join(&#39;\n&#39;)
}

For 클래스가 아닌 코드에는 컨테이너가 필요합니다. 여기서는 두 가지 방법을 사용합니다. 하나는 다음과 같이 ookay 스크립트에 사용됩니다.

40fc65e74328a5ea22a3b784f397d3e4

let a = a+b // a 및 b는 객체 인스턴스입니다

2cacc6d41bbb37262a98f745aa00fbf0
다른 하나는 다음과 같이 코드를 __$$__ 메서드에 매개변수로 전달하여 코드를 컴파일하고 실행하는 것입니다.


/**
   * 非继承类的注入方法
   * @param target
   */
  static inject (target) {
    let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(target))
    protos.forEach((proto, key, own) => {
      if (proto != &#39;constructor&#39;) {
        Object.defineProperty(target, proto, {
          value:new Function(translate_block(proto, target[proto].toString())).call(target)
        })
      }
    })
  }

위는 다음과 같습니다. 모두를 위해 정리한 내용이 앞으로 모든 사람에게 도움이 되기를 바랍니다.

JQuery ajax가 json을 반환할 때 중국어 왜곡 코드를 해결하는 방법 ajax 게시물 사용 방법. Django 프레임워크의 메서드

django


에서 jquery ajax 게시 데이터를 사용할 때 발생하는 403 오류에 대한 해결 방법

위 내용은 Javascript의 연산자 오버로딩에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.