獲取局部變量
<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 參數對象所屬函數
}