12. JS高级-with、eval以及严格模式

该系列文章连载于公众号coderwhy和掘金XiaoYu2002中

  • 对该系列知识感兴趣和想要一起交流的可以添加wx:XiaoYu2002-AI,拉你进群参与共学计划,一起成长进步
  • 课程对照进度:JavaScript高级系列53-56集(coderwhy)
  • 后续JavaScript高级知识技术会持续更新,如果喜欢我们的文章,欢迎关注、点赞、转发、评论,大家的支持是我们最大的动力

脉络探索

  • 在本章节中,我们会补充完在本次课程系列中函数部分的最后一些碎片化内容,也就是with语句以及eval函数和严格模式
    • 这些内容,都能代表一部分JS语言一路发展的经历,我们不仅要了解,更会去探索这些内容为什么会被淘汰,为什么会被完善的原因

一、JS碎片知识补充

  • 在JS当中,往往有很多小块的内容,这些是阻拦我们深入学习的绊脚石,有很多小块内容的作用不在于使用,而在于学习其他内容是的触类旁通
    • 在这次的学习当中,我们就来学习其中的两小块,一个是with一个是eval,但不管是哪个,都是我们现在所不提倡使用的,作为一个了解,补足知见就OK

1.1. with语句

  • with 语句在 JavaScript 中是一个较为古老且具有争议的特性,它的目的是为了简化多次写入同一个对象的属性时的代码
    • 然而,JavaScript 的原始版本是在非常短的时间内设计出来的,这意味着很多设计决策都是出于快速实现功能的考虑,而非长远的语言健全性。这在早期的 JavaScript 中造成了许多设计上的缺陷,而with 语句就是因为这原因而产生几个明显问题
    • 最致命的问题在于:with 语句会创建自己的作用域,其中包含的变量可以指向传入的对象的属性,也可以指向外部作用域的变量(优先考虑传入的对象属性)。这种行为很容易造成混淆,特别是当对象属性和外部变量同名时,很难判断代码的真正意图,如图12-1
  • 由于我们不可能再去使用with语句(写法和函数一样),所以在学习函数的时候,才会说函数和全局是目前会产生作用域的内容
var obj = {
  name:"小余",
  age:18
}
var obj2 = {
  name:"coderwhy",
  age:35
}
with(obj){
  console.log(name)
  console.log(age)
}
with(obj2){
  console.log(name)
  console.log(age)
}

API语法参数分类

图12-1 with形成作用域

  • 不过with语句所想要达成的简化多次写入同一个对象的属性时的代码,在后续可以通过ES6之后的语法解构进行实现
    • 所以说JS这门语言一直在变得更好,是值得我们去学习投资的

1.2. eval函数

  • eval函数的出现和落幕也跟with语句是相似的
    • eval是一个特殊的函数,它可以将传入的字符串当做JavaScript代码来运行
  • 而之所以不在开发中进行使用的原因是:
    • eval代码的可读性非常的差(代码的可读性是高质量代码的重要原则)
    • eval 可以执行任何 JavaScript 代码,这意味着恶意代码也可能被执行。如果被用来执行用户输入的代码,可能会导致跨站脚本攻击(XSS)等安全问题
    • eval的执行必须经过JS解释器生成,不能被JS引擎优化,从效率和性能角度来说,就会差上很多
    • 通过 eval 执行的代码可能难以调试,因为它是动态生成的,可能不容易追踪到源代码位置
