Javascript中的with語法

這兩天在幹活的時候,遇到了這麼一個業務場景.就是後臺接口返回的數據中有不少字段是我不需要的,而我只想保留幾個我想要的數據字段,不想要整個對象賦值.

我們假設後臺返回的數據如下:

{
  "code" : "200",
  "msg" : "操作成功",
  "data" : {
    "name": "zhangsan",
    "age": 12,
    "job": "FE developer",
    "like": "football"
  },
  "hasError" : false
}

按照以前的做法,管它三七二十一,全給我拿來.直接把整個對象賦值給myData

aInterface().then(res => {
	this.myData = res.data.data
})

然後在模板中使用:

<div>
	<ul>
      <li v-for="prop in myData">
        {{prop}}
      </li>
    </ul>
</div>

而我現在只想要 nameage 這兩個字段,上面的做法會將所有的屬性值全部打印出來.所以,我採用的賦值方法一般是

aInterface().then(res => {
	const data = res.data.data
	this.myData.name = data.name
	this.myData.age = data.age
})

但是這樣的寫法就顯得有點繁瑣了,每次都要寫 this.myData 這個變量了.此時想起了以前看到過的有個叫 with 的語句,語法是這樣的:

const obj = {
  name:'zhangsan',
  age:12
}
console.log(obj)  // {name: "zhangsan", age: 12}

obj.name = 'lisi'
obj.age = 15
console.log(obj)  // {name: "lisi", age: 15}

with(obj){
  name = 'wangwu'
  age = 18
  job = 'fe'
}
console.log(obj)  // {name: "wangwu", age: 18}

obj.a = 11 這種是我們最常見的給對象裏面屬性賦值的方式,而 with 後面跟了一個表達式 obj , 花括號裏面的語句就只需要 a = 111 這樣的賦值方式,感覺是可以少寫一點代碼了. 那麼我們可以看出,其實 with 關鍵字改變了裏面語句的作用域,在 with 代碼塊內部,變量會先被認爲是一個局部變量,如果某個變量名與表達式 obj 中的一個屬性名是一樣的,那麼這個局部變量就會指向 obj 對象中同名屬性.但假如 obj 中沒有一個屬性名是與代碼塊中的局部變量的名字是一樣的,那麼此時就會發生污染全局變量的現象.不知道小夥伴們是否注意到了,上面的代碼中,在代碼塊的最後,我加了 job = 'fe' 這樣的一句語句.但是,console 控制檯打印出來的 obj 中並沒有包含這個屬性.這就是因爲此時的 job 這個變量已經泄漏到了全局作用域中了,我們可以繼續在控制檯執行下面代碼

console.log(job === window.job)  // true

會發現結果是 true ,證明此時 job 已經是全局變量了.這就是 with 的其中一個弊端,容易數據泄漏,污染全局.而 with 的另外一個缺點就是會導致性能下降.我們來運行如下代碼,然後在控制檯查看運行結果:

function test(){
  console.time('test')
  const obj = {
    a:1
  }
  for(let i = 0;i < 99999; i++){
    const tmp = obj.a
  }
  console.timeEnd('test')
}
test()  // test: 1.2958984375ms

function testWith(){
  console.time('testWith')
  const obj = {
    a:1
  }
  with(obj){
    for(let i = 0;i < 99999; i++){
      const tmp = a
    }
  }
  
  console.timeEnd('testWith')
}
testWith()  // testWith: 12.7939453125ms

注意:
console.time() 方法是作爲計算器的起始方法, console.timeEnd()方法作爲計算器的結束方法 . 兩個方法配合使用,一般是用來測試一段程序執行的時長.所以,這裏兩個函數的運行結果很可能是每次都不一樣的,但是每次偏差應該都不會相差太大.由此,我們可以看出使用了 with 語句的代碼所需要的時間更長.是沒有使用with語句的好多倍.這是因爲JavaScript引擎在編譯階段就進行一些性能優化,比如在執行之前就確定了一些變量的定義位置,然後在代碼真正的執行過程中可以快速的找到標識符,而使用了 with 之後,因爲無法知道傳遞到with 中的對象是哪個,所以JavaScript引擎它也會很懵逼,然後選擇放棄,不做優化.

總結:
我們代碼中儘量不推薦使用 with 語句,並且在ES5嚴格模式中已經禁止該標籤.但假如真的很想要用它的話,那麼在 with 代碼塊的語句中,儘量使用指定對象的屬性作爲變量名,至少我們要保證儘量的不污染全局.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章