js最基础的作用域问题
1、什么是作用域?
每个变量和函数,都有其作用的范围,超出这个范围,就不能使用了,这个范围就叫做“作用域”,我们举个例子,一个文件中的变,在另一个文件中直接访问,是访问不到的,两个文件是两个“域”,两个文件中的私有量,另一个文件无法访问,因为超出了“域”。
2、我们想用另一个文件中的变量,怎么办?把两个文件合并到一起吧,是不是就可以用了?我们可以把两个文件称为“局部作用域”,把合并后的文件称为“全局作用域”。如果在函数内部,我们直接使用一个量,例如下面的例子,在test中直接使用a,程序会先在test中查找,不管是在使用a前,还是在使用a后,函数内部只要定义了a,那么程序就认为,a现在是局部作用的,不用再“提升”到全局去查找了,由于这个例子实在后面定义的,这时alert(a) // undefined。如果,test函数内部从前到后,并没有定义变量a,这时程序在test内找不到var a = xxxx,才会把查找a定义的过程放大到全局,发现全局定义了var a = 'aa',这时alert(a) // aa。这个查找的过程的顺序,叫做“作用域链”。
函数可以自动“预解析”,即便是在使用函数的语句后面定义,也可以把函数定义先解析,再使用。
var a = "aa"
function test() {
alert(a) // undefined, 在函数内部,找到了定义,所以不会往上层去找,但是还没有执行到,所以undefined
var a = 'bb'
alert(a) // 找到局部作用域,且有值,返回“bb”
}
test()
alert(a) // 在全局作用下找到的a = "aa", 直接返回
test() // 和上次执行的结果一致,不受第一次执行的影响 //相当于这样写:
var a = "aa"
function test() {
var a //定义提前
alert(a)
var a = 'bb' //赋值不变
alert(a)
}
test()
alert(a)
function test2() {
b() // 函数可以“预解析”,正确执行
var a = 1
function b() {
console.log(1)
console.log(a) // undefined,找到了定义在下面的a,不再往外层找
var a = 2 // 内层函数的a定义
}
console.log(a) // 外层函数的a
}
test2() // 1 undefined 1
再来看一个例子:(内部可以访问外部,但外部的不能访问内部的 )
var a=10;
function aaa(){
alert(a);
};
function bbb(){
var a=20;
aaa();
}
bbb(); //结果为10,在bbb中执行aaa,相当于aaa自己直接调用,此时调用aaa的this指向window
// 所以无法往下层去找变量,访问不到bbb()里面的局部变量,所以访问到的是全局的a=10。不要被写在bbb中迷惑了
继续上例子:(只要不是用var (ES6-),就会定义成全局变量)
function aaa(){
a=10;
}
aaa();
alert(a); //结果为10;
//等价于:
var a;
function aaa(){
a=10;
};
aaa();
alert(a);
再来一个:
function aaa(){
a=10;
}
alert(a); // 报错,虽说不写var,可以成为全局变量,但是要先调用函数,经过aaa的使用,才可以成为全局的,否则aaa不使用,外面的谁也别想用
// 改成这样,就成为全局变量了:
function aaa(){
a=10;
}
aaa()
alert(a);
更上一层楼:
var i = 10 // 全局变量
function a() {
i = 20 // 局部变量
console.log(i) //
for (var i = 0; i < 6; i++) {
console.log(i) // 0-5
}
console.log(this.i) // 执行a(),相当于window.a(),当前this指向window,所以是全局变量10
console.log(i) // 6: 0-5之后,i++ => 6
}
a()
console.log(i) // 全局变量10
高级点的:
var x = 1
function a() {
console.log(x)
setTimeout(() => {
console.log(x, "SetTimeut")
})
new Promise(resolve => {
console.log(x, "Promise")
resolve()
console.log(2)
}).then(() => {
console.log(x, 'then')
})
var x = 'hello world'
console.log(x)
}
a()
// undefined , undefinde "Promise", 2, hello word,
// hello word "then", hello world 'setTimeout'
再高级一点: with语句作用域分析:MDN中给出with的解释是:扩展一个语句的作用域链。JavaScript查找某个未使用命名空间(可以理解为未定义)的变量时,会通过作用域链来查找,作用域链是跟执行代码的context(当前作用域)或者包含这个变量的函数有关。'with'语句將某个对象添加到作用域链的顶部,如果在statement(with内部语句)中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出ReferenceError异常。
with (expression) {
statement
}
function f(x, o) {
with (o)
print(x);
}
f被调用时,x有可能能取到值,也可能是undefined,如果能取到, 有可能是在o上取的值,如果o中没有这个属性的话,就去取函数的第一个参数x的值。如果你忘记在作为第二个参数的对象o中定义x这个属性,程序并不会报错,只是取到另一个值而已。
function f(foo, values) {
with (foo) {
console.log(values)
}
}
如果是在ECMAScript 5环境调用f([1,2,3], obj),则with语句中变量values将指向函数的第二个参数values。但是,ECMAScript 6标准给Array.prototype添加了一个新属性values,所有数组实例将继承这个属性。所以在ECMAScript 6环境中,with语句中变量values将指向[1,2,3].values。
看个例子:
var a = 1
function f() {
var o = {a: 3}
with (o) {
console.log(a); // 现在a在函数内部未定义,但是with依然可以去参数中查找,发现o中有a属性,不再去全局查找,所以要取o.a = 3
var a = 2 // 因为o中有a,所以 这里的a 指向 o.a
console.log(o.a) //
console.log(a) // 这里的a 也是指o.a
}
}
f()
js最基础的作用域问题的更多相关文章
- JS基础学习——作用域
JS基础学习--作用域 什么是作用域 变量的作用域就是变量能被访问到的代码范围,比如在下面的这个js代码中,变量a的作用域就是函数foo,因此在全局作用域内的console.log(a)语句不能访问到 ...
- JS基础语法---作用域
作用域:使用范围 全局变量: 声明的变量是使用var声明的, 那么这个变量就是全局变量 全局变量可以在页面的任何位置使用 除了函数以外, 其他的任何位置定义的变量都是全局变量 局部变量:在函数内部定义 ...
- css+js+html基础知识总结
css+js+html基础知识总结 一.CSS相关 1.css的盒子模型:IE盒子模型.标准W3C盒子模型: 2.CSS优先级机制: 选择器的优先权:!important>style(内联样式) ...
- 对js中闭包,作用域,原型的理解
前几天,和朋友聊天,聊到一些js的基础的时候,有一种‘好像知道,好像又不不知道怎么讲的感觉’...于是捡起书,自己理一理,欢迎拍砖. 闭包 理解闭包首先要理解,js垃圾回收机制,也就是当一个函数被执行 ...
- JS中变量、作用域的本质,定义及使用方法
全局作用域和局部作用域 全局作用域 局部作用域:函数作用域 全局作用域在全局和局部都可以访问到,局部作用域只能在局部被访问到 var name="cyy"; function fn ...
- node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法
1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...
- 6个函数的output看JS的块级作用域
1. var output = 0; (function() { output++; }()); console.log(output); 函数对全局的output进行操作,因为JS没有块级作用域,所 ...
- Node.js系列基础学习----安装,实现Hello World, REPL
Node.js基础学习 简介 简单的说 Node.js 就是运行在服务端的 JavaScript.Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台.Node.js是一 ...
- [JS] javascript基础语法
W3CSchool全套Web开发手册:点击下载 1.javascript是什么 js是具有面向对象能力的,解释性的程序设计语言. 2.js的类型 [基本类型]:string number boolea ...
随机推荐
- git 遇到的问题
1.error: RPC failed; curl transfer closed with outstanding read data remaining 解决办法: git clone https ...
- MTK平台环境搭建---Ubuntu Linux 下执行sudo apt-get install提示“现在没有可用的软件包……
问题描述: sudo apt-get install openssh-server 正在读取软件包列表... 完成正在分析软件包的依赖关系树 Reading state information... ...
- [设计模式]访问者 Visitor 模式
访问者模式是对象的行为模式. 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变.
- Java集合(5):HashSet
存入Set的每个元素必须是惟一的,因为Set不保存重复元素.加入Set的元素必须定义equals()方法以确保对象的唯一性.Set不保证维护元素的次序.Set与Collection有完全一样的接口. ...
- 转:[NHibernate]视图处理
转自:http://www.cnblogs.com/wolf-sun/p/4082899.html 目录 写在前面 文档与系列文章 视图 一个例子 总结 写在前面 前面的文章主要讲了对物理数据表的操作 ...
- PL/SQL编程—视图
create or replace view test_view as select TestA.id, TestB.idno, TestB.name, TestB.sex from TestB le ...
- 62二叉搜索树的第k个结点
题目描述 给定一颗二叉搜索树,请找出其中的第k大的结点.例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4. 思路 二叉搜索树的中序遍历的输出结果是拍好序 ...
- Spark机器学习6·聚类模型(spark-shell)
K-均值(K-mean)聚类 目的:最小化所有类簇中的方差之和 类簇内方差和(WCSS,within cluster sum of squared errors) fuzzy K-means 层次聚类 ...
- 毕业一年后的java面试总结
前言 目前公司闲,没有新产品开发,都是一些维护工作,于是我提出了离职,开始了面试之路,抱着一个面试就是学习的心态去面试的,当然了,也是希望能拿到大公司的offer,大概面试了一个月左右的时间!!! ...
- 编写Tesseract的Python扩展
Tesseract是一个开源的OCR(光学字符识别)引擎,用于识别并输出图片中的文字.虽然和商业软件比起来识别精度不算很高,但是如果你要寻找免费开源的OCR引擎,可能Tesseract就是唯一的选择了 ...