var evalString = `var message = "Hello World;console.log(message)"`
eval(evalString)
console.log(message)
  • 而这些代码为什么没有被废弃,直到今天也依旧可以使用,也是有重要原因的
    • 作为 Web 开发中最核心的脚本语言,JavaScript 需要在全球范围内广泛的浏览器和设备上保持运行的兼容性。这限制了对旧有缺陷进行根本修复的可能性,因为修复这些缺陷可能会破坏大量现有的网站和应用
    • 而这也是为什么每年ECMAScript系列发布新的API的时候,除了ECMAScript 2015(ES6)之外,往后每一年直到ES15,基本上都是挤牙膏的原因
    • 在没有确定下来之前,是不会进行大幅度改动的,因为每一次的改动,都算得上不可逆的。一旦打算废弃,所花费的代价是非常大的,所以更常用的做法是让时间去掩埋其中存在的痕迹,这也是我们对于这些内容产生陌生的原因
  • 但因为这个原因,所以JS目前的内容是非常稳固的,学习之后,在未来很多年都不会失去收益。而各种框架和第三方库就相对不稳定多了,无时无刻不再快速迭代,所带来的负面作用则是会偶尔产生破坏性的更新
    • 这种更新通常是大版本更新,因为各种同类竞争严重所产生的效果,内容繁多,也是大多数人学习非常累的原因
    • 学习没多久的内容就会落伍,就会失去效益,就像是吊在眼前的萝卜,诱人但直到失去力气都吃不到的东西。产生的原因就来自于我们自身
    • 所以需要通过学习其中相对稳定的内容,从这稳定的思维图式去延伸到新颖、前沿、不确定的内容上去

层出不穷的技术如眼前的胡萝卜

图12-2 层出不穷的技术如眼前的胡萝卜

二、严格模式

严格模式(strict mode)是JavaScript语言的一个功能,目的是让代码运行在一个更严格的语法和行为环境中

2.1. 认识严格模式

2.1.1. 开启严格模式
  • 那么如何开启严格模式呢?严格模式支持粒度话的迁移:
    • 可以支持在js文件中开启严格模式
    • 也支持对某一个函数开启严格模式;
  • 严格模式通过在文件或者函数开头使用 “use strict ” 来开启,如图12-4

API语法参数分类

图12-4 开启全局严格模式

"use strict"


var name = "abc"
console.log(name)


var message = "Hello World"
console.log(message)
function foo(){
    "use strict";
    
    m = "foo"
    console.log(m)
}

foo()
  • 通过这两种方式,其实我们是可以猜到严格模式的运行范围的
    • 作用域范围,即是严格模式的生效范围
    • 在全局就所有地方生效,在函数作用域就该函数内生效
    • 但不管是哪一种方式,都需要写在作用域的最上面
  • 在全局开启严格模式,这种方式存在陷阱,我们不能盲目地合并冲突代码
    • 试想合并一个严格模式的脚本和一个非严格模式的脚本:合并后的脚本代码看起来是严格模式
    • 反之亦然:非严格合并严格看起来是非严格的。合并均为严格模式的脚本或均为非严格模式的都没问题,只有在合并严格模式与非严格模式有可能有问题
    • 建议按一个个函数去开启严格模式(至少在学习的过渡期要这样做)

2.2. 严格模式限制

这里我们来说几个严格模式下的严格语法限制:

  • JavaScript为了让新手开发者更容易上手,所以有时候本来错误语法,被认为也是可以正常被解析的
  • 但是这种宽松的设计方式可能给以后留下安全隐患
  • 而在严格模式下,这种失误就会被当做错误,以便可以快速的发现和修正
    • 之所以不直接将严格模式替换为默认的JS运行环境,还是因为我们之前说的原因,改变几乎是不可逆的,一旦将严格模式设置为默认情况,之前的很多老代码都将无法运行,这是不能接受的事情,也是全局开启严格模式所存在的陷阱
    • 所以才需要将严格模式设置为可选的情况,拔高这门语言的上限,从这个角度看,过于自由的语言会带来较为严重的隐患,但在一门语言的发展中,是不可避免会出现的事情
    • 随着发展的推移,设计得严谨,就会像C++中的内容变得非常繁琐冗余,设计得宽松则会像JS出现各种缺陷。新的语言诞生会吸收以往的教训,形成在当下更好的形式,并且以极快的速度发展,但当新语言成为前沿者,没有其他教训可以参考的时候,也会走上这条权衡利弊的道路,去摸索其中的平衡点
    • 所以,不需要纠结要不要学习最新的语言,而是应当根据自己的需求去学习。避免被潮流所淹没思考,但至少就前端来说,只有一门JS语言以及它的超集TS语言,如果要学习前端,就不至于去纠结这些问题
  • 市场上仍然有大量的浏览器版本只部分支持严格模式或者根本就不支持,所以使用的时候,不要盲目依赖
2.2.1. 限制内容

