js代碼提升(js 函數提升)

本文目錄一覽:

解釋JavaScript中的變數聲明提升?

由於JavaScript在設計之初就是弱類型,所以很多地方設計的不是特別嚴格。JavaScript代碼是自上而下執行的,變數提升指的就是你明明在第10行通過 var 申明了變數並賦值,但是在程序運行時還沒載入到第10行的時候,變數就被申明,但是到第10行的時候變數才被賦值。這個就是變數提升。所以一般都是把變數申明放在JavaScript的最頂端 或者使用let const 申明避免變數的提升

Web前端工程師應該知道的提高JavaScript技能的技巧!

今天小編要跟大家分享的文章是關於Web前端工程師應該知道的提高JavaScript

技能的技巧!熟悉web前端工作的小夥伴都知道,JavaScript是前端工程師的必備技能。JavaScript

是一種複雜的語言。如果是你是高級或者初級web開發人員,了解它的基本概念非常重要。本篇文章小編就為大家介紹幾種提高JavaScript

技能的技巧,下面讓我們一起來看一看吧!

01、變數賦值(值vs引用)

理解JavaScript如何給變數賦值可以幫助我們減少一些不必要的bug。如果你不理解這一點,可能很容易地編寫被無意中更改值的代碼。

JavaScript總是按照值來給變數賦值。這一部分非常重要:當指定的值是JavaScript的五種基本類型之一(即

Boolean,null,undefined,String和Number)時,將分配實際值。但是,當指定的值是

Array,Function或Object時,將分配對內存中對象的引用給變數。

在以下代碼段中,使用var1對var2進行賦值。由於var1是基本類型(String),因此var2的值等於var1的String

值,並且可以認為此時與var1完全不同。因此,重新賦值var2對var1沒有影響。

letvar1=’Mystring’;

letvar2=var1;

var2=’Mynewstring’;

console.log(var1);

//’Mystring’

console.log(var2);

//’Mynewstring’

接著,與對象賦值進行比較。

letvar1={name:’Jim’}

letvar2=var1;

var2.name=’John’;

console.log(var1);

//{name:’John’}

console.log(var2);

//{name:’John’}

如果你期望它會像原始類型賦值那樣,很可能會出問題!如果你創建了一個無意中會改變對象的函數,就會出現一些非預期的行為。

02、閉包

閉包是一個重要的JavaScript模式,可以私有訪問變數。在本例中,createGreeter返回一個匿名函數,這個函數可以訪問參數

greeting(在這裡是「Hello」)。在後續的調用中,sayHello將有權訪問這個greeting!

functioncreateGreeter(greeting){

returnfunction(name){

console.log(greeting+’,’+name);

}

}

constsayHello=createGreeter(‘Hello’);

sayHello(‘Joe’);

//Hello,Joe

在更真實的場景中,你可以設想一個初始函數apiConnect(apiKey),它返回一些使用APIkey的方法。在這種情況下,apiKey

只需要提供一次即可。

functionapiConnect(apiKey){

functionget(route){

returnfetch(`${route}?key=${apiKey}`);

}

functionpost(route,params){

returnfetch(route,{

method:’POST’,

body:JSON.stringify(params),

headers:{

‘Authorization’:`Bearer${apiKey}`

}

})

}

return{get,post}

}

constapi=apiConnect(‘my-secret-key’);

//NoneedtoincludetheapiKeyanymore

