内容預覽
1. js 中的作用域
2.閉包的了解和運用
3.this 的了解和運用
【一】 js中的作用域
一段簡單的代碼來說明
var outFunc = function() {
var out_name = "outFunc";
var out_num = 130;
var inFunc = function() {
var in_name = "inFunc";
var in_num = 3;
alert(out_name);
alert(out_num);
alert(in_name);
alert(in_num);
};
inFunc();
// 調用 inFunc 函數執行的結果是,彈出:outFunc、130、inFunc、3
alert(out_name);
alert(out_num);
alert(in_name);
alert(in_num);
};
outFunc();
// 調用 inFunc 函數執行的結果是,彈出:outFunc、130、undefined、undefined
内部函數可以通路外部函數的變量,外部不能通路内部函數的變量。上面的例子中内部函數inFunc可以通路變量 out_name和out_num,而外部函數 outFunc 不可以通路 inFunc 中的變量 in_name和in_num,是以會抛出沒有定義變量的異常。
很重要的一點,如果忘記 var,那麼變量或者函數就會被聲明為全局變量或者全局函數了。下面例子的寫法,in_name 變量和 test 函數 是全局的變量和全局函數,不屬内部作用域了。
var outFunc = function() {
var out_name = "outFunc";
var out_num = 130;
var inFunc = function() {
in_name = "inFunc";
var in_num = 3;
};
test function(){
alert('Test');
}
};
【二】 閉包的了解和運用
閉包這個概念,在函數式程式設計裡很常見,簡單的說常見的兩大用處,一是使外部函數可以突破作用域進而通路定義在内部函數中的變量,二是讓變量的值始終儲存在記憶體中。當在一個函數中定義另個函數就會産生閉包。如果要深入了解閉包,可以檢視這篇部落格http://coolshell.cn/articles/6731.html
//javascript 中特殊形式的函數,自調用函數
var a = function() {
function setUp() {
//定義方法時可以做首次的初始化,這個隻會調用一次
alert('初始化');
}
setUp();
function doSomething() {
alert('要執行的操作')
}
return doSomething; //這裡傳回的不是一個函數,而是一個引用
}(); //加()進行首次調用初始化,既首次執行setUp函數(自調用函數)
// a(); //彈出 初始化
// a(); //彈出 要執行的操作
//閉包的應用一: 通過閉包突破全局作用域鍊
var n;
function f() {
var a = 'king'; //這是局部變量
n = function() { //外部可通過 n 函數通路局部變量a
return a;
};
//這個test函數 不加var 預設為全局的函數,加var 則為局部的
test = function() {
alert('預設全局函數');
}
}
//閉包的應用二: 定義私有變量的取值和指派
var setValue, getValue;
(function() {
var n = 0; //私有變量
getValue = function() {
return n;
}
setValue = function(x) {
n = x;
}
})(); //這樣寫為自調用函數
//閉包的應用三:疊代器
function test(x) {
var i = 0;
return function() {
return x[i++];
}
}
var next = test(['a', 'b', 'c', 'd']);
// alert(next());//彈出a
// alert(next());//彈出b
// alert(next());//彈出c
// alert(next());//彈出d
//了解不到位常犯的錯誤,這種錯誤通常不容易被發現
function f() {
var a = [];
var i;
for (var i = 0; i < 3; i++) {
a[i] = function() {
return i; //這裡隻是對 i 這個指針進行了引用
};
}
return a;
}
var test = f();
// alert(test[0]());//彈出 3
// alert(test[1]());//彈出 3
// alert(test[2]());//彈出 3
//出現這個問題原因在于 i 是一個指針,也就是一個位址,閉包隻是引用了這個指針。當for 循環周遊結束 指針 i 指向的值為 3
// 可采用自調用函數的方式來避免上述的問題,如下所示
function f() {
var a = [];
var i;
for (var i = 0; i < 3; i++) {
a[i] = (function(x) {
return function() {
return x;
}
})(i);
}
return a;
}
var test = f();
alert(test[0]()); //彈出 0
alert(test[1]()); //彈出 1
alert(test[2]()); //彈出 2
【三】this 的了解和運用
在函數執行時,this 總是指向調用該函數的對象。要判斷 this 的指向,其實就是判斷 this 所在的函數屬于誰。
在《javaScript語言精粹》這本書中,把 this 出現的場景分為四類,簡單的說就是:
1) 有對象就指向調用對象
var myObject = {value:111};
myObject.getValue = function(){
console.log(this.value);//輸出100
console.log(this);//輸出 { value: 100, getValue: [Function] }
}
myObject.getValue();
// getValue() 屬于對象 myObject,并由 myOjbect 進行 . 調用,是以 this 指向對象 myObject。
2) 沒調用對象就指向全局對象
var myObject = { value: 100 };
myObject.getValue = function() {
var foo = function() {
console.log(this.value) // 輸出 undefined
console.log(this); // 輸出全局對象 global
//foo 函數雖然定義在 getValue 的函數體内,但實際上它既不屬于 getValue 也不屬于 myObject。
// foo 并沒有被綁定在任何對象上,是以當調用時,它的 this 指針指向了全局對象 global。
};
foo();
return this.value; //這個this 在 getValue中,進而指向 myObject。
};
console.log(myObject.getValue()); // 輸出 100
3) 用new構造就指向新對象
//js 中,我們通過 new 關鍵詞來調用構造函數,此時 this 會綁定在該新對象上。
var SomeClass = function() {
this.value = 100;
}
var myCreate = new SomeClass();
console.log(myCreate.value); // 輸出100
4) 通過 apply 或 call 或 bind 來改變 this 的所指
// apply 和 call 調用以及 bind 綁定: 指向綁定的對象
// apply() 方法接受兩個參數第一個是函數運作的作用域, 另外一個是一個參數數組(arguments)。
// call() 方法第一個參數的意義與 apply() 方法相同, 隻是其他的參數需要一個個列舉出來。
// 簡單來說, call 的方式更接近我們平時調用函數, 而 apply 需要我們傳遞 Array 形式的數組給它。 它們是可以互相轉換的。
var myObject = { value: 100 };
var foo = function() {
console.log(this);
};
foo(); // 全局變量 global
foo.apply(myObject); // { value: 100 }
foo.call(myObject); // { value: 100 }
var newFoo = foo.bind(myObject);
newFoo(); // { value: 100 }</span>