无法意外地创建全局变量

  • 非严格模式下,如果一个变量没有被声明(即没有使用var, let, const),它会自动成为全局变量,这种声明方式我们之前说过是隐式声明。这增加了全局污染的风险,代码会更难维护和理解
  • 严格模式下,如果尝试使用未声明的变量,JavaScript会抛出错误,从而发现并修正这种潜在的错误

严格模式会使引起静默失败的赋值操作抛出异常

  • 非严格模式下,某些赋值失败(如尝试写入只读属性)不会报错,只是静默失败
  • 严格模式改变了这一行为,这类赋值失败也会抛出异常,从而即时通知开发者问题的存在,增加代码的透明度和可预测性

严格模式下试图删除不可删除的属性

  • 非严格模式下,删除一个不可配置(non-configurable)的属性时不会报错,只是操作无效
  • 严格模式下,这种操作会抛出错误,提醒开发者这一行为是不允许的,避免错误预期

严格模式不允许函数参数有相同的名称

  • 允许重名的参数可以导致代码逻辑混乱,难以理解和错误的参数值使用
  • 严格模式禁止这种情况,确保函数的参数列表的清晰和一致性

不允许0开头的八进制语法

  • 非严格模式下,以0开头的数字被视为八进制数。这种语法在某些情况下可能导致混淆和错误
  • 严格模式中,八进制必须明确使用新的0o0O前缀,提高代码的清晰度

在严格模式下,不允许使用with

  • with语句可以改变代码块的作用域链,增加运行时错误的风险,并且使得代码更难优化和分析
  • 在严格模式下禁用with,以便保持作用域的清晰和代码的可优化性

在严格模式下,eval不再为上层引用变量

  • 非严格模式下,eval可以修改它的调用环境的作用域
  • 严格模式中,eval有自己的作用域,不影响外部作用域,这样增加了代码的安全性和模块化

严格模式下,this绑定不会默认转成对象

  • 非严格模式下,函数中的this如果是基本类型(如数字或字符串),会自动转换为对应的对象
  • 严格模式下,this保持原有的值(如果没有明确的对象绑定,this值为undefined),这样减少了意外的类型转换,使得函数行为更加可预测

这些是限制内容是最常见的类型,不需要刻意去记,只需要了解就行




message = "Hello World"
console.log(message);

function foo(){
    age = 18
}
foo()
console.log(age);


function foo(x,y,x){
    console.log(x,y,x);
}
foo(10,20,30)


true.name = "xiaoyu"
NaN = 123
var obj = {}
Object.defineProperty(obj,'name',{
    configurable:false,
    writable:false,
    value:"why"
})
console.log(obj.name)
obj.name = "xiaoyu"


var num = 0123
var num2 = 0x123
var num3 = 0b100
console.log(num,num2,num3)


var jsString = "var message = 'Hello World';console.log(message)"
eval(jsString)
console.log(message)
2.2.2. 严格模式下的this
"use strict"

function foo1(){
    console.log("foo1",this);
}

function foo2(){
    console.log("foo2",this);
    foo1()
}

function foo3(){
    console.log("foo3",this);
    foo2()
}

foo3()

API语法参数分类

图12-5 严格模式下的this结果

  • 包括说,在自执行函数中,我们如果使用this.localStorage.setItem来使用全局的方法,也可以直接localStorage.setItem,会自动找到全局中的方法
"use strict"

function foo(){
    console.log(this)
    
    localStorage.setItem
} 
foo()


setTimeout(()=>{
    console.log(this)
},2000)

setTimeout(function(){
    console.log(this)
},2000)


定时器中的cake对特殊情况this的处理

图12-6 定时器中的cake对特殊情况this的处理

后续预告

  • 在补充完这些内容之后,我们的函数学习之旅其实就告一段落了
    • 在JS当中,除了函数之外,最重要的其实就是对象了
    • 对象的重要性几乎无法被过分强调,因为对象本身就是JavaScript的核心概念之一,几乎所有在JavaScript中的操作和应用都与对象密切相关,包括我们之前的使用中就处处都是对象
    • 严格的来说,函数也是一种特殊对象
  • 而接下来,我们将深入对象的学习之旅
    • 而通过回顾第一篇章的JS高级课程思维导图中,也可以先进行推测我们需要学习的内容
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=21333,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?