一個因爲Function.name形成的兼容性bug

最近遇到一個bug,在調用APP的js接口時,有一個接口須要傳遞函數名過去,在js中我已經傳遞了函數名過去,可是在部分Android6.0及如下的安卓手機以及iOS 8上發現,APP並無收到我傳遞函數名,函數名爲空,百思不得其解,後來瀏覽了MDN上對function.name的解釋後,修復了這個bug。vue

項目基於VUE2.X開發,語法大部分使用ES6。webpack

具體以下:es6

//須要傳遞給APP的函數
let callbackFn = {
    fn: () => {
        //...
    }
}

//調用APP的js接口
nativeAPI.call(callbackFn.fn.name)

簡單的邏輯如上所示,可是在與安卓開發和iOS開發聯調時,他們告訴我,在低版本手機中,我傳過去的回調函數名稱callbackFn.fn.name值爲空字符串!就是說我並有獲取到function的名字!web

通過思考,嘗試瞭如下幾種辦法瀏覽器

1. 檢查webpack中babel-polyfill及babel的配置,使打包後的代碼兼容更多的設備

通過檢查,webpack中確實引入了babel-polyfillbabel

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: ["babel-polyfill", "./src/main.js"]
  },
...

.babelrc文件中配置以下app

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }],
    "stage-0"
  ],
  "plugins": ["transform-vue-jsx", "transform-runtime"]
}

結果:然而發現並無解決問題。函數

2.放棄es6的箭頭語法,手動改寫js函數

將callbackFn改成code

var callbackFn = {
    fn: function() {
        //...
    }
}

結果:仍是不行orm

3.將回調函數的js文件放到static文件夾中,不參與混淆打包

由於js的混淆會改變變量名,爲了不可能發生的錯誤,將回調函數單獨挪到static文件夾中,不參與打包
結果:失敗

4.改寫獲取函數名的方式

由於步驟3的失敗,讓我感受問題可能沒有出在打包過程當中,直覺告訴我,我獲取函數名的方法(function.name)可能有問題,因而去MDN搜索了一下,確實有所收穫。
Function.name - JavaScript | MDN

推斷函數名稱
變量和方法能夠從句法位置推斷匿名函數的名稱(ECMAScript 2015中新增)。
var f = function() {};
var object = {
  someMethod: function() {}
};

console.log(f.name); // "f"
console.log(object.someMethod.name); // "someMethod"

注意描述:(ECMAScript 2015中新增)
這讓我極度懷疑,在函數名的傳遞過程當中,可能瀏覽器並無幫我「推斷」,也許取到的仍是匿名函數,因此我獲取函數名時,獲取的是空字符串,因而我開始手動改寫,代碼以下:

//聲明函數
function callbackFn() {
    //...
}

//獲取函數名稱
let callbackName = callbackFn.name

//調用APP的js接口
nativeAPI.call(callbackName)

至此,這個問題解決了。

總結:1.須要傳遞函數名的時候,最好顯式的聲明函數,不然依賴瀏覽器推斷函數名的話不可靠,瀏覽器種類衆多,不能肯定是否實現了這個標準;2.儘可能避免使用傳遞函數名這種方式來作爲回調函數,由於通過壓縮混淆時會改變函數名,這種作法不可靠。

相關文章
相關標籤/搜索