api.get(‘#/get-endpoint’);

api.post(‘#/post-endpoint’,{name:’Joe’});

03、解構

JavaScript參數解構可以從對象中干中提取所需屬性的常用方法。

constobj={

ame:’Joe’,

food:’cake’

}

const{name,food}=obj;

console.log(name,food);

//’Joe”cake’

如果要以其他名稱提取屬性,可以使用如下方式:

constobj={

ame:’Joe’,

food:’cake’

}

const{name:myName,food:myFood}=obj;

console.log(myName,myFood);

//’Joe”cake’

解構經常也用於直接用於提取傳給函數的參數。如果你熟悉React,可能已經見過這個:

constperson={

ame:’Eddie’,

age:24

}

functionintroduce({name,age}){

console.log(`I’m${name}andI’m${age}yearsold!`);

}

console.log(introduce(person));

//”I’mEddieandI’m24yearsold!”

04、展開運算

ES6的一個常用之一的特性就是展開(…)運算符了,在下面的例子中,Math.max不能應用於arr

數組,因為它不將數組作為參數,但它可以將各個元素作為參數傳入。展開運算符…可用於提取數組的各個元素。

constarr=[4,6,-1,3,10,4];

constmax=Math.max(…arr);

console.log(max);

//10

05、剩餘參數

剩餘參數語法和展開語法看起來的一樣的,不同的是展開語法是為了結構數組和對象;而剩餘參數和展開運算符是相反的,剩餘參數收集多個元素合成一個數組。

functionmyFunc(…args){

console.log(args[0]+args[1]);

}

myFunc(1,2,3,4);

//3

restparameters和arguments的區別

1.arguments是偽數組,包含所有的實參

2.剩餘參數是標準的數組,可以使用數組的方法

06、數組方法

JavaScript數組方法通常可以提供令人難以置信的、優雅的方法來執行所需的數據轉換。作為StackOverflow

的貢獻者,我經常看到關於如何以某種方式操縱對象數組的問題,這往往也是數組方法的完美用例。

map、filter、reduce

JavaScript數組方法map、filter和reduce容易混淆,這些都是轉換數組或返回聚合值的有用方法。

map:返回一個數組,其中每個元素都使用指定函數進行過轉換。

constarr=[1,2,3,4,5,6];

constmapped=arr.map(el=el+20);

console.log(mapped);

//[21,22,23,24,25,26]

filter:返回一個數組,只有當指定函數返回true時,相應的元素才會被包含在這個數組中。

constarr=[1,2,3,4,5,6];

constfiltered=arr.filter(el=el===2||el===4);

console.log(filtered);

//[2,4]

reduce:按函數中指定的值累加

constarr=[1,2,3,4,5,6];

constreduced=arr.reduce((total,current)=total+current);

console.log(reduced);

//21

find,findIndex,indexOf

find:返回與指定條件匹配的第一個實例,如果查到不會繼續查找其他匹配的實例。

constarr=[1,2,3,4,5,6,7,8,9,10];

constfound=arr.find(el=el5);

console.log(found);

//6

再次注意,雖然5之後的所有元素都滿足條件,但是只返回第一個匹配的元素。當你發現匹配項時,通常會中斷for循環,在這種情況下,這實際上非常有用。

findIndex:這與find幾乎完全相同,但不是返回第一個匹配元素,而是返回第一個匹配元素的索引。

constarr=[‘Nick’,’Frank’,’Joe’,’Frank’];

constfoundIndex=arr.findIndex(el=el===’Frank’);

console.log(foundIndex);

//1

indexOf:與findIndex幾乎完全相同,但它不是將函數作為參數,而是採用一個簡單的值。

當w你需要更簡單的邏輯並且不需要使用函數來檢查是否存在匹配時,可以使用此方法。

constarr=[‘Nick’,’Frank’,’Joe’,’Frank’];

constfoundIndex=arr.indexOf(‘Frank’);

console.log(foundIndex);

//1

push,pop,shift,unshift

push:這是一個相對簡單的方法,它將一個項添加到數組的末尾。它就地修改數組,函數本身會返回添加到數組中的項。

letarr=[1,2,3,4];

constpushed=arr.push(5);

console.log(arr);

//[1,2,3,4,5]

console.log(pushed);

//5

pop:這將從數組中刪除最後一項。同樣,它在適當的位置修改數組,函數本身返回從數組中刪除的項。

letarr=[1,2,3,4];

constpopped=arr.pop();

console.log(arr);

//[1,2,3]

console.log(popped);

//4

shift:從數組中刪除第一項。同樣,它在適當的位置修改數組。函數本身返回從數組中刪除的項。

letarr=[1,2,3,4];

constshifted=arr.shift();

console.log(arr);

//[2,3,4]

console.log(shifted);

//1

unshift:將一個或多個元素添加到數組的開頭。同樣,它在適當的位置修改數組。與許多其他方法不同,函數本身返回數組的新長度。

letarr=[1,2,3,4];

constunshifted=arr.unshift(5,6,7);

console.log(arr);

//[5,6,7,1,2,3,4]

console.log(unshifted);

//7

splice,slice

splice:通過刪除或替換現有元素和/或添加新元素來更改數組的內容,此方法會修改了數組本身。

下面的代碼示例的意思是:在數組的位置1上刪除0個元素,並插入b。

letarr=[‘a’,’c’,’d’,’e’];

arr.splice(1,0,’b’)

slice:從指定的起始位置和指定的結束位置之前返回數組的淺拷貝。如果未指定結束位置,則返回數組的其餘部分。

重要的是,此方法不會修改數組,而是返回所需的子集。

letarr=[‘a’,’b’,’c’,’d’,’e’];

constsliced=arr.slice(2,4);

console.log(sliced);

//[‘c’,’d’]

console.log(arr);

//[‘a’,’b’,’c’,’d’,’e’]

sort

sort:根據提供的函數對數組進行排序。這個方法就地修改數組。如果函數返回負數或0,則順序保持不變。如果返回正數,則交換元素順序。

letarr=[1,7,3,-1,5,7,2];

constsorter=(firstEl,secondEl)=firstEl-secondEl;

arr.sort(sorter);

console.log(arr);

//[-1,1,2,3,5,7,7]

07、Generators(生成器)

生成器是一種特殊的行為,實際上是一種設計模式,我們通過調用next()方法來遍歷一組有序的值。想像一下,例如使用遍歷器對數組[1,2,3,4,5]進行遍歷。第一次調用next()方法返回1,第二次調用next()方法返回2,以此類推。當數組中的所有值都返回後,調用next()方法將返回null或false或其它可能的值用來表示數組中的所有元素都已遍歷完畢。

function*greeter(){

yield’Hi’;

yield’Howareyou?’;

yield’Bye’;

}

constgreet=greeter();

console.log(greet.next().value);

//’Hi’

console.log(greet.next().value);

//’Howareyou?’

console.log(greet.next().value);

//’Bye’

console.log(greet.next().value);

//undefined

使用生成器生成無限個值:

function*idCreator(){

leti=0;

while(true)

yieldi++;

}

constids=idCreator();

console.log(ids.next().value);

//0

console.log(ids.next().value);

//1

console.log(ids.next().value);

//2

//etc…

08、恆等運算符(===)與相等運算符(==)

大家一定要知道JavaScript中的恆等運算符(===)和相等運算符(==)之間的區別!

==運算符在比較值之前會進行類型轉換,而===運算符在比較之前不會進行任何類型轉換。

console.log(0==’0′);

//true

console.log(0===’0′);

//false

09、對象比較

我看到JavaScript新手所犯的錯誤是直接比較對象。變數指向內存中對象的引用,而不是對象本身!實際比較它們的一種方法是將對象轉換為JSON

字元串。這有一個缺點:對象屬性順序不能保證!比較對象的一種更安全的方法是引入專門進行深度對象比較的庫(例如,lodash的isEqual)。

下面的對象看起來是相等的,但實際上它們指向不同的引用。

constjoe1={name:’Joe’};

constjoe2={name:’Joe’};

console.log(joe1===joe2);

//false

相反,下面的計算結果為true,因為一個對象被設置為與另一個對象相等,因此指向相同的引用(內存中只有一個對象)。

constjoe1={name:’Joe’};

constjoe2=joe1;

console.log(joe1===joe2);

//true

相反,以下計算結果為true,因為一個對象設置為等於另一個對象,因此指向相同的引用(內存中只有一個對象)。

constjoe1={name:’Joe’};

constjoe2=joe1;

console.log(joe1===joe2);

//true

10、回調函數

很多人都被JavaScript回調函數嚇倒了!他們很簡單,舉個例子。console.log函數作為回調傳遞給myFunc。

它在setTimeout完成時執行。

functionmyFunc(text,callback){

setTimeout(function(){

callback(text);

},2000);

}

myFunc(‘Helloworld!’,console.log);

//’Helloworld!’

11、Promises

一旦你理解了JavaScript回調,很快就會發現自己陷入了「回調地獄」中。這個時候可以使用promise,將非同步邏輯包裝在promise

中,成功時resolve或在失敗時reject使用「then」來處理成功的情況,使用catch來處理異常。

constmyPromise=newPromise(function(res,rej){

setTimeout(function(){

if(Math.random()

returnres(‘Hooray!’);

}

returnrej(‘Ohno!’);

},1000);

});

myPromise

.then(function(data){

console.log(‘Success:’+data);

})

.catch(function(err){

console.log(‘Error:’+err);

});

//IfMath.random()returnslessthan0.9thefollowingislogged:

//”Success:Hooray!”

//IfMath.random()returns0.9orgreaterthefollowingislogged:

//”Error:Onno!”

12、Async/Await

在掌握了promise的用法後,你可能也會喜歡asyncawait,它只是一種基於promise

的「語法糖」。在下面的示例中,我們創建了一個async函數,並awaitgreeterpromise。

constgreeter=newPromise((res,rej)={

setTimeout(()=res(‘Helloworld!’),2000);

})

asyncfuncti

var a=0; function fun(){ a++; if(a

var a=0; function fun(){ a++; if(a=10){ fun(); } console.log(a+=1) } fun();

為什麼結果是十一個十一?理由如下:

帶 var 的只聲明還沒有被定義,帶 function 的已經聲明和定義。所以在代碼執行前有帶 var 的就提前聲明。

變數提升示例:

console.log(a)  // undefinedvar

a = 10

變數提升是當棧內存作用域形成時,JS代碼執行前,瀏覽器會將帶有var, function關鍵字的變數提前進行聲明 declare(值默認就是 undefined)。

定義 defined(就是賦值操作),這種預先處理的機制就叫做變數提升機制也叫預定義。

在變數提升階段:帶 var 的只聲明還沒有被定義,帶 function 的已經聲明和定義。所以在代碼執行前有帶 var 的就提前聲明,比如這裡的 a 就賦值成 undefined,在代碼執行過程中遇到創建函數的代碼瀏覽器會直接跳過。

變數提升只發生在當前作用域。比如:在頁面開始載入時,只有全局作用域發生變數提升,這時候的函數中存儲的都是代碼字元串。

全局作用域中不帶var聲明變數雖然也可以但是建議帶上 var聲明變數,不帶 var 的相當於給window對象設置一個屬性罷了。

私有作用域(函數作用域),帶 var 的是私有變數。不帶 var 的是會向上級作用域查找,如果上級作用域也沒有那麼就一直找到 window 為止,這個查找過程叫作用域鏈。

全局作用域中使用 var 申明的變數會映射到 window 下成為屬性。

js中if是一個代碼塊嘛? 寫在if裡面的函數聲明和var變數會得到提升嘛?

你好,你的這個問題是這樣的首先第一個列印a,是在源碼開頭定義的var變數a。

緊接著在第一個if內嵌套定義了一個名為a的函數,因為js是弱語言,所以實現對應的變數a被重新指向了函數a,所以在最後一次列印a的時候是函數a

Jsp中有大量js和css,如何提高頁面載入速度

載入速度不必刻意強求,真正項目尤其是前端開發講究的是可讀性,如真的項目寫好後可以考慮壓縮css和js代碼,css帶走方向的複合屬性如邊框,外邊距,補白等最好用一個屬性代替,順序為上,右,下,左。表格盡量少用。

js判斷對象里是否有內容

Javascript語言的設計不夠嚴謹,很多地方一不小心就會出錯。

舉例來說,請考慮以下情況。

現在,我們要判斷一個全局對象myObj是否存在,如果不存在,就對它進行聲明。用自然語言描述的演算法如下:

複製代碼代碼如下:

if (myObj不存在){

聲明myObj;

}

你可能會覺得,寫出這段代碼很容易。但是實際上,它涉及的語法問題,遠比我們想像的複雜。Juriy Zaytsev指出,判斷一個Javascript對象是否存在,有超過50種寫法。只有對Javascript語言的實現細節非常清楚,才可能分得清它們的區別。

第一種寫法

根據直覺,你可能覺得可以這樣寫:

複製代碼代碼如下:

if (!myObj) {

myObj = { };

}

但是,運行這段代碼,瀏覽器會直接拋出ReferenceError錯誤,導致運行中斷。請問錯在哪裡?

對了,if語句判斷myObj是否為空時,這個變數還不存在,所以才會報錯。改成下面這樣,就能正確運行了。

複製代碼代碼如下:

if (!myObj) {

var myObj = { };

}

為什麼加了一個var以後,就不報錯了?難道這種情況下,if語句做判斷時,myObj就已經存在了嗎?

要回答這個問題,就必須知道Javascript解釋器的工作方式。Javascript語言是”先解析,後運行”,解析時就已經完成了變數聲明,所以上面的代碼實際等同於:

複製代碼代碼如下:

var myObj;

if (!myObj) {

var myObj = { };

}

因此,if語句做判斷時,myObj確實已經存在了,所以就不報錯了。這就是var命令的”代碼提升”(hoisting)作用。Javascript解釋器,只”提升”var命令定義的變數,對不使用var命令、直接賦值的變數不起作用,這就是為什麼不加var會報錯的原因。

第二種寫法

除了var命令,還可以有另一種改寫,也能得到正確的結果:

複製代碼代碼如下:

if (!window.myObj) {

myObj = { };

}

window是javascript的頂層對象,所有的全局變數都是它的屬性。所以,判斷myobj是否為空,等同於判斷window對象是否有myobj屬性,這樣就可以避免因為myObj沒有定義而出現ReferenceError錯誤。不過,從代碼的規範性考慮,最好還是對第二行加上var:

複製代碼代碼如下:

if (!window.myObj) {

var myObj = { };

}

或者寫成這樣:

if (!window.myObj) {

window.myObj = { };

}

第三種寫法

上面這種寫法的缺點在於,在某些運行環境中(比如V8、Rhino),window未必是頂層對象。所以,考慮改寫成:

複製代碼代碼如下:

if (!this.myObj) {

this.myObj = { };

}

在全局變數的層面中,this關鍵字總是指向頂層變數,所以就可以獨立於不同的運行環境。

第四種寫法

但是,上面這樣寫可讀性較差,而且this的指向是可變的,容易出錯,所以進一步改寫:

複製代碼代碼如下:

var global = this;

if (!global.myObj) {

global.myObj = { };

}

用自定義變數global表示頂層對象,就清楚多了。

第五種寫法

還可以使用typeof運算符,判斷myObj是否有定義。

複製代碼代碼如下:

if (typeof myObj == “undefined”) {

var myObj = { };

}

這是目前使用最廣泛的判斷javascript對象是否存在的方法。

第六種寫法

由於在已定義、但未賦值的情況下,myObj的值直接等於undefined,所以上面的寫法可以簡化:

複製代碼代碼如下:

if (myObj == undefined) {

var myObj = { };

}

這裡有兩個地方需要注意,首先第二行的var關鍵字不能少,否則會出現ReferenceError錯誤,其次undefined不能加單引號或雙引號,因為這裡比較的是undefined這種數據類型,而不是”undefined”這個字元串。

第七種寫法

上面的寫法在”精確比較”(===)的情況下,依然成立:

複製代碼代碼如下:

if (myObj === undefined) {

var myObj = { };

}

第八種寫法

根據javascript的語言設計,undefined == null,所以比較myObj是否等於null,也能得到正確結果:

複製代碼代碼如下:

if (myObj == null) {

var myObj = { };

}

不過,雖然運行結果正確,但是從語義上看,這種判斷方法是錯的,應該避免。因為null指的是已經賦值為null的空對象,即這個對象實際上是有值的,而undefined指的是不存在或沒有賦值的對象。因此,這裡只能使用”比較運算符”(==),如果這裡使用”精確比較運算符”(===),就會出錯。

第九種寫法

還可以使用in運算符,判斷myObj是否為頂層對象的一個屬性:

複製代碼代碼如下:

if (!(‘myObj’ in window)) {

window.myObj = { };

}

第十種寫法

最後,使用hasOwnProperty方法,判斷myObj是否為頂層對象的一個屬性:

複製代碼代碼如下:

if (!this.hasOwnProperty(‘myObj’)) {

this.myObj = { };

}

總結

1. 如果只判斷對象是否存在,推薦使用第五種寫法。

2. 如果除了對象是否存在,還要判斷對象是否有null值,推薦使用第一種寫法。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/227468.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-09 16:30
下一篇 2024-12-09 16:30

相關推薦

  • Python周杰倫代碼用法介紹

    本文將從多個方面對Python周杰倫代碼進行詳細的闡述。 一、代碼介紹 from urllib.request import urlopen from bs4 import Bea…

    編程 2025-04-29
  • JS Proxy(array)用法介紹

    JS Proxy(array)可以說是ES6中非常重要的一個特性,它可以代理一個數組,監聽數據變化並進行攔截、處理。在實際開發中,使用Proxy(array)可以方便地實現數據的監…

    編程 2025-04-29
  • Python中引入上一級目錄中函數

    Python中經常需要調用其他文件夾中的模塊或函數,其中一個常見的操作是引入上一級目錄中的函數。在此,我們將從多個角度詳細解釋如何在Python中引入上一級目錄的函數。 一、加入環…

    編程 2025-04-29
  • Python字元串寬度不限制怎麼打代碼

    本文將為大家詳細介紹Python字元串寬度不限制時如何打代碼的幾個方面。 一、保持代碼風格的統一 在Python字元串寬度不限制的情況下,我們可以寫出很長很長的一行代碼。但是,為了…

    編程 2025-04-29
  • Python中capitalize函數的使用

    在Python的字元串操作中,capitalize函數常常被用到,這個函數可以使字元串中的第一個單詞首字母大寫,其餘字母小寫。在本文中,我們將從以下幾個方面對capitalize函…

    編程 2025-04-29
  • Python基礎代碼用法介紹

    本文將從多個方面對Python基礎代碼進行解析和詳細闡述,力求讓讀者深刻理解Python基礎代碼。通過本文的學習,相信大家對Python的學習和應用會更加輕鬆和高效。 一、變數和數…

    編程 2025-04-29
  • Python中set函數的作用

    Python中set函數是一個有用的數據類型,可以被用於許多編程場景中。在這篇文章中,我們將學習Python中set函數的多個方面,從而深入了解這個函數在Python中的用途。 一…

    編程 2025-04-29
  • 三角函數用英語怎麼說

    三角函數,即三角比函數,是指在一個銳角三角形中某一角的對邊、鄰邊之比。在數學中,三角函數包括正弦、餘弦、正切等,它們在數學、物理、工程和計算機等領域都得到了廣泛的應用。 一、正弦函…

    編程 2025-04-29
  • 單片機列印函數

    單片機列印是指通過串口或並口將一些數據列印到終端設備上。在單片機應用中,列印非常重要。正確的列印數據可以讓我們知道單片機運行的狀態,方便我們進行調試;錯誤的列印數據可以幫助我們快速…

    編程 2025-04-29
  • Python3定義函數參數類型

    Python是一門動態類型語言,不需要在定義變數時顯示的指定變數類型,但是Python3中提供了函數參數類型的聲明功能,在函數定義時明確定義參數類型。在函數的形參後面加上冒號(:)…

    編程 2025-04-29

發表回復

登錄後才能評論