欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

理解javascript中的with關(guān)鍵字

 更新時(shí)間:2016年02月15日 15:50:39   作者:狼狼的藍(lán)胖子  
這篇文章主要幫助大家理解javascript中的with關(guān)鍵字,學(xué)習(xí)with關(guān)鍵字的作用,感興趣的小伙伴們可以參考一下

說(shuō)起js中的with關(guān)鍵字,很多小伙伴們的第一印象可能就是with關(guān)鍵字的作用在于改變作用域,然后最關(guān)鍵的一點(diǎn)是不推薦使用with關(guān)鍵字。聽(tīng)到不推薦with關(guān)鍵字后,我們很多人都會(huì)忽略掉with關(guān)鍵字,認(rèn)為不要去管它用它就可以了。但是有時(shí)候,我們?cè)诳匆恍┐a或者面試題的時(shí)候,其中會(huì)有with關(guān)鍵字的相關(guān)問(wèn)題,很多坑是你沒(méi)接觸過(guò)的,所以還是有必要說(shuō)說(shuō)with這一個(gè)關(guān)鍵字。

一、基本說(shuō)明

在js高級(jí)程序設(shè)計(jì)中是這樣描述with關(guān)鍵字的:with語(yǔ)句的作用是將代碼的作用域設(shè)置到一個(gè)特定的作用域中,基本語(yǔ)法如下:

with (expression) statement;

使用with關(guān)鍵字的目的是為了簡(jiǎn)化多次編寫(xiě)訪(fǎng)問(wèn)同一對(duì)象的工作,比如下面的例子:

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;

這幾行代碼都是訪(fǎng)問(wèn)location對(duì)象中的屬性,如果使用with關(guān)鍵字的話(huà),可以簡(jiǎn)化代碼如下:

with (location){
  var qs = search.substring(1);
  var hostName = hostname;
  var url = href;
}

在這段代碼中,使用了with語(yǔ)句關(guān)聯(lián)了location對(duì)象,這就以為著在with代碼塊內(nèi)部,每個(gè)變量首先被認(rèn)為是一個(gè)局部變量,如果局部變量與location對(duì)象的某個(gè)屬性同名,則這個(gè)局部變量會(huì)指向location對(duì)象屬性。
注意:在嚴(yán)格模式下不能使用with語(yǔ)句。

二、with關(guān)鍵字的弊端

前面的基本說(shuō)明中,我們可以看到with的作用之一是簡(jiǎn)化代碼。但是為什么不推薦使用呢?下面我們來(lái)說(shuō)說(shuō)with的缺點(diǎn):

1、性能問(wèn)題
2、語(yǔ)義不明,調(diào)試?yán)щy

三、性能問(wèn)題

首先說(shuō)說(shuō)性能問(wèn)題,關(guān)于使用with關(guān)鍵字的性能問(wèn)題,首先我們來(lái)看看兩段代碼:

第一段代碼是沒(méi)有使用with關(guān)鍵字:

function func() {
  console.time("func");
  var obj = {
    a: [1, 2, 3]
  };
  for (var i = 0; i < 100000; i++) {
    var v = obj.a[0];
  }
  console.timeEnd("func");//0.847ms
}
func();

第二段代碼使用了with關(guān)鍵字:

function funcWith() {
  console.time("funcWith");
  var obj = {
    a: [1, 2, 3]
  };
  var obj2 = { x: 2 };
  with (obj2) {
    console.log(x);
    for (var i = 0; i < 100000; i++) {
      var v = obj.a[0];
    }
  }
  console.timeEnd("funcWith");//84.808ms
}
funcWith();

在使用了with關(guān)鍵字后了,代碼的性能大幅度降低。第二段代碼的with語(yǔ)句作用到了obj2這個(gè)對(duì)象上,然后with塊里面訪(fǎng)問(wèn)的卻是obj對(duì)象。有一種觀點(diǎn)是:使用了with關(guān)鍵字后,在with塊內(nèi)訪(fǎng)問(wèn)變量時(shí),首先會(huì)在obj2上查找是否有名為obj的屬性,如果沒(méi)有,再進(jìn)行下一步查找,這個(gè)過(guò)程導(dǎo)致了性能的降低。但是程序性能真正降低的原因真的是這樣嗎?
我們修改一下第二段代碼,修改如下:

function funcWith() {
  console.time("funcWith");
  var obj = {
    a: [1, 2, 3]
  };
  with (obj) {
    for (var i = 0; i < 100000; i++) {
      var v = a[0];
    }
  }
  console.timeEnd("funcWith");//88.260ms
}
funcWith();

