1. 程式人生 > 其它 >Linux使用者、組與shell指令碼

Linux使用者、組與shell指令碼

vue原始碼createPatchFunction

export function createPatchFunction (backend) {
  // ... 一些輔助方法
  return function patch (oldVnode, vnode, hydrating, removeOnly) {
    if (isUndef(vnode)) {
      if (isDef(oldVnode)) invokeDestroyHook(oldVnode)
      return
    }

    let isInitialPatch = false
    const insertedVnodeQueue = []

    if (isUndef(oldVnode)) {
      // empty mount (likely as component), create new root element
      isInitialPatch = true
      createElm(vnode, insertedVnodeQueue)
    } else {
      const isRealElement = isDef(oldVnode.nodeType)
      if (!isRealElement && sameVnode(oldVnode, vnode)) {
        // patch existing root node
        patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly)
      } else {
        if (isRealElement) {
          // mounting to a real element
          // check if this is server-rendered content and if we can perform
          // a successful hydration.
          if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
            oldVnode.removeAttribute(SSR_ATTR)
            hydrating = true
          }
          if (isTrue(hydrating)) {
            if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
              invokeInsertHook(vnode, insertedVnodeQueue, true)
              return oldVnode
            } else if (process.env.NODE_ENV !== 'production') {
              warn(
                'The client-side rendered virtual DOM tree is not matching ' +
                'server-rendered content. This is likely caused by incorrect ' +
                'HTML markup, for example nesting block-level elements inside ' +
                '<p>, or missing <tbody>. Bailing hydration and performing ' +
                'full client-side render.'
              )
            }
          }
          // either not server-rendered, or hydration failed.
          // create an empty node and replace it
          oldVnode = emptyNodeAt(oldVnode)
        }

        // replacing existing element
        const oldElm = oldVnode.elm
        const parentElm = nodeOps.parentNode(oldElm)

        // create new node
        createElm(
          vnode,
          insertedVnodeQueue,
          // extremely rare edge case: do not insert if old element is in a
          // leaving transition. Only happens when combining transition +
          // keep-alive + HOCs. (#4590)
          oldElm._leaveCb ? null : parentElm,
          nodeOps.nextSibling(oldElm)
        )

        // update parent placeholder node element, recursively
        if (isDef(vnode.parent)) {
          let ancestor = vnode.parent
          const patchable = isPatchable(vnode)
          while (ancestor) {
            for (let i = 0; i < cbs.destroy.length; ++i) {
              cbs.destroy[i](ancestor)
            }
            ancestor.elm = vnode.elm
            if (patchable) {
              for (let i = 0; i < cbs.create.length; ++i) {
                cbs.create[i](emptyNode, ancestor)
              }
              // #6513
              // invoke insert hooks that may have been merged by create hooks.
              // e.g. for directives that uses the "inserted" hook.
              const insert = ancestor.data.hook.insert
              if (insert.merged) {
                // start at index 1 to avoid re-invoking component mounted hook
                for (let i = 1; i < insert.fns.length; i++) {
                  insert.fns[i]()
                }
              }
            } else {
              registerRef(ancestor)
            }
            ancestor = ancestor.parent
          }
        }

        // destroy old node
        if (isDef(parentElm)) {
          removeVnodes([oldVnode], 0, 0)
        } else if (isDef(oldVnode.tag)) {
          invokeDestroyHook(oldVnode)
        }
      }
    }

    invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch)
    return vnode.elm
  }
}

上面程式碼中,在函式createPatchFunction 中返回了patch 方法,這種程式設計方式屬於函式柯里化,也屬於高階函式的一種用法

什麼是函式柯里化

柯里化(curring)是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且接受餘下的引數且返回結果的新函式的技術。

上面的解釋來自於百度百科,這樣對於理解可能有些抽象,結合下面的程式碼會更好理解

// 普通的add函式
function add (x,y){
  return x + y
}
// curring之後
function curringAdd (x) {
  return function (y) {
    return x + y
  }
}
add(1,2) // 3
curringAdd(1)(2) // 3

實際上就是把add函式的xy兩個引數變成了先用一個函式接收x然後返回一個函式去處理y引數。現在思路應該就比較清晰了,就是值傳遞給函式一部分引數來呼叫它,讓它返回一個函式去處理剩下的引數。

柯里化有什麼好處

  1. 引數複用
// 正常正則驗證字串reg.test(txt)
// 函式封裝後
function check(reg, txt) {
  return reg.test(txt)
}
check(/\d+/g, 'test')// false
check(/[a-z]+/g, 'test') // true
// curring後
function curringCheck(reg) {
  return function(txt) {
    return reg.test(txt)
  }
}
var hasNumber = curringCheck(/\d+/g)
var hasLetter = curringCheck(/[a-z]+/g)
hasNumber('test1') // true
hasNumber('testttt') // false
hasLetter('234')// false

上面的示例是一個正則的校驗,正常來說直接呼叫check函式就可以了,但是如果我有很多地方都要校驗是否有數字,起始就是需要將第一個引數reg進行復用,這樣別的笛梵幹就能夠直接呼叫hasNumber,hasLetter等函式,讓引數能夠複用,呼叫起來也更方便。
2. 提前確認

var on = function(element, event, handler) {
    if (document.addEventListener) {
        if (element && event && handler) {
            element.addEventListener(event, handler, false);
        }
    } else {
        if (element && event && handler) {
            element.attachEvent('on' + event, handler);
        }
    }
}

var on = (function() {
    if (document.addEventListener) {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.addEventListener(event, handler, false);
            }
        };
    } else {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.attachEvent('on' + event, handler);
            }
        };
    }
})();

//換一種寫法可能比較好理解一點,上面就是把isSupport這個引數給先確定下來了
var on = function(isSupport, element, event, handler) {
    isSupport = isSupport || document.addEventListener;
    if (isSupport) {
        return element.addEventListener(event, handler, false);
    } else {
        return element.attachEvent('on' + event, handler);
    }
}

我們在做專案的過程中,封裝一些dom操作可以說再常見不過,上面第一種寫法也是比較常見,但是我們看看第二種寫法,它相對一第一種寫法就是自執行然後返回一個新的函式,這樣其實就是提前確定了會走哪一個方法,避免每次都進行判斷。
3. 延遲執行

Function.protorype.bind = function(context) {
  const _this = this
  const args = Array.prototype.slice.call(arguments,1)
  return function(){
    return _this.apply(context, args)
  }
}

像我們js中經常使用的bind,實現的機制就死Curring

柯里化效能

  • 存取arguments物件通常要比存取命名引數要慢一點
  • 一些老版本的瀏覽器在arguments.length的實現上是相當慢的
  • 使用fn.apply(...)fn.call(...)通常比直接呼叫fn(...)稍微慢點
  • 建立大量巢狀作用域和閉包函式會帶來花銷,無論是在記憶體上還是速度上

起始大部分應用中,主要的效能瓶頸是在操作DOM節點上,這js的效能損耗基本是可以忽略不計的,所以currying是可以直接放心使用的

經典面試題

實現一個add方法,使計算結果能夠滿足如下預期
add(1)(2)(3) = 6
add(1,2,3)(4) = 10
add(1)(2)(3)(4)(5) = 15
function add(){
  const _args = Array.prototype.slice.call(arguments)
  const _adder = function () {
    _args.push(...arguments)
    return _adder 
  }
  _adder.toSting = function(){
    return _args.reduce(function(a,b){
      return a + b
    })
  }
  return _adder
}