用域、作用域鏈、詞法作用域
在 Javascript 中,函數和對象都是變量,作用域決定了代碼不同部分的變量的可訪問性。
有趣的是,當我們開始更好地理解作用域時,我們可以在不同的作用域中使用相同的變量名,而不會發生任何沖突等等……
范圍分為三種,
全球范圍
在函數外部聲明的變量稱為全局范圍,我們可以從代碼的任何部分訪問這些變量。
這里要注意的是我們可以訪問在全局范圍內聲明的變量,在代碼的任何范圍內,如函數或塊范圍。
功能或本地范圍
在函數內部聲明的變量是局部作用域,我們無法在函數外部訪問這些變量,這些變量僅限于該特定函數。
var bikeName="Jarvis"; // declared in global scopefunction bikerDetails(){ var bikerName="TTF"; // declared in functional or local scope console.log(bikerName + " loves " + bikeName);
}bikerDetails();
在上面的代碼中,bikeName是在全局范圍內聲明的,我們可以從代碼的任何部分訪問bikeName,變量bikerName是在bikerDetails函數內部聲明的,我們不能從外部訪問bikerName。
塊范圍
這是在 ES6 中引入的,大括號稱為代碼塊,其中在塊內使用 let 和 const 聲明的變量只能在塊內訪問。
在 ES6 之前的傳統 javascript 中,在 var 中聲明的變量要么是函數作用域,要么是全局作用域,取決于它的聲明位置,因此當花括號塊不像其他語言那樣形成作用域時,這可能會非常棘手和混亂。
const raining=1;
if(raining){
var action="off the AC";
}else{
var action="let the AC run";
}
console.log(action);
在上面的 var 示例中,它是全局作用域,我們可以從代碼的任何部分訪問 var 操作,為了避免這種混淆,在 ES6 let 中,引入了 const 和塊作用域。
const raining=1;
if(raining){
let action="off the AC";
}else{
let action="let the AC run";
}
console.log(action);
在上面的代碼中,控制臺語句拋出了一個錯誤,因為變量 action 沒有在全局范圍內定義,我們試圖在塊范圍內定義的全局范圍內訪問 action 變量。
與 var 不同,let 和 const 的作用域是最近的花括號,但如果我們在代碼塊中聲明 var,我們可以從代碼的任何部分(如全局作用域)訪問該 var 變量。
{
var bikeName="Jarvis";
let bikerName="TTF";
}
console.log(bikeName); // jarvis
console.log(bikerName); // throws not defined error
在上面的代碼塊中,由于 let 的行為, bikerName 會拋出一個錯誤,就像 let const 一樣,行為是這樣的。
當我們在聲明時不將 var、let 或 const 放在變量的前綴中時,默認情況下它將作為 var 。
{
bikerFriend="Ajeesh Bro";
}
在上述場景中,變量 bikerFriend 的行為類似于 var 。
以上內容也適用于嵌套作用域,當前上下文的作用域可以訪問父作用域的變量,它會搜索到全局作用域的變量,如果在全局作用域中沒有找到該變量,那么它 引發參考錯誤,未定義。
嵌套范圍
讓我們考慮以下示例代碼,
const bikeName="Jarvis";
function printBikeDetails() {
function getBikerDetails() {
function getBikeName() {
return bikeName;
}
return getBikeName();
}
return getBikerDetails();
}
console.log(printBikeDetails()); // Jarvis
在上面的嵌套范圍中,我們從 getBikeName 函數返回了 bikeName 變量,其中 getBikeName 函數在自己的范圍內搜索變量,如果沒有找到,則在其父范圍或其外部范圍 getBikerDetails 中搜索,再次在父范圍中搜索 ,直到找到bikeNamevariable,它一直在父范圍內搜索,直到到達全局范圍。
要記住的主要事情是范圍是關于定義空間的,而不是關于調用空間的
上述在外部作用域中查找變量直至到達全局作用域的過程稱為作用域鏈。
詞匯環境
無論何時創建執行上下文 詞法環境也被創建,詞法環境是本地內存以及其父或外部范圍的詞法環境。
詞匯意味著層次或順序。
讓我們考慮這個例子,
const bikeName="Jarvis";
function printBikeDetails() {
function getBikerDetails() {
function getBikeName() {
return bikeName;
}
return getBikeName();
}
return getBikerDetails();
}
console.log(printBikeDetails()); // Jarvis
內部函數 getBikeName 可以訪問 getBikerDetails 的詞法環境,就像 getBikerDetails 可以訪問 printBikerDetails 的詞法環境一樣,其中 printBikerDetails 可以訪問全局范圍。
通過使用作用域鏈和詞法環境,當本地作用域中不可用時,我們可以從父作用域訪問變量。
關注七爪網,獲取更多APP/小程序/網站源碼資源!
年快樂,開工大吉。今天帶大家了解一個實用的CSS新特性:@scope規則。在Sass或Less這類CSS預編譯工具中嵌套語法較為常見,就像這樣,可以一定程度上簡化CSS代碼的書寫,讓層次結構更清晰。
@scope規則的作用與之類似,例如將剛才的Sass嵌套改為@scope規則書寫,就會是這樣,可以看到樣式按照正確的預期渲染了,這里的背景色成功渲染了。
@scope規則不會改變CSS選擇器的優先級,例如這里的@scope(nav)的優先級等同于nav,右邊的案例可以證明這一點。如果@scope(nav)不參與優先級計算,遵循后來居上的原則,上面這個鏈接的背景色應該是淺粉色,但事實沒有,說明@scope(nav)參與了優先級計算。
any-link是偽類選擇器,優先級大于任意的標簽選擇器,因此下面的鏈接的背景色是淺粉色。規范還提供了名為:scope的偽類,可以選擇規則自身的匹配,例如這里可以設置nav元素自身紅色邊框。
@scope規則還提供了排除語法,例如此例,通過to語法的設置讓p元素的子元素不參與nav匹配,因此p元素下的a元素就沒有背景色設置。
最后@scope規則還支持復雜選擇器,就像這樣的語法也是合法的。
以上就是本次分享的全部內容,如果你有任何疑問可以通過評論的方式進行反饋,我會一一解答,我們下個視頻再見。
端工程師最常見且最具挑戰性的問題之一是 CSS 命名約定。隨著 Block Element Modifier(BEM)方法的流行,許多人習慣于按照一種可維護的模式組織他們的樣式。
即將在 Chrome 瀏覽器中實施的 @scope 允許在樣式表中對樣式進行塊級作用域劃分,從而進一步提高了 BEM 的性能。這將使樣式表更易于維護,同時對 CSS 級聯進行更嚴格的控制。
在這篇文章中,我們將展示如何在 Chrome 中使用 @scope 特性,以及如何使用它來替換前端項目中的 BEM。我們通過幾個例子進行講解,你可以在 GitHub 上的示例項目中查看并跟隨操作。
在即將發布的 Chrome 118 版本中,@scope 特性創建了 CSS 樣式的塊級作用域。這給了開發者對 CSS 樣式更多的控制權,因為我們現在可以在 CSS 文件中直接為視圖的不同部分明確定義作用域。
請看下面的 HTML 示例:
<main className="sample-page">
<h1>With Scope</h1>
<section className="first-section">
<p>some text</p>
<p>
some text and then a <a href="/">back link</a>
</p>
</section>
<section className="second-section">
<h2>Dog Picture</h2>
<div>
<p>second section paragraph text</p>
</div>
<img src={'./DOG_1.jpg'} alt="dog" />
</section>
</main>
在此 HTML 中,我們可以使用以下方法對 second-section 樣式區域內的元素進行樣式設置:
.second-section {
display: flex;
flex-direction: column;
border: solid;
padding: 40px;
margin: 20px;
}
@scope (.second-section) {
h2 {
text-align: center;
}
img {
max-width: 400px;
max-height: 100%;
}
div {
display: flex;
justify-content: center;
margin: 20px;
}
p {
max-width: 200px;
text-align: center;
background-color: pink;
color: forestgreen;
padding: 10px;
border-radius: 20px;
font-size: 24px;
}
}
使用 @scope 時,還可以創建一個 "甜甜圈 "作用域,為一組樣式及其中的元素定義起始和結束部分。使用上述相同的 HTML,甜甜圈作用域可以定義從 sample-page 的起始區域到 second-section 樣式區域的樣式:
/* donut scope */
@scope (.sample-page) to (.second-section) {
p {
font-size: 24px;
background-color: forestgreen;
color: pink;
text-align: center;
padding: 10px;
}
a {
color: red;
font-size: 28px;
text-transform: uppercase;
}
}
最棒的是,它的功能與使用 BEM 造型非常相似,但代碼量更少。
截至2023年10月2日,CSS @scope 還未正式發布,因此需要開啟實驗性網絡功能標志來使用它。要做到這一點,首先在 Chrome 中打開一個標簽頁,前往 chrome://flags/,然后搜索并啟用“實驗性網絡平臺功能”標志:
BEM 是一種在HTML視圖中分組樣式的方式,可以輕松地進行導航。
考慮到一個大型 HTML 頁面有許多具有不同樣式的元素。在設置了幾個初始樣式名稱后,隨著頁面的擴展,要保持樣式就會變得很困難。BEM 試圖通過圍繞實際樣式來構建樣式名來緩解這一問題。
block 是一個包含 HTML 元素。考慮一下類似這樣的 HTML
<main className="sample-page">
<h1 className="sample-page__title">With BEM</h1>
<section className="sample-page__first-section">
<p className="sample-page__first-section--first_line">
some text
</p>
<p className="sample-page__first-section--second-line">
some text and then a{' '}
<a
className="sample-page__first-section--second-line-link"
href="/"
>
back link
</a>
</p>
</section>
</main>
在此 HTML 中
修改器 = 當在 <section> 元素中為 <p> 元素設計樣式時,樣式名稱會多出一個 --first-line ,從而創建 sample-page__first-section--first-line ,所以:
BEM 的擴展性很好,尤其是在使用 SASS 將樣式分組并使用 & 操作符創建類似內容時:
.sample-page {
display: flex;
flex-direction: column;
margin-top: 10px;
&__title {
font-size: 48px;
color: forestgreen;
}
&__first-section {
font-size: 24px;
border: solid;
padding: 40px;
margin: 20px;
&--first-line{
font-size: 24px;
background-color: forestgreen;
color: pink;
text-align: center;
padding: 10px;
}
}
}
難點在于,在一個大型項目中,這會產生非常大的 CSS 或 SASS 文件,而這些文件仍然很難進行大規模管理。可以使用 @scope 替換 BEM 樣式,使樣式定義更小、更易于管理。
展示使用 @scope 的優勢的最佳方式是在使用 React 等主流框架或庫的應用程序中使用 @scope。在 GitHub 上的示例應用程序中, react-example 文件夾中有一個項目,其中的頁面首先使用 BEM 進行了樣式設計,然后使用 @scope 進行了重構。
可以運行應用程序并單擊 WithBEM 或 WithScope 按鈕來查看具體實現。組件和樣式表都有相應的名稱,前綴為 WithBEM 或 WithScope ,分別位于 pages 和 styles 文件夾中。
從 BEM 樣式組件 WithBEMPage.tsx 開始,我們首先看到了用 BEM 方法設計的 HTML 樣式:
<main className="sample-page">
<h1 className="sample-page__title">With BEM</h1>
<section className="sample-page__first-section">
<p className="sample-page__first-section--first_line">
some text
</p>
<p className="sample-page__first-section--second-line">
some text and then a{' '}
<a
className="sample-page__first-section--second-line-link"
href="/"
>
back link
</a>
</p>
</section>
<section className="sample-page__second-section">
<h2 className="sample-page__second-section--title">
Dog Picture
</h2>
<div className="sample-page__second-section--div">
<p className="sample-page__second-section--div-paragraph">
second section paragraph text
</p>
</div>
<img
className="sample-page__second-section--image"
src={'./DOG_1.jpg'}
alt="dog"
/>
</section>
</main>
在組件 WithScopePage.tsx 中,我們可以通過以下內容看到重構是多么干凈利落:
<main className="sample-page">
<h1>With Scope</h1>
<section className="first-section">
<p>some text</p>
<p>
some text and then a <a href="/">back link</a>
</p>
</section>
<section className="second-section">
<h2>Dog Picture</h2>
<div>
<p>second section paragraph text</p>
</div>
<img src={'./DOG_1.jpg'} alt="dog" />
</section>
</main>
要將 BEM 重構為 @scope ,只需找到樣式組,然后適當添加您的作用域樣式。我們先來看看標題部分。在原始的 WithBEMPage.tsx 文件中,每個部分都定義了不同的樣式。而在 @scope 版本中,則為特定元素定義了更簡潔的樣式:
.sample-page {
display: flex;
flex-direction: column;
margin-top: 10px;
}
/* replaced */
/* .sample-page__title {
font-size: 48px;
color: forestgreen;
} */
/* donut scope */
@scope (.sample-page) to (.first-section) {
h1 {
font-size: 48px;
color: forestgreen;
}
}
同樣,在第一部分內容中,原始 BEM 風格如下:
.sample-page__first-section {
font-size: 24px;
border: solid;
padding: 40px;
margin: 20px;
}
.sample-page__first-section--first_line {
font-size: 24px;
background-color: forestgreen;
color: pink;
text-align: center;
padding: 10px;
}
.sample-page__first-section--second-line {
font-size: 24px;
background-color: forestgreen;
color: pink;
text-align: center;
padding: 10px;
}
.sample-page__first-section--second-line-link {
color: red;
font-size: 28px;
text-transform: uppercase;
}
用 @scope 重構第一部分,我們現在就有了一個更簡潔的樣式定義:
.first-section {
font-size: 24px;
border: solid;
padding: 40px;
margin: 20px;
}
/* donut scope */
@scope (.sample-page) to (.second-section) {
p {
font-size: 24px;
background-color: forestgreen;
color: pink;
text-align: center;
padding: 10px;
}
a {
color: red;
font-size: 28px;
text-transform: uppercase;
}
}
這樣做的另一個好處是,HTML 視圖更小,更容易閱讀。考慮到之前
<section className="sample-page__first-section">
<p className="sample-page__first-section--first_line">
some text
</p>
<p className="sample-page__first-section--second-line">
some text and then a{' '}
<a
className="sample-page__first-section--second-line-link"
href="/"
>
back link
</a>
</p>
</section>
然后
<section className="first-section">
<p>some text</p>
<p>
some text and then a <a href="/">back link</a>
</p>
</section>
通過這兩個示例組件,我們可以對每個部分進行重構。最終注意到它是如何使樣式更簡潔、更易讀的。
除了將 BEM 重構為 @scope 的優勢外,使用 @scope 還可以更好地控制 CSS 級聯。CSS 級聯是一種算法,它定義了網絡瀏覽器如何處理組成 HTML 頁面上元素的樣式條件。
在處理任何前端項目時,開發者可能需要處理由于樣式層疊而產生的奇怪結果。通過使用@scope,可以通過緊密限定元素范圍來控制層疊的副作用。
文件 no_scope.html 的樣式和一些元素定義如下:
<!DOCTYPE html>
<html>
<head>
<title>Plain HTML</title>
<style>
.light {
background: #ccc;
}
.dark {
background: #333;
}
.light a {
color: red;
}
.dark a {
color: yellow;
}
div {
padding: 2rem;
}
div > div {
margin: 0 0 0 2rem;
}
p {
margin: 0 0 2rem 0;
}
</style>
</head>
<body>
<div class="light">
<p><a href="#">First Level</a></p>
<div class="dark">
<p><a href="#">Second Level</a></p>
<div class="light">
<p><a href="#">Third Level</a></p>
</div>
</div>
</div>
</body>
</html>
結果如下:
這里的問題是,根據已定義的 CSS, Third Level 應為紅色文本,而不是黃色。這是 CSS 級聯的副作用,因為頁面樣式是根據外觀順序來解釋的,因此 Third Level 被認為是黃色而不是紅色。通過 Bram.us 原文中的圖表,我們可以看到 CSS 級聯評估選擇器和樣式的順序:
如果不使用 @scope ,CSS 級聯將直接從 "特定性 "轉為 "外觀順序"。使用 @scope 后,CSS 級聯將首先考慮 @scope 元素。您可以通過在示例中為 .light 和 .dark 樣式添加 @scope 來了解其效果。
首先,將原始 HTML 和 CSS 修改如下:
<!DOCTYPE html>
<html>
<head>
<title>Plain HTML</title>
<style>
.light {
background: #ccc;
}
.dark {
background: #333;
}
div {
padding: 2rem;
}
div > div {
margin: 0 0 0 2rem;
}
p {
margin: 0 0 2rem 0;
}
@scope (.light) {
:scope {
background: white;
}
a {
color: red;
}
}
@scope (.dark) {
:scope {
background: black;
}
a {
color: yellow;
}
}
</style>
</head>
<body>
<div class="light">
<p><a href="#">First Level</a></p>
<div class="dark">
<p><a href="#">Second Level</a></p>
<div class="light">
<p><a href="#">Third Level</a></p>
</div>
</div>
</div>
</body>
</html>
輸出結果如下
在本文中,我們探討了將 BEM 風格應用程序重構為使用 Chrome 瀏覽器中新推出的 @scope 功能的方法。我們介紹了 @scope 的工作原理,然后將一個簡單的頁面從 BEM 重構為 @scope 。
新的 @scope 功能有可能成為前端開發人員的一大優勢。不過,其他瀏覽器也必須實現支持,這可能需要時間。在此之前,這絕對是一個有趣的功能,對前端項目的樣式設計可能會有很大幫助。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。