這段代碼將with語(yǔ)句作用到了obj對(duì)象上,然后直接使用a訪(fǎng)問(wèn)obj的a屬性,按照前面說(shuō)到的觀點(diǎn),訪(fǎng)問(wèn)a屬性時(shí),是一次性就可以在obj上找到該屬性的,但是為什么代碼性能依舊降低了呢。
真正的原因是:使用了with關(guān)鍵字后,JS引擎無(wú)法對(duì)這段代碼進(jìn)行優(yōu)化。
JS引擎在代碼執(zhí)行之前有一個(gè)編譯階段,在不使用with關(guān)鍵字的時(shí)候,js引擎知道a是obj上的一個(gè)屬性,它就可以靜態(tài)分析代碼來(lái)增強(qiáng)標(biāo)識(shí)符的解析,從而優(yōu)化了代碼,因此代碼執(zhí)行的效率就提高了。使用了with關(guān)鍵字后,js引擎無(wú)法分辨出a變量是局部變量還是obj的一個(gè)屬性,因此,js引擎在遇到with關(guān)鍵字后,它就會(huì)對(duì)這段代碼放棄優(yōu)化,所以執(zhí)行效率就降低了。
使用with關(guān)鍵字對(duì)性能的影響還有一點(diǎn)就是js壓縮工具,它無(wú)法對(duì)這段代碼進(jìn)行壓縮,這也是影響性能的一個(gè)因素。

四、語(yǔ)義不明,難以調(diào)試

前面說(shuō)到除了性能的問(wèn)題,with還存在的一個(gè)缺點(diǎn)語(yǔ)義不明,難以調(diào)試,就是造成代碼的不易閱讀,而且可能造成潛在的bug。

function foo(obj) {
  with (obj) {
    a = 2;
  }
}

var o1 = {
  a: 3
};
var o2 = {
  b: 3
};

foo(o1);
console.log(o1.a); // 2

foo(o2);
console.log( o2.a ); // undefined
console.log( a ); // 2

這段代碼很容易理解了,在foo函數(shù)內(nèi),使用了with關(guān)鍵字來(lái)訪(fǎng)問(wèn)傳進(jìn)來(lái)的obj對(duì)象,然后修改a屬性。當(dāng)傳入o1對(duì)象時(shí),因?yàn)閛1對(duì)象存在著a屬性,所以這樣沒(méi)有問(wèn)題。傳入o2對(duì)象時(shí),在修改a屬性時(shí),由于o2對(duì)象沒(méi)有a這個(gè)屬性,所以被修改的a屬性則變成了全局變量。這就造成了潛在的bug。

五、延伸分析

前面說(shuō)了那么多,相信大家已經(jīng)理解了為什么不推薦使用with關(guān)鍵字以及可能存在的問(wèn)題。下面我們來(lái)看看一些更復(fù)雜的情況,看下面的代碼:

var obj = {
  x: 10,
  foo: function () {
    with (this) {
      var x = 20;
      var y = 30;
      console.log(y);//30
    }
  }
};
obj.foo();
console.log(obj.x);//20
console.log(obj.y);//undefined

在這段代碼中,分別輸出30,20,undefined的。涉及的知識(shí)點(diǎn)也比較多:with關(guān)鍵字,this關(guān)鍵字,變量提升等等,我們來(lái)一一解釋一下。
1、this關(guān)鍵字
關(guān)于this關(guān)鍵字的文章google上面相當(dāng)多,這里不再贅述,我們只需記住一點(diǎn):this關(guān)鍵字始終指向調(diào)用函數(shù)的對(duì)象。在這里,foo函數(shù)中,this指向的就是obj對(duì)象。因此在with(this)語(yǔ)句塊里面,可以直接通過(guò)x變量來(lái)訪(fǎng)問(wèn)obj的x屬性。
2、變量提升
js中的變量提升也是一個(gè)經(jīng)常遇到的問(wèn)題,我們可以簡(jiǎn)單理解成在js中,變量聲明會(huì)被提升到函數(shù)的頂部,盡管有的時(shí)候,它是在后面聲明的。

所以上面的代碼可以解析為:

var obj = {
  x: 10,
  foo: function () {
    var x;//聲明局部變量x
    var y;//聲明局部變量y
    with (obj) {
      x = 20;//訪(fǎng)問(wèn)變量x,在obj上找到x,則修改為20
      y = 30;//訪(fǎng)問(wèn)變量y,在bojg上找不到y(tǒng),則進(jìn)一步查找,找到局部變量y,修改為30
      console.log(y);//30//直接輸出局部變量y,
    }
  }
};
obj.foo();
console.log(obj.x);//20,obj.x已被修改為20
console.log(obj.y);//undefined,obj不存在y屬性,則為undefined

上面的注釋中,解釋了代碼的執(zhí)行過(guò)程,相信大家已經(jīng)理解了為什么會(huì)出處30,20,undefined的原因。

