如何延长作用域链_谈一谈javascript作用域

从今天开始研究讨论javascript作用域,感兴趣的同学请保持关注

什么是javascript作用域?

作用域是指程序源代码中定义变量的区域。
作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。 谈起javascript作用域你会想到哪些知识点?

函数作用域块级作用域闭包变量提升let 暂时性死区var let constthis一个变量的生命周期(从有到无)全局作用域局部作用域作用域链

等等,这些都是关于作用域的知识点,
我下载了几个源码,我们观察一些图片
jquery.js 

102e59765c514d03336468f8657ff59c.png

 vue.js 

4955a488ecb89c6e3596ec3da9d66892.png

axios.js 

bd0314e6dd75c8a07eb5a38e631c3b95.png

 上面的三个图,你会发现他们在结构上有一个共同点

(function(){

    //。。。代码

}('参数'))

为什么要这么设计?

我们看一个栗子?

let hisName = '郭靖'

function hero() {

  let herName = "黄蓉"

  let hisName = "洪七公"

  console.log(hisName);//=>洪七公

}

hero()

console.log(hisName);//=>郭靖

console.log(herName);//Uncaught ReferenceError: herName is not defined

输出

//=>洪七公

//=>郭靖

//Uncaught ReferenceError: herName is not defined

hero内部的hisName变量覆盖了外部的全局的hisName变量 ,hero外部无法访问hero内部的变量(hero内部的变量被保护起来,形成了私有变量) 

上面的栗子?做一下改动

let hisName = '郭靖'

function hero() {

  let herName = "黄蓉"

  function likeFun() {

    let like = '喜欢'

    console.log(`${herName}喜欢${hisName}`);//=>黄蓉喜欢郭靖

  }

  likeFun()

  console.log(like);//ReferenceError: like is not defined

}

hero()

输出

//=>黄蓉喜欢郭靖

//ReferenceError: like is not defined

通过上面的两个小栗子,我们可以得出以下结论:

内部可以访问外部变量,外部不可以访问内部变量 函数进行了嵌套,其实也是作用域进行了嵌套,js 会从内向外一层一层查找,找到后就返回,找不到就报错,形成了作用域链

一个栗子?

const element='123321'

const arr1 = [1, 2, 3, 4, 5]

const arr2 = ['a', 'b', 'c', 'd', 'e']

arr1.forEach(element => {

  console.log('element1:', element);

  arr2.forEach(element => {

    console.log('element2:', element);

  })

});

虽然可读性很差,但是当内部没有对外部进行引用时,这么写也是允许的, 

继续看一个栗子?

let a = 1;

let b = 2;

function add(x,y) {

  let a = 10;

  let b = 20;

  return a+b+x+y

}

function sum(x,y) {

  let a = 'a';

  let b = 'b'

  console.log(a+b+x+y);

}

console.log(add(a,b));//=>33

sum(a,b)//=>ab12

add 和sum两个函数,它们将内部逻辑和全局进行了隔离,尽管外部(全局)存在变量a和变量b,
但是对函数内部没有影响,拿add来说,函数add如何与window进行交流,
(当然,交流不是必须的)如果要交流,以参数作为输入,以return作为输出(联想一下import和export)

打印一下全局变量

console.log(window)

现在全局作用域下多了几个变量:add,sum 。a和b呢?
⚠️:let和const声明的变量不在window下,用var声明的变量会在window下,我们今天不讨论var

所以上面的栗子中的全局变量只有函数add和函数sum
当我们的项目越来越庞大的时候,过多的全局变量必然存在危险,首当其冲的就是变量的命名冲突,
或许你千方百计的对你的变量名称进行唯一化,命名了一些很长的,自认为不会引起冲突的名字,但是当你引入了第三方js库时,并且那个第三方库并没有妥善的处理自有变量,这时候依然存在命名冲突的风险,这并不能从根本上解决问题。
我们要最大限度的减少全局变量
现在我们对上面的栗子进行优化

function aFun(params) {

  let a = 1;

  let b = 2;

  function add(x, y) {

    let a = 10;

    let b = 20;

    return a + b + x + y

  }

  function sum(x, y) {

    let a = 'a';

    let b = 'b'

    console.log(a + b + x + y);

  }

  console.log(add(a, b)); //=>33

  sum(a, b) //=>ab12

}

aFun()

这样,add和sum就不在全局变量下了,有一个全局变量=>aFun,每次使用变量add和sum的时候需要调用aFun
再优化一下

(function aFun() {

//省略

})()

这样,aFun就不在全局作用域下了,不会引发全局变量污染,也不会引起命名冲突
如果你对上面的代码不理解,我们可以拆解一下

const aFun=function(){

    //省略

}

aFun()

aFun就是

function(){

    //省略

}

函数名后加一对()进行执行操作
我们比较一下两者区别

function aFun() {

    //省略

}

aFun()

//----------------

(function aFun(){

    //省略

}())

第一个,aFun在所在的作用域中(全局作用域),可以通过aFun进行调用
第二个,aFun在自己的函数表达式中,可以在自身内部调用,不能再外部调用

(function aFun(){

    //省略

    aFun()//可以在这里调用,小心递归死循环

}())

aFun()//这里调用会报错Uncaught ReferenceError: aFun is not defined

如果不会出现自己调用自己的情况可以直接使用匿名函数

(function (){

    //省略

}())

现在回头看下开篇的那三个js源码,他们都采用了这种方式进行封装,对自有变量和自有方法进行隔离,防止污染全局
今天的内容不难,你get到了吗

END

692bc29cd7e10babf3eb8318df36cdc7.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值