1、this的默认绑定
this 默认指向了 window
// 1、全局环境下的this指向了window
console.log(this);
// 2、函数独立调用,函数内部的this也指向了window
function fn() {
console.log(this);
}
fn();
// 3、被嵌套的函数独立调用时,this默认指向了window
var a = 0;
var obj = {
a: 2,
foo: function () {
// 函数当作对象的方法调用时,this指向了obj
var that = this; // obj
function test() {
console.log(that.a); // window
}
test();
}
}
obj.foo();
// 4、IIFE 自执行函数中内部的this指向了window
var a = 10;
function foo() {
console.log(this);
(function test(that) {
console.log(that.a);
})(this)
}
var obj = {
a: 2,
foo: foo
}
obj.foo();
(
function () {
console.log(this); //window
}
)()
// 5、闭包中的this默认指向了window
var a = 0;
var obj = {
a: 2,
foo: function () {
var c = this.a;
return function test() {
console.log(this); //window
return c;
}
}
}
var fn = obj.foo();
fn();
2、this的隐式绑定
// 当函数当作方法来调用,this指向了直接对象
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo,
obj2: {
a: 2,
foo: foo
}
}
// foo()函数的直接对象是obj,this的指向指向了直接对象
obj.foo();
// foo()函数的直接对象是obj2,this的指向指向了直接对象
obj.obj2.foo();
3、this的显示绑定
// call()、apply()、bind()把对象绑定到this上,叫做显式绑定
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 2
}
foo(); //0
foo.call(obj); //2
foo.apply(obj); //2
var fn = foo.bind(obj);
fn(); //2
// 2、硬绑定,是显式绑定的一个变种,使得this不能再被改变
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 2
}
var bar = function () {
foo.call(obj);
}
bar(); //2
setTimeout(bar, 1000); //2
bar.call(window); //2
// 3、数组的forEach(fn,对象)、map()、filter()、some()、every()
var id = 'window';
/* function fn(el) {
console.log(el, this.id);
} */
var obj = {
id: 'fn'
}
var arr = [1, 2, 3];
// this 指向了 obj
arr.forEach(function (el, index) {
console.log(el, index, this);
}, obj)
4、new关键字绑定
function fn() {
// 1、如果是new关键字来执行函数,相当于构造函数来实例化对象,那么内部的this指向了当前实例化的对象
console.log(this);
}
var fn1 = new fn();
console.log(fn1);
// 2
function fn2() {
// this还是指向了当前的对象
console.log(this);
// 使用return来返回对象的时候,实例化出来的对象是当前的返回对象
return {
name: '张三'
}
}
var fn2 = new fn2();
console.log(fn2);
// 3
var person = {
fav:function(){
return this;
}
}
var p = new person.fav();
console.log(p,p === person); //fav,false
// 实例化出来的对象内部的属性constructor属性指向了当前的构造函数
console.log(p.constructor === person.fav); //true
5、隐式丢失this的5种情况
隐式丢失就是指被隐式绑定的函数丢失了绑定对象,从而默认绑定到了window,这种情况非常容易出错且又非常常见。
// 1、隐式丢失,函数别名
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo
}
// 把obj.foo()赋值给变量bar,造成隐式丢失的情况,因为只是把obj.foo赋值给了bar变量,
// 而bar与obj毫无关系
var bar = obj.foo;
bar();
// 2、参数传递
var a = 0;
function foo() {
console.log(this.a);
}
function bar(fn) {
fn();
}
var obj = {
a: 1,
foo: foo
}
// 把obj.foo当作参数传递到bar函数中,有隐式的函数赋值 fn=obj.foo,只是把foo函数赋值给了fn,而fn函数与obj对象毫无关系,所以当前foo函数内部的this指向了window
bar(obj.foo);
// 3、内置函数,setTimeout()和setInterval()第一个参数的回调函数中的this,默认指向了window,跟第2种情况是类似的
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo
}
setTimeout(obj.foo, 1000);
// 4、间接调用
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo
}
var p = { a: 2 };
// 隐式绑定,函数当作对象的方法来使用,内部的this指向了obj
obj.foo(); //1
// 将obj.foo函数对象赋值给了p.foo()函数,然后立即执行,相当于仅仅是foo()函数的立即调用,内部的this默认指向了window
(p.foo = obj.foo)(); //0
p.foo = obj.foo
p.foo(); //2
// 5、其他情况,指向了window的特殊情况
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo
}
(obj.foo = obj.foo)(); //0
(false || obj.foo)(); //0
(1,obj.foo)(); //0
6、严格模式下的this指向
// 1、严格模式下,独立调用的函数内部的this指向了undefined
function fn(){
'use strict'
console.log(this);
}
fn();
// 2、严格模式下,函数apply()和call()内部的this始终是他们的第一个参数
var color = 'red';
function showColor(){
'use strict'
console.log(this); //null
console.log(this.color); //报错
}
showColor.call(null);
7、总结
1、默认绑定
2、隐式绑定
3、显示绑定
4、new绑定
分别对应函数的四种调用:
-独立调用
-方法调用
-间接调用
call()、apply()、bind()
-构造函数调用
隐式丢失:
1、函数别名
2、函数当作参数传递
3、内置函数
4、间接调用
5、其他情况,指向了window的特殊情况
文章最后:更多精彩文章和资源,欢迎参观我的公众号:小笑残虹。