有興趣的同學(xué)可以看看下面這段代碼:

({
x: 10,
foo: function () {
  function bar() {
    console.log(x);
    console.log(y);
    console.log(this.x);
  }
  with (this) {
    var x = 20;
    var y = 30;
    bar.call(this);
  }
}
}).foo();

這段代碼會(huì)輸出什么?為什么呢?

總結(jié)

本文總結(jié)了with語(yǔ)句的特點(diǎn)和弊端,總的來(lái)說(shuō),強(qiáng)烈不推薦使用with關(guān)鍵字。其實(shí)在日常編碼中,我們只需要知道不去使用with就可以了,但是有的時(shí)候我們可能會(huì)遇到一些關(guān)于with的奇奇怪怪的問(wèn)題,想要找出真正的原因,就要深入理解with關(guān)鍵字,這有助于我們?nèi)ド钊雽W(xué)習(xí)JS這門(mén)語(yǔ)言,同時(shí)也是學(xué)習(xí)JS的一個(gè)樂(lè)趣。

  • uniapp介紹與使用以及小程序?qū)崟r(shí)獲取視頻播放時(shí)間

    uniapp介紹與使用以及小程序?qū)崟r(shí)獲取視頻播放時(shí)間

    這篇文章主要給大家介紹了關(guān)于uniapp介紹與使用以及小程序?qū)崟r(shí)獲取視頻播放時(shí)間的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用uniapp具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-02-02
  • 詳解搭建es6+devServer簡(jiǎn)單開(kāi)發(fā)環(huán)境

    詳解搭建es6+devServer簡(jiǎn)單開(kāi)發(fā)環(huán)境

    這篇文章主要介紹了詳解搭建es6+devServer簡(jiǎn)單開(kāi)發(fā)環(huán)境,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • JS 文件本身編碼轉(zhuǎn)換 圖文教程

    JS 文件本身編碼轉(zhuǎn)換 圖文教程

    JS編碼轉(zhuǎn)換,這句話(huà)本身就是一句具有二重義的話(huà)。通常理解為JS文件里能轉(zhuǎn)換編碼的代碼,但是,我所碰到的問(wèn)題并不是這樣的,是要解決JS文件本身的編碼問(wèn)題,它是UTF-8編碼的還是ANSI編碼的?
    2009-10-10
  • 最全的package.json解析

    最全的package.json解析

    從我們接觸前端開(kāi)始,每個(gè)項(xiàng)目的根目錄下一般都會(huì)有一個(gè)package.json文件,這個(gè)文件定義了當(dāng)前項(xiàng)目所需要的各種模塊,以及項(xiàng)目的配置信息,本文就詳細(xì)的來(lái)介紹一下
    2021-07-07
  • 一文學(xué)會(huì)用JS判斷文字是否被省略(ellipsis)

    一文學(xué)會(huì)用JS判斷文字是否被省略(ellipsis)

    這篇文章主要給大家介紹了用JS如何判斷文字被省略ellipsis,CSS幫我們搞定了省略,但是JS并不知道文本什么時(shí)候被省略了,所以我們得通過(guò)JS來(lái)計(jì)算,接下來(lái),我將介紹2種方法來(lái)實(shí)現(xiàn)JS計(jì)算省略,需要的朋友可以參考下
    2023-08-08
  • splitChunks精細(xì)控制代碼分割降低包大小

    splitChunks精細(xì)控制代碼分割降低包大小

    這篇文章主要為大家介紹了如何使用splitChunks精細(xì)控制代碼分割來(lái)實(shí)現(xiàn)降低包大小的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • UniApp開(kāi)發(fā)H5接入微信登錄的全過(guò)程

    UniApp開(kāi)發(fā)H5接入微信登錄的全過(guò)程

    uni-app是一個(gè)使用Vue.js開(kāi)發(fā)跨平臺(tái)應(yīng)用的前端框架,下面這篇文章主要給大家介紹了關(guān)于UniApp開(kāi)發(fā)H5接入微信登錄的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • JavaScript生成簡(jiǎn)單等差數(shù)列

    JavaScript生成簡(jiǎn)單等差數(shù)列

    本文給大家分享使用for循環(huán)實(shí)現(xiàn)js生成簡(jiǎn)單的等差數(shù)列,具體實(shí)現(xiàn)方法,大家參考下本文
    2017-11-11
  • 編程語(yǔ)言JavaScript簡(jiǎn)介

    編程語(yǔ)言JavaScript簡(jiǎn)介

    這篇文章主要介紹了編程語(yǔ)言JavaScript簡(jiǎn)介,本文講解了JavaScript是什么、JavaScript特點(diǎn)、JavaScript和Java的區(qū)別等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • 最新評(píng)論