jsJS

JavaScript:this的指向

2021-05-08  本文已影响0人  前小小

this 的默认绑定

console.log(this); // window
function fn() {
  console.log(this);
}
fn(); // window   // 相当于window.fn();
var obj = {
  a: 2,
  // 函数当做对象的方法来调用 this指向了obj
  fn: function () {
    function test() {
      console.log(this); // window
    }
    test();
  },
};
obj.fn(); // 此时test()函数自己去执行,相当于函数独立调用, 所以此时的this也是window
(function () {
  console.log('自执行函数中内部的this: ' + this); //window
})();
// 闭包就是能够读取其他函数内部变量的函数。下面的test函数就是闭包
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();
console.log(fn()); // 2
function test1() {
  console.log(this); // window
  test2();
}

function test2() {
  console.log(this); // window
}
test1();
// 1.
setTimeout(function () {
  console.log(this); // window
}, 1000);
// 2.
var a = 10;
function foo() {
  console.log(this.a);
}
var obj = {
  a: 1,
  foo: foo,
};
setTimeout(obj.foo, 1000); // 10
// 以上代码相当于
setTimeout(function foo() {
  console.log(this.a);
}, 1000); // 10

this 的隐式绑定

// 1. 当函数当做对象的方法来调用,this指向了直接对象
function foo() {
  console.log(this.a);
}
var obj = {
  a: 1,
  foo: foo,
  obj2: {
    a: 2,
    foo: foo,
  },
};
// foo()函数的直接对象是obj, this会隐式的被绑定到obj对象上
obj.foo(); // 1
// foo()函数的直接对象是obj2, this会隐式的被绑定到obj对象上
obj.obj2.foo(); // 2

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
var a = 0;
function foo() {
  console.log(this.a);
}
var obj = {
  a: 2,
};
var bar = function () {
  foo.call(obj);
};
bar();
setTimeout(bar, 2000);
// 硬绑定后bar无论怎么调用,都不会影响foo函数的this绑定
bar.call(window); // 2
// 因为默认情况下传入的函数是独立调用的(默认绑定)
var id = 'window';
var obj = {
  id: 'fn',
};
var arr = [1, 2, 3];
arr.forEach(function (item) {
  console.log(item, this.id); // 打印了三次"window"
});
// 如果要改变该函数的this指向, 就给forEach的第二个参数传递一个对象
var id = 'window';
var obj = {
  id: 'fn',
};
var arr = [1, 2, 3];
arr.forEach(function (item) {
  console.log(item, this.id); // 打印了三次"fn"
}, obj);

this 的 new 绑定

// 如果是new关键字来调用函数 相当于构造函数来实例化对象,那么内部的this指向了当前实例化的对象
// 创建Person
function Person() {
  console.log(this); // Person {}
}

var p = new Person();
console.log(p); // Person {}

this 的隐式丢失

var a = 0;
function foo() {
  console.log(this.a);
}
var obj = {
  a: 1,
  foo: foo,
};
obj.foo(); // 1
// 因为foo最终被调用的位置是bar,而bar在进行调用时没有绑定任何的对象,也就没有形成隐式绑定,此时为默认绑定情况,里面的this指向了window
var bar = obj.foo;
bar(); // 0
var a = 0;
function foo() {
  console.log(this.a);
}
var obj = {
  a: 1,
  foo: foo,
};
obj.foo(); // 1
// 因为foo最终被调用的位置是bar,而bar在进行调用时没有绑定任何的对象,也就没有形成隐式绑定,此时为默认绑定情况,里面的this指向了window
var bar = obj.foo;
bar(); // 0
function foo() {
  console.log(this.a);
}
var a = 2;
var obj = {
  a: 3,
  foo: foo,
};
var p = { a: 4 };
// 隐式绑定,函数当做对象中的方法来使用,内部的this指向了该对象
obj.foo(); // 3

// 赋值(obj2.foo = obj1.foo)的结果是foo函数;
// foo函数被直接调用,那么是默认绑定
(p.foo = obj.foo)(); // 2

// 将obj.foo函数赋值给p.foo函数, 之后p.foo()函数再执行,其实是属于p对象的方法的执行,this指向了当前的p对象
p.foo = obj.foo;
p.foo(); // 4

ES6 箭头函数中的 this 指向

MDN 官方文档:「箭头函数不会创建自己的 this,它只会从自己的作用域链的上一层继承 this。」

var obj = {
  a: () => {
    console.log(this);
  },
};
// 对象是不能产生作用域的,a方法实际是被定义在了全局作用域下,里面的this指向的是window
obj.a(); // window
// 不能用call方法改变箭头函数的this指向
var obj = {
  a: () => {
    console.log(this);
  },
};
obj.a.call({ name: 'zhangsan' }); // window

严格模式下的 this 指向

// 1. 严格模式下, 独立调用的函数内部的this指向了undefined
function fn() {
  'use strict';
  console.log(this); // undefined
}
fn();
// 2. 严格模式下, 函数apply()和call()内部的this始终是它们的第一个参数
function fn() {
  'use strict';
  console.log(this); // 第一个输出null,第二句输出undefined
}
showColor.call(null);
showColor.call(undefined);
上一篇下一篇

猜你喜欢

热点阅读