這兩天在幹活的時候,遇到了這麼一個業務場景.就是後臺介面返回的資料中有不少欄位是我不需要的,而我只想保留幾個我想要的資料欄位,不想要整個物件賦值.
我們假設後臺返回的資料如下:
{
"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>
複製程式碼
而我現在只想要 name
和 age
這兩個欄位,上面的做法會將所有的屬性值全部列印出來.所以,我採用的賦值方法一般是
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
程式碼塊的語句中,儘量使用指定物件的屬性作為變數名,至少我們要保證儘量的不汙染全域性.