国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > JS > 正文

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

2024-05-06 16:28:19
字體:
供稿:網(wǎng)友
這篇文章主要幫助大家理解javascript中的with關(guān)鍵字,學習with關(guān)鍵字的作用,感興趣的小伙伴們可以參考一下
 

說起js中的with關(guān)鍵字,很多小伙伴們的第一印象可能就是with關(guān)鍵字的作用在于改變作用域,然后最關(guān)鍵的一點是不推薦使用with關(guān)鍵字。聽到不推薦with關(guān)鍵字后,我們很多人都會忽略掉with關(guān)鍵字,認為不要去管它用它就可以了。但是有時候,我們在看一些代碼或者面試題的時候,其中會有with關(guān)鍵字的相關(guān)問題,很多坑是你沒接觸過的,所以還是有必要說說with這一個關(guān)鍵字。

一、基本說明

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

with (expression) statement;

使用with關(guān)鍵字的目的是為了簡化多次編寫訪問同一對象的工作,比如下面的例子:

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

這幾行代碼都是訪問location對象中的屬性,如果使用with關(guān)鍵字的話,可以簡化代碼如下:

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

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

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

前面的基本說明中,我們可以看到with的作用之一是簡化代碼。但是為什么不推薦使用呢?下面我們來說說with的缺點:

1、性能問題
2、語義不明,調(diào)試困難

三、性能問題

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

第一段代碼是沒有使用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語句作用到了obj2這個對象上,然后with塊里面訪問的卻是obj對象。有一種觀點是:使用了with關(guān)鍵字后,在with塊內(nèi)訪問變量時,首先會在obj2上查找是否有名為obj的屬性,如果沒有,再進行下一步查找,這個過程導(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語句作用到了obj對象上,然后直接使用a訪問obj的a屬性,按照前面說到的觀點,訪問a屬性時,是一次性就可以在obj上找到該屬性的,但是為什么代碼性能依舊降低了呢。
真正的原因是:使用了with關(guān)鍵字后,JS引擎無法對這段代碼進行優(yōu)化。
JS引擎在代碼執(zhí)行之前有一個編譯階段,在不使用with關(guān)鍵字的時候,js引擎知道a是obj上的一個屬性,它就可以靜態(tài)分析代碼來增強標識符的解析,從而優(yōu)化了代碼,因此代碼執(zhí)行的效率就提高了。使用了with關(guān)鍵字后,js引擎無法分辨出a變量是局部變量還是obj的一個屬性,因此,js引擎在遇到with關(guān)鍵字后,它就會對這段代碼放棄優(yōu)化,所以執(zhí)行效率就降低了。
使用with關(guān)鍵字對性能的影響還有一點就是js壓縮工具,它無法對這段代碼進行壓縮,這也是影響性能的一個因素。

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

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

function foo(obj) {  with (obj) {    a = 2;  }}var o1 = {  a: 3};var o2 = {  b: 3};foo(o1);console.log(o1.a); // 2foo(o2);console.log( o2.a ); // undefinedconsole.log( a ); // 2

這段代碼很容易理解了,在foo函數(shù)內(nèi),使用了with關(guān)鍵字來訪問傳進來的obj對象,然后修改a屬性。當傳入o1對象時,因為o1對象存在著a屬性,所以這樣沒有問題。傳入o2對象時,在修改a屬性時,由于o2對象沒有a這個屬性,所以被修改的a屬性則變成了全局變量。這就造成了潛在的bug。

五、延伸分析

前面說了那么多,相信大家已經(jīng)理解了為什么不推薦使用with關(guān)鍵字以及可能存在的問題。下面我們來看看一些更復(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);//20console.log(obj.y);//undefined

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

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

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

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

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

({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();

這段代碼會輸出什么?為什么呢?

總結(jié)

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



注:相關(guān)教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 郓城县| 长武县| 溧阳市| 马公市| 乾安县| 永兴县| 桐梓县| 临洮县| 司法| 信阳市| 唐山市| 舞阳县| 台中市| 克山县| 虞城县| 张家港市| 南宁市| 板桥市| 安陆市| 商水县| 灵丘县| 元谋县| 松阳县| 丰宁| 赤峰市| 麻江县| 乌拉特后旗| 都昌县| 临夏县| 柏乡县| 剑川县| 民勤县| 木兰县| 遂川县| 佳木斯市| 彭山县| 常熟市| 桑植县| 澳门| 晋江市| 儋州市|