this
this既不指向函数自身也不指向函数的词法作用域
this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
需要明确的是,this在任何情况下都不指向函数的词法作用域
function foo() {
var a = 2;
this.bar();
}
function bar() {
console.log(this.a);
}
foo(); // ReferenceError: a is not defined
function identify() {
return this.name.toUpperCase();
}
function speak() {
var greeting = "Hello, I'm " + identify.call(this);
console.log(greeting);
}
var me = {
name: "Kyle"
};
var you = {
name: "Reader"
};
identify.call(me); // KYLE
identify.call(you); // READER
speak.call(me); // Hello, 我是KYLE
speak.call(you); // Hello, 我是READER
function identify(context) {
return context.name.toUpperCase();
}
function speak(context) {
var greeting = "Hello, I'm " + identify (context);
console.log(greeting);
}
identify(you); // READER
speak(me); //hello, I'm KYLE
判断函数计算函数调用次数
function foo(num) {
console.log("foo: " + num);
// 记录foo被调用的次数
this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
if (i > 5) {
foo(i);
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo被调用了多少次?
console.log(foo.count); // 0 -- 什么?!
function foo(num) {
console.log("foo: " + num);
// 记录foo被调用的次数
// 注意,在当前的调用方式下(参见下方代码), this确实指向foo
this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
if (i > 5) {
// 使用call(..)可以确保this指向函数对象foo本身
foo.call(foo, i);
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo被调用了多少次?
console.log(foo.count); // 4
绑定规则
默认绑定
非严格模式下,this指向window全局
严格模式下,this指向undefined
function foo() {
"use strict";
//如果使用严格模式(strict mode),则不能将全局对象用于默认绑定,因此this会绑定到undefined
console.log(this.a);
}
var a = 2;
foo(); // TypeError: this is undefined
function foo() {
//foo()运行在非strict mode下时,默认绑定才能绑定到全局对象;在严格模式下调用foo()则不影响默认绑定
console.log(this.a);
}
var a = 2;
(function(){
"use strict";
foo(); // 2
})();
隐式绑定
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
是foo()的声明方式,及其之后是如何被当作引用属性添加到obj中的。但是无论是直接在obj中定义还是先定义再添加为引用属性,这个函数严格来说都不属于obj对象。
当foo()被调用时,它的前面确实加上了对obj的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因为调用foo()时this被绑定到obj,因此this.a和obj.a是一样的。
function foo() {
console.log(this.a);
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
//对象属性引用链中只有上一层或者说最后一层在调用位置中起作用
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a是全局对象的属性
bar(); // "oops, global"
虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。
function foo() {
console.log(this.a);
}
function doFoo(fn) {
// fn其实引用的是foo
fn(); // <-- 调用位置!
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a是全局对象的属性
doFoo(obj.foo); // "oops, global"
参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值
如果把函数传入语言内置的函数而不是传入你自己声明的函数,会发生什么呢?结果是一样的,没有区别
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a是全局对象的属性
setTimeout(obj.foo, 100); // "oops, global"
显示绑定
//硬绑定
function foo() {
console.log(this.a);
}
var obj = {
a:2
};
var bar = function() {
foo.call(obj);
};
bar(); // 2
setTimeout(bar, 100); // 2
// 硬绑定的bar不可能再修改它的this
bar.call(window); // 2
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
优先级
显示绑定比默认优先级高
function foo() {
console.log(this.a);
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3,
foo: foo
};
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call(obj2); // 3
obj2.foo.call(obj1); // 2
this四种绑定规则的优先级
- 显式绑定 > 隐式绑定 > 默认绑定
- new绑定 > 隐式绑定 > 默认绑定
548

被折叠的 条评论
为什么被折叠?



