this
关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象。
根据不同的使用场合,this
有不同的值,主要分为下面几种情况:
什么情况下使用默认绑定呢?独立函数调用。
案例一:普通函数调用
this
指向全局对象(window
);jsfunction foo() {
console.log(this); // window
}
foo();
案例二:函数调用链(一个函数又调用另外一个函数)
js// 2.案例二:
function test1() {
console.log(this); // window
test2();
}
function test2() {
console.log(this); // window
test3()
}
function test3() {
console.log(this); // window
}
test1();
案例三:将函数作为参数,传入到另一个函数中
jsfunction foo(func) {
func()
}
function bar() {
console.log(this); // window
}
foo(bar);
我们对案例进行一些修改,考虑一下打印结果是否会发生变化:
window
,为什么呢?jsfunction foo(func) {
func()
}
var obj = {
name: "why",
bar: function() {
console.log(this); // window
}
}
foo(obj.bar);
另外一种比较常见的调用方式是通过某个对象进行调用的:
案例一:通过对象调用函数
foo
的调用位置是 obj.foo()
方式进行调用的foo
调用时 this
会隐式的被绑定到 obj
对象上jsfunction foo() {
console.log(this); // obj对象
}
var obj = {
name: "why",
foo: foo
}
obj.foo();
案例二:案例一的变化
obj2
又引用了 obj1
对象,再通过 obj1
对象调用 foo
函数;foo
调用的位置上其实还是 obj1
被绑定了 this
;jsfunction foo() {
console.log(this); // obj1 对象
}
var obj1 = {
name: "obj1",
foo: foo
}
var obj2 = {
name: "obj2",
obj1: obj1
}
obj2.obj1.foo();
案例三:隐式丢失
结果最终是 window
,为什么是 window
呢?
foo
最终被调用的位置是 bar
,而 bar
在进行调用时没有绑定任何的对象,也就没有形成隐式绑定;jsfunction foo() {
console.log(this);
}
var obj1 = {
name: "obj1",
foo: foo
}
// 讲obj1的foo赋值给bar
var bar = obj1.foo;
bar();
隐式绑定有一个前提条件:
对象内部
有一个对函数的引用(比如一个属性);如果我们不希望在 对象内部 包含这个函数的引用,同时又希望在这个对象上进行强制调用,该怎么做呢?
JavaScript
所有的函数都可以使用 call
和 apply
方法(这个和 Prototype
有关)。
apply
为数组,call
为参数列表;this
准备的。this
绑定到这个传入的对象上。因为上面的过程,我们明确的绑定了 this
指向的对象,所以称之为 显示绑定。
案例一:call
、apply
通过 call
或者 apply
绑定 this
对象
this
就会明确的指向绑定的对象jsfunction foo() {
console.log(this);
}
foo.call(window); // window
foo.call({name: "why"}); // {name: "why"}
foo.call(123); // Number对象,存放 123
案例二:bind
函数
如果我们希望一个函数总是显示的绑定到一个对象上,我们可以使用 bind
函数:
function foo() { console.log(this); } var obj = { name: "why" } var bar = foo.bind(obj); bar(); // obj对象 bar(); // obj对象 bar(); // obj对象
案例三:内置函数
有些时候,我们会调用一些 JavaScript
的内置函数,或者一些第三方库中的内置函数。
JavaScript
内部或者第三方库内部会帮助我们执行;this
又是如何绑定的呢?js// 1. setTimeout中会传入一个函数,这个函数中的this通常是window
setTimeout(function() {
console.log(this); // window
}, 1000);
// 2. forEach map filter 等高阶函数 this 通常指向 window对象,但我们可以通过第二个参数改变
var names = ["abc", "cba", "nba"];
names.forEach(function(item) {
console.log(this); // 三次window
});
var names = ["abc", "cba", "nba"];
var obj = {name: "why"};
names.forEach(function(item) {
console.log(this); // 三次obj对象
}, obj);
new
绑定JavaScript
中的函数可以当做一个类的构造函数来使用,也就是使用 new
关键字。
使用 new
关键字来调用函数时,会执行如下的操作:
Prototype
连接;this
上 (this
的绑定在这个步骤完成);js// 创建Person
function Person(name) {
console.log(this); // Person {}
this.name = name; // Person {name: "why"}
}
var p = new Person("why");
console.log(p);
new绑定
> 显示绑定(bind)
> 隐式绑定
> 默认绑定
PS: new
绑定后可以使用 bind
但是 bind
不会生效。 new
绑定后使用 call
和 apply
会报错。
bind
绑定一个 null
或者 undefined
无效jsfunction foo() {
console.log(this);
}
var obj1 = {
name: "obj1",
foo: foo
};
var obj2 = {
name: "obj2"
}
obj1.foo(); // obj1对象
// 赋值(obj2.foo = obj1.foo)的结果是foo函数
// foo函数被直接调用,那么是默认绑定;
(obj2.foo = obj1.foo)(); // window
ES6
箭头函数:箭头函数不使用 this
的四种标准规则(也就是不绑定 this
),而是根据外层作用域来决定 this
。本文作者:叶继伟
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!