用域、作用域链、词法作用域
在 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小时内与您取得联系。