获取局部变量
<script>
function fn1() {
var a ="月薪10w";
}
alert(a);
</script>
如何获取内部变量
- 作为函数返回值
<script>
function fn1() {
var a ="月薪10w";
return a;
}
alert(fn1());
</script>
- 通过变量向外传递
<script>
var b="";
function fn1() {
var a ="月薪10w";
b=a;
}
fn1();
alert(b);
</script>
- 通过函数传参
<script>
function fn1() {
var a ="月薪10w";
fn2(a);
}
function fn2(str){
alert(str);
}
fn1();
</script>
条件和循环体
<script>
if (1){
var a =1;
}
alert(a);
</script>
会有结果1
<script>
alert(a);
if (false){
var a =10;
}
</script>
结果是undefined
<script>
if (1){
function fn1() {
}
}
alert(fn1);
结果是函数体
- {}不代表作用域 但是有例外
<script>
alert(fn1);
if (1){
function fn1() {
}
}
结果是 undefined 这是es6的规范 在es6中 花括号{}会被看作是代码块 在{}当中声明一个函数 相当于 var 声明 所以结果是undefined
<script>
alert(fn1);
function fn1() {
}
结果是函数体
- 尽量不要在代码块中声明函数 否则 调用会出问题
<script>
fn1();
if (1){
function fn1() {
alert(1);
}
}
</script>
会报错 因为此时看作是代码块 相当于var 声明var a=fn1(){}
这时候fn1();是不会执行的 会报错
<script>
alert(fn1);
if (1){
function fn1() {
alert(1);
}
}
</script>
结果是个undefined
闭包
<script>
function t1() {
var age =20;
function t2() {
alert(age);
}
return t2;
}
var tmp =t1();
var age =1000;
tmp();
</script>
结果是 20 AO分析
- 第1步 AO{t1:function,tmp:un,age:un}
- 第2步 tmp=t1(); t1执行
进入函数体 AO{age:un,t2:fun} 执行AO{age:20,t2:fn} 遇到return t2 跳出函数 t2 =function t2(){} 所以 AO{ tmp=t2, age:1000} - tmp执行 进入函数t2 AO 没发现变量声明 从上级寻找 age为20
- 我们在返回函数的时候 并不是单纯的返回了一个函数 而是把作用域链返回了 如果没有变量声明会沿着作用域链往上找
- 函数的作用域 取决于声明时 而不取决于调用时
闭包是什么
- 有函数套嵌
- 内部函数使用了外部函数的变量
- 内部函数的使用外部函数的那些变量和参数会永久保存
- 垃圾回收机制:当环境都不存在有某个对象/数据的引用时,这个数据会自动被回收 但是全局变量不会被回收
- 返回函数时 并非孤立的函数 而是连同周围的环境 AO 打了一个包 成了一个封闭的环境包 共同返回出来----闭包
<script>
var age = 10;
function t1() {
var age =20;
return function t2() {
alert(++age);
}
}
var t3=t1();
t3();
t3();
t3();
alert(age);
结果 21 22 23 10
console.log(function () {} === function(){});
console.log([]===[]);
console.log({}==={});
这些都不一样 不等于
var a =function(){};
var b =a;
console.log(a==b);
这是相等的 变量存储 function {} []存储的是个地址
<script>
var age = 10;
function t1() {
var age =20;
return function t2() {
alert(++age);
}
}
var t3=t1();
var t4=t1();
t3();
t4();
</script>
结果是 21 21 因为t3 t4 表示的不是一个函数 虽然都是t2
<script>
function foo() {
var a=2;
function baz() {
console.log(a);
}
bar(baz);
}
function bar(fn) {
var a=3;
fn();
}
foo();
</script>
结果是2 函数的作用域取决于声明时 不是调用时
计数器
<script>
window.cnt=0
function inc() {
cnt++;
}
inc();
inc();
console.log(cnt);
</script>
<script>
var cnt=100;
inc();
console.log(cnt);
</script>
结果是 2 101 会污染变量
<script>
function counter(){
var cnt=0;
var cont =function(){
return ++cnt;
}
return cont;
}
var inc =counter();
console.log(inc());
</script>
<script>
var cnt=100;
inc();
console.log(inc())
</script>
结果是1 3 没有污染变量
<script>
function counter(){
var cnt=0;
return function(){
return ++cnt;
}
}
var inc =counter();
console.log(inc());
</script>
<script>
var cnt=100;
inc();
console.log(inc())
</script>
简化版本
<script>
var inc = (function (){
var cnt=0;
return function(){
return ++cnt;
}
})();
var inc =counter();
console.log(inc());
</script>
<script>
var cnt=100;//如果继续var inc =100;又会污染变量
inc();
console.log(inc());
</script>
解决变量污染
<script>
var juce ={};
juce.inc = (function (){
var cnt=0;
return function(){
return ++cnt;
}
})();
console.log(juce.inc());
</script>
<script>
var cnt=100;
inc();
console.log(inc())
</script>
js的命名空间 别人不能用里面的函数
for循环中的闭包
方法一:通过自定义属性
<script>
var inp= document.getElementsByTagName("input");
for (var i=0;i<inp.length;i++){
inp[i].i=i;
inp[i].onclick = function () {
inp[this.i].style.backgroundColor = "red";
}
}
console.log(i);
</script>
方法二:使用let
<script>
var inp= document.getElementsByTagName("input");
for (let i=0;i<inp.length;i++){
inp[i].onclick = function () {
inp[i].style.backgroundColor = "red";
}
}
console.log(i);
</script>
第三种:使用this 第四种:for循环每执行一次 都会立即执行一个匿名函数 并且匿名函数的作用域中 传入了当时的i
for (var i=0;i<inp.length;i++){
(function(i){
inp[i].onclick = function () {
inp[i].style.backgroundColor = "red";
}})(i);
}
第五种:将变量传进作用域
for (var i=0;i<inp.length;i++){
(function(){
var arg = i;
inp[arg].onclick = function () {
inp[arg].style.backgroundColor = "red";
}})();
}
第六种:循环时候立即执行函数 将变量传进作用域
for (var i=0;i<inp.length;i++){
inp[i].onclick = function (i) {
return function() {
inp[i].style.backgroundColor = "red";
}
}(i);
}
方法七:基本包装类型 通过 new 使用 Function 的构造函数 创建 Function 实例实现,由于传入的函数体的内容是字符串,故 Function 得到的是一个字符串拷贝,而没有得到 i 的引用(这里是先获取 i.toString()然后与前后字符串拼接成一个新的字符串,Function 对其进行反向解析成 JS 代码)
for(var i=0;i<inp.length;i++){
inp[i].onclick = new Function(`inp[${i}].style.backgroundColor = "red";`);
}
方法九:
function fn(a) {
alert(1);
}
console.log(fn.length);
结果是1,length是形参个数
for (var i=0;i<inp.length;i++){
(inp[i].onclick = function () {
inp[arguments.callee.i].style.backgroundColor = "red";
}).i=i;//arguments 参数对象 arguments.callee 参数对象所属函数
}