思维脑图+代码示例让作用域到作用域链的知识点一目了然!
作用域
作用域的篇幅不会太长,作为自己对Js总结的第三篇文章,主要是承上启下。
之后会涉及到执行上下文,闭包等相关专题,为了避免内容过多,作用域这一部分单独总结。
目录
- 前言
- 一、作用域的定义
- 二、理解作用域
- 三、作用域链
- 四、思考与总结
五、写在最后
(免费学习推荐:javascript视频教程)
前言
JavaScript内功系列:
- this指向详解,思维脑图与代码的结合,让你一篇搞懂this、call、apply。系列(一)
- 从原型到原型链,修炼JavaScript内功这篇文章真的不能错过!系列(二)
- 本文
一、作用域的定义
一张导图概括本节内容
注意:除了作用域,在此送大家2020最新企业级 Vue3.0/Js/ES6/TS/React/Node等实战视频教程,点击此处免费获取,小白勿进哦
1.1 常见的解释
- 一段程序代码中所用到的名字并不总是有效,而限定它的可用性的范围就是这个名字的作用域;
- 作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限;
- 通俗的讲作用域就是一套规则,用于确定在何处以及如何查找某个变量的规则
function func(){ var a = 100; console.log(a); // 100}console.log(a) // a is not defined a变量并不是任何地方都可以被找到的
1.2 JavaScript中作用域工作模型
JavaScript 采用是词法作用域(lexical scoping),也就是静态作用域:
- 函数的作用域在函数定义的时候就决定了
与之对应的还有一个动态作用域:
- 函数的作用域是在函数调用的时候才决定的;
1.3 全局变量和局部变量
根据定义变量的方式又可以分为:
局部变量:只能在函数中访问,该函数外不可访问;
- 定义在函数中的变量
function fn(){ var name = '余光'; console.log(name);}console.log(name); // ?fn(); // ?
全局:任何地方都能访问到的对象拥有全局作用域。
- 函数外定义的变量
- 所有末定义直接赋值的变量自动声明为拥有全局作用域
var a = 100;console.log('a1-',a);function fn(){ a = 1000; console.log('a2-',a);}console.log('a3-',a);fn();console.log('a4-',a);
注意:在ES6之后又提出了块级作用域,它们之间的区别我们之后再来讨论。
二、理解作用域
根据第一节的描述,我们一一验证一下
2.1 理解词法作用域
var value = 1;function foo() { console.log(value);}function bar() { var value = 2; foo();}bar();
我们结合定义去分析:
- 执行
bar
函数,函数内部形成了局部作用域; - 声明value变量,并赋值2
- 执行
foo
函数,函数foo的作用域内没有value
这个变量,它会向外查找 - 根据词法作用域的规则,函数定义时,
foo
的外部作用域为全局作用域 - 打印结果是1
如果是动态作用域的话:结果就是2,不知道你是否想明白了?
2.2 全局变量
var str = '全局变量';function func(){ console.log(str+1); function childFn(){ console.log(str+2); function fn(){ console.log(str+3); }; fn(); }; childFn();}func();// 全局变量1// 全局变量2// 全局变量3
再来分析下面的代码:
var a = 100;function fn(){ a = 1000; console.log('a1-',a);}console.log('a2-',a);fn();console.log('a3-',a);// a2- 100 // 在当前作用域下查找变量a => 100// a1- 1000 // 函数执行时,全局变量a已经被重新赋值// a3- 1000 // 全局变量a => 1000
2.3 局部作用域
局部作用域一般只在固定的代码片段内可访问到,最常见的就是以函数为单位的:
function fn(){ var name="余光"; function childFn(){ console.log(name); } childFn(); // 余光}console.log(name); // name is not defined
三、作用域链
3.1 当查找变量的时候都发生了什么?
- 会先从当前上下文的变量对象中查找;
- 如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找;
- 一直找到全局上下文的变量对象,也就是全局对象;
- 作用域链的顶端就是全局对象;
这样由多个执行上下文的变量对象构成的链表就叫做作用域链,从某种意义上很类似原型和原型链。
3.2 作用域链和原型继承查找时的区别:
- 查找一个普通对象的属性,但是在当前对象和其原型中都找不到时,会返回
undefined
- 查找的属性在作用域链中不存在的话就会抛出
ReferenceError
。
3.3 作用域嵌套
既然每一个函数就可以形成一个作用域(词法作用域
|| 块级作用域
),那么当然也会存在多个作用域嵌套的情况,他们遵循这样的查询规则:
- 内部作用域有权访问外部作用域;
- 外部作用域无法访问内部作用域;(真是是这样吗?)
- 兄弟作用域不可互相访问;
在《你不知道的Js》中,希望读者可以将作用域的嵌套和作用域链想象成这样:
四、思考与总结
4.1 总结
4.2 思考
最后,让我们看一个《JavaScript权威指南》中的两段代码:
var scope = "global scope";function checkscope1(){ var scope = "local scope"; function f(){ return scope; } return f(); // 注意}checkscope1();var scope = "global scope";function checkscope2(){ var scope = "local scope"; function f(){ return scope; } return f;}checkscope2()();
两段代码的结果都是"local scope",书中的回答是:JavaScript 函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量 scope 一定是局部变量,不管何时何地执行函数 f(),这种绑定在执行 f() 时依然有效。
但是它们内部经历的事情是一样的吗?
相关免费学习推荐:javascript视频教程
Atas ialah kandungan terperinci 思维脑图+代码示例让作用域到作用域链的知识点一目了然!. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

typedef struct digunakan dalam bahasa C untuk mencipta alias jenis struktur untuk memudahkan penggunaan struktur. Ia alias jenis data baharu kepada struktur sedia ada dengan menentukan alias struktur. Faedah termasuk kebolehbacaan yang dipertingkatkan, penggunaan semula kod dan pemeriksaan jenis. Nota: Struktur mesti ditakrifkan sebelum menggunakan alias itu mestilah unik dalam program dan hanya sah dalam skop di mana ia diisytiharkan.

Pengecualian nilai jangkaan pembolehubah dalam Java boleh diselesaikan dengan: memulakan pembolehubah menggunakan nilai nol menggunakan semakan dan tugasan;

Arahan prapemproses #include dalam C++ memasukkan kandungan fail sumber luaran ke dalam fail sumber semasa, menyalin kandungannya ke lokasi yang sepadan dalam fail sumber semasa. Digunakan terutamanya untuk memasukkan fail pengepala yang mengandungi pengisytiharan yang diperlukan dalam kod, seperti #include <iostream> untuk memasukkan fungsi input/output standard.

Kelebihan penutupan JavaScript termasuk mengekalkan skop pembolehubah, membolehkan kod modular, pelaksanaan tertunda, dan keburukan pengendalian peristiwa termasuk kebocoran memori, peningkatan kerumitan, overhed prestasi dan kesan rantaian skop.

Kitaran hayat penunjuk pintar C++: Penciptaan: Penunjuk pintar dicipta apabila memori diperuntukkan. Pemindahan pemilikan: Pindahkan pemilikan melalui operasi pemindahan. Keluaran: Memori dikeluarkan apabila penunjuk pintar keluar dari skop atau dikeluarkan secara eksplisit. Pemusnahan objek: Apabila objek runcing dimusnahkan, penunjuk pintar menjadi penunjuk tidak sah.

Dalam JavaScript, jenis penunjuk ini termasuk: 1. Objek global 2. Panggilan fungsi; 4. Pengendali acara; Selain itu, penunjuk kepada ini boleh ditetapkan secara eksplisit menggunakan kaedah bind(), call(), dan apply().

boleh. C++ membenarkan definisi dan panggilan fungsi bersarang. Fungsi luaran boleh menentukan fungsi terbina dalam, dan fungsi dalaman boleh dipanggil terus dalam skop. Fungsi bersarang meningkatkan enkapsulasi, kebolehgunaan semula dan kawalan skop. Walau bagaimanapun, fungsi dalaman tidak boleh mengakses pembolehubah tempatan fungsi luaran secara langsung, dan jenis nilai pulangan mesti konsisten dengan pengisytiharan fungsi luaran Fungsi dalaman tidak boleh rekursif sendiri.

Penutupan dalam Java membenarkan fungsi dalaman mengakses pembolehubah skop luar walaupun fungsi luar telah keluar. Dilaksanakan melalui kelas dalaman tanpa nama, kelas dalam memegang rujukan kepada kelas luar dan memastikan pembolehubah luar aktif. Penutupan meningkatkan fleksibiliti kod, tetapi anda perlu sedar tentang risiko kebocoran memori kerana rujukan kepada pembolehubah luaran oleh kelas dalaman tanpa nama memastikan pembolehubah tersebut hidup.
