this和對象原型 this是一個很特別的關鍵字,被自動定義在所有函數的作用域中 // foo.count 是0,字面理解是錯誤的 function foo(num) { console.log("foo:"+ num); this.count++; } foo.count = 0; var i; ...
this和對象原型
this是一個很特別的關鍵字,被自動定義在所有函數的作用域中
// foo.count 是0,字面理解是錯誤的
function foo(num) {
console.log("foo:"+ num);
this.count++;
}
foo.count = 0;
var i;
for(i=0;i<10;i++){
if(i>5){
foo(i)
}
}
console.log(foo.count) //0
// 使用詞法作用域解決問題
function foo(num) {
console.log("foo:"+ num);
data.count++;
}
var data = {
count:0
};
var i;
for(i=0;i<10;i++){
if(i>5){
foo(i)
}
}
console.log(data.count); // 4
// 用foo標識符來替代this來引用函數對象,迴避了this 的問題,完全依賴於變數foo的詞法作用域。
function foo(num) {
console.log("foo:"+ num);
foo.count++;
}
foo.count = 0
var i;
for(i=0;i<10;i++){
if(i>5){
foo(i)
}
}
console.log(foo.count) //4
//強制this 指向foo函數對象
function foo(num) {
console.log("foo:"+num);
this.count++
}
foo.count = 0;
var i;
for(i=0; i< 10; i++){
if(i>5){
foo.call(foo,i);
}
}
console.log(foo.count) //4
this是在運行是 綁定的,並不是在編寫時綁定的,它的上下文取決於函數調用時的各種條件,this的綁定和和函數聲明的位置沒有任何關係,只取決於函數調用的方式。
this全面解析
調用棧與調用位置
function baz(){
//當前調用棧是:baz
// 因此,當前的調用中位置是全局作用域
console.log("baz");
bar(); // <--bar的調用位置
}
function bar(){
//當前的調用棧是: baz-> bar
// 因此,當前調用位置在baz
console.log("bar);
foo(); // <-- foo 的調用位置
}
function foo(){
//當前的調用棧是: baz-> bar->foo
// 因此,當前調用位置在bar
console.log("foo");
}
baz(); // <-- baz 的調用位置
只有運行在非strict mode 下,預設綁定才能綁定到全局對象。
對象屬性引用鏈中只有最頂層或者說最後一層灰影響調用位置。
function foo() {
console.log(this.a);
}
var obj2 = {
a: 42,
foo:foo
};
var obj1 = {
a:2,
obj2: obj2
};
obj1.obj2.foo(); // 42
硬綁定的典型應用場景就是創建一個包裹函數,傳入所有的函數並返回接收到的所有的值。
function foo(something){
console.log(this.a,something);
return this.a + something;
};
var obj = {
a:2
};
var bar = function() {
return foo.apply(obj,arguments);
};
var b = bar(3) ; // 2 3
console.log(b) // 5
另一種方法是創建一個i可以重覆使用的輔助函數
function foo(something){
console.log(this.a, something);
return this.a + something;
}
// 簡單的輔助綁定函數
function bind(fn,obj){
return function(){
return fn.apply(obj,arguments);
};
}
var obj = {
a:2
}
var bar = bind(foo,obj);
var b = bar(3); // 2 3
console.log(b) // 5
ES5 中提供了內置的方法 Function.prototype.bind, bind(..) 會返回一個硬編碼的新函數,它會
把參數設置為this的上下文並調用原始函數。
function foo(something){
console.log(this.a, something);
return this.a + something;
}
var obj = {
a:2
}
var bar = foo.bind(obj);
var b = bar(3); // 3 5
console.log(b) // 5
API 調用的 上下文
function foo(el){
console.log(el,this.id);
}
var obj = {
id: "awesome'
}
// 調用 foo(..)時把this 綁定到obj
[1,2,3].forEach(foo,obj);
// 1 awesome 2 awesome 3 awesome
new可以影響函數調用時this 綁定行為的方法。
function foo(a){
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2
判斷this
1.函數是否在new 中調用(new 綁定)? 如果是的話this 綁定的是新創建的對象。
var bar = new foo();
2.函數是否通過call , apply (顯示綁定) 或者硬綁定調用? 如果是的話,this的綁定時指定的對象。
va bar = foo.call(obj2)
3.函數是否在某個上下文對象中調用(隱式綁定) ? 如果是的話,this 的綁定時在那個上下文。
var bar = obj1.foo()
4.如果都不是的話,使用預設綁定。如果在嚴格模式下,就綁定到undefined,否則綁定到全局對象上。
var bar = foo();
軟綁定
function foo(){
console.log("name:" + this.name);
}
var obj = {name: "obj"},
obj2 = {name: "obj2"},
obj3 = {name: "obj3"},
obj3 = {name: "obj3"};
var foo0BJ = foo.softBind(obj);
foo0BJ(); // name:obj
obj2.foo = foo.softBind(obj);
obj2.foo(); // name:obj3 <--看!
setTimeout(obj2.foo,10);
// name:obj <--- 應用了軟綁定