作用域
什么是作用域?
一个变量的可用范围
避免函数内外(作用域)的变量之间互相干扰
作用域分为两种:
- 全局作用域:window对象
保存着所有的全局变量
随处可用
可反复使用
极易被污染 - 函数作用域:
函数内的范围成为函数作用域
出了函数{ }不能使用
不能重复使用
//全局作用域
var a = 10;
function fun (){
//函数内的范围成为函数作用域 (局部变量)
var a = 100;
a++;
console.log(a) //这里的a输出是101
}
fun()
console.log(a); //这里的a输出是10
函数生命周期
一个函数从创建,到调用,最后到调用完所经历的阶段。
定义函数时:
- 创建函数对象
- 创建函数变量名,保存函数对象的地址
调用函数时:
- 临时创建本次函数调用的函数作用域对象
- 在函数作用域对象中,创建本次函数所需的所有局部变量
①在函数内 var定义的变量
②形参定义的变量 (形参变量虽然没有 var ,但是也属于局部变量) - 在函数执行过程中 函数优先使用局部变量 没有的话去找全局变量
函数调用后(函数执行完):
- 释放函数作用域对象
- 导致函数作用域对象中的局部变量也跟着被释放了
(意味着 函数作用域的变量 也就是局部变量都不可重复使用)
按值传递
什么是按值传递?
在两个变量间赋值时,或者 将变量作为参数掺入函数时,其实只是将原变量的值复制一个副本 给对方变量。 (只要是赋值都存在按值传递!!!)
赋值的使用情况:
① 变量赋值 a=10
② 函数传参赋值 function fun ( a, b){
a=3;
b=5;
};
add(3,5)
③对象的属性赋值(:冒号赋值) var lilei={
sname:"Li Lei"
}
④ 双向绑定(vue中) :titel="title"
注:
修改副本,不会影响原来的值?
如果传递的是原始类型的值,在函数中修改新变量,不会影响到原变量的值
如果传递的是引用类型的值,因为复制的是地址值,造成了两个变量引用同一个对象,所以 任何一方修改都会受影响
两个变量间赋值时:(以下传递的是原始类型的值)
var h = 10;
var i = h; //按值传递
//=右边的赋值其实是将原来变量中的值(var h = 10)再复制一个副本,给i变量 此时i 的值也为10 (内存中会有两个10) 但是是副本 所以不对原来的h造成影响 (也就是对原始类型的值来说 修改变量中的副本 不影响原来的变量)
i++;
console.log(h) //h 的输出依然为10
两个变量间赋值时:(以下传递的是引用类型的值)
var xiaoming = ["包子","包子","包子","包子"] //定义一个数组 假设小明有四个包子
var xiaohong = xiaoming //此时赋值 因为是引用类型的值,并不会把数组的值直接创建一个副本给
xiaohong变量 而是把数组内存中引用的地址给xiaohong变量,
此时xiaohong得到的副本是地址值 而不是 实际数组 !!!
因为内存中两个地址指向的都是一个内容 ["包子","包子","包子","包子"]
那么xiaohong.pop()吃掉了一个包子 此时内容为 ["包子","包子","包子"]
就是3个包子,那么最后地址中引用的就会是三个包子
xiaohong.pop(); //假设小红此时吃掉了一个包子
console.log(xiaoming.length) // 3
将变量作为参数传入函数时:
var d = 10;
function fun (d){
//副本10
d++;
console.log(d) // 11
}
fun(d); //传参d相当于给形参变量赋值 也就是再fun(){ }里边 var d; 也就会形成按值传递
//那么就将全局变量中的d=10,复制一个副本给 fun(){ }里边的d 也就是10,所以再函数内修改d,不
会影响到全局变量的d
console.log(d) //10
以下情况表示 按值传递不只有一种情况
修改student2对象中的 原始类型的值时,原变量student不会改变
修改student2对象中的 引用类型的值( student2.school{ } )时,原变量student中的 ( student2.school{ } )也会改变
扩展 作用域笔试题:
var b = 10;
function fun2(){
b=100; //2.其次没有再函数体里边var定义变量 就没有局部变量,那么就会找到全局变量的b 进行赋值 所有的b都会对全局的b进行改变 此时b=100 就会更改全局中的b为100
b++;
console.log(b); //101
}
fun2(); // 1.首先此时没有对函数进行传参
console.log(b); //101
作用域链
什么是作用域链?
有多级作用域串联形成的链式结构
每个函数在创建时,就有了自己的作用域链,
普通函数作用域链里边包含2个内容:
①一个离自己近的,暂时为空 调用函数时 用来引用函数作用域对象 (局部)
②一个离自己远的 为window 始终保持着全局作用域对象 (全局)
作用域 保存着一个函数可用的所有变量 控制着变量的使用顺序 先局部 局部没有 再全局!
js中没有块级作用域
什么是块级作用域?
程序块:除函数以外的循环和分支的 { } 里的 称为程序块
如:for( ){ xxx } if( ){ xxx } else{ xxx }
因为js中没有块级作用域 ,所以即使再循环内和分支内声明的变量,即便出了分支 { } 也照样使用
声明提前:
在程序开始执行前,都是先在整段程序中 查找var声明的变量和 function声明的函数,将他们的定义提前到当前作用域的顶部集中创建。赋值留在原地。
因为声明提前 function fun()声明的函数被提提前 会在函数执行前:
function fun( ){ console.log(1) }
function fun( ){ console.log(2) }
由于在 html js css 中都是 解释执行 那么后边的同名的内容会覆盖前边的function 所以只剩一个
function fun( ){ console.log(2) }
那么 fun() fun() 执行结果都是 2