目录
1.this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用者是谁
1.this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用者是谁
var getName = function() {
return this.name;
};
var person1 = {
name: 'Alice',
getName: getName
};
var person2 = {
name: 'Bob',
getName: getName
};
console.log(person1.getName()); // Alice
console.log(person2.getName()); // Bob
下面的例子中,直接运行 obj.fn() ,调用该函数的上一级对象是 obj,所以 this 指向 obj,得到 this.x 的值是 2;之后我们将 fn 方法首先赋值给变量 a,a 运行在全局环境中,所以此时 this 指向全局对象Window,得到 this.x 为 1。
var x = 1
var obj = {
x: 2,
fn: function() {
console.log(this);
console.log(this.x);
}
}
obj.fn()
// obj.fn()结果打印出
// Object {x: 2, fn: function}
// 2
var a = obj.fn
a()
// a()结果打印出:
// Window 全局对象
// 1
2.对象嵌套、函数嵌套中的this
对象嵌套。this 始终会指向直接调用函数的上一级对象,即 y。
var x = 1
var obj = {
x: 2,
y: {
x: 3,
fn: function() {
console.log(this);
console.log(this.x);
}
}
}
obj.y.fn();
//打印结果为:
// Object {x: 3, fn: function}
// 3
函数嵌套。在函数 y 中,this 指向了调用它的上一级对象 obj。但是在嵌套函数 fn 中,this 并不指向 obj。嵌套的函数不会从调用它的函数中继承 this,当嵌套函数作为函数调用时,其 this 值在非严格模式下指向全局对象,在严格模式是 undefined。
var obj = {
y: function() {
console.log(this === obj);
console.log(this);
fn();
function fn() {
console.log(this === obj);
console.log(this);
}
}
}
obj.y();
//打印结果为:
// true
// Object {y: function}
// false
// Window 全局对象
3.在严格模式和非严格模式中全局调用普通函数的区别
如果普通函数是在全局环境中被调用,在非严格模式下,普通函数中 this 也指向全局对象;如果是在严格模式下,this 将会是 undefined。
function f1 () {
console.log(this)
}
function f2 () {
'use strict'
console.log(this)
}
f1() // window
f2() // undefined
//--非严格模式--
var x = 1
function fn() {
console.log(this); // Window 全局对象
console.log(this.x); // 1
}
fn();
//--严格模式--
"use strict" // 使用严格模式
var x = 1
function fn() {
console.log(this); // undefined
console.log(this.x); // 报错 "Cannot read property 'x' of undefined",因为此时 this 是 undefined
}
fn();
在严格模式下,在全局作用域中,this指向window对象。
//--严格模式--
"use strict" // 使用严格模式
console.log(this); // Window全局对象
4.构造函数调用中的this
使用 new 关键字,通过构造函数生成一个实例对象。此时,this 便指向这个新对象。
var x = 1;
function Fn() {
this.x = 2;
console.log(this); // Fn {x: 2}
}
var obj = new Fn(); // obj和Fn(..)调用中的this进行绑定
console.log(obj.x) // 2
如果构造函数返回了引用类型,this 将指向实例化的新对象。因为Fn()返回(return)的是一个对象(引用类型),this 会指向这个return的对象。
var x = 1
function Fn() {
this.x = 2
return {x: 3}
}
var a = new Fn()
console.log(a.x) // 3
如果return的是一个非引用类型的值,this将被绑定到new Fn()
构造的新对象a。
var x = 1
function Fn() {
this.x = 2
return 3
}
var a = new Fn()
console.log(a.x) // 2
5.call 和 apply 方法调用
如果你想改变 this 的指向,可以使用 call 或 apply 方法。它们的第一个参数都是指定函数运行时其中的this
指向。如果第一个参数不传(参数为空)或者传 null 、undefined,默认 this 指向全局对象(非严格模式)或 undefined(严格模式)。
var x = 1;
var obj = {
x: 2
}
function fn() {
console.log(this);
console.log(this.x);
}
fn.call(obj)
// Object {x: 2}
// 2
fn.apply(obj)
// Object {x: 2}
// 2
fn.call()
// Window 全局对象
// 1
fn.apply(null)
// Window 全局对象
// 1
fn.call(undefined)
// Window 全局对象
// 1
call 和 apply 的区别在于,call 的第二个及后续参数是一个参数列表,apply 的第二个参数是数组。
var x = 1
var obj = {
x: 2
}
function Sum(y, z) {
console.log(this.x + y + z)
}
Sum.call(obj, 3, 4) // 9
Sum.apply(obj, [3, 4]) // 9
6.bind 方法调用
调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,新函数的 this 会永久的指向 bind 传入的第一个参数,无论这个函数是如何被调用的。
var x = 1
var obj1 = {
x: 2
};
var obj2 = {
x: 3
};
function fn() {
console.log(this);
console.log(this.x);
};
var a = fn.bind(obj1);
var b = a.bind(obj2);
fn();
// Window 全局对象
// 1
a();
// Object {x: 2}
// 2
b();
// Object {x: 2}
// 2
a.call(obj2);
// Object {x: 2}
// 2
7.箭头函数中的this
ES6中新增的()=>箭头函数。箭头函数中使用的this
,其实是直接包含它的那个函数或函数表达式中的this。
箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。
var obj = {
y: function() {
console.log(this === obj); // true
console.log(this); // Object {y: function}
var fn = () => {
console.log(this === obj); // true
console.log(this); // Object {y: function}
}
fn();
}
}
obj.y()
下例中,虽然存在两个箭头函数,其实this取决于最外层的箭头函数,由于obj是个对象而非函数,所以this指向为Window全局对象。
var obj = {
y: () => {
console.log(this === obj); // false
console.log(this); // Window 全局对象
var fn = () => {
console.log(this === obj); // false
console.log(this); // Window 全局对象
}
fn();
}
}
obj.y()
同 bind 一样,箭头函数也很“顽固”,我们无法通过 call 和 apply 来改变 this 的指向,即传入的第一个参数被忽略。
var x = 1
var obj = {
x: 2
}
var a = () => {
console.log(this.x)
console.log(this)
}
a.call(obj)
// 1
// Window 全局对象
a.apply(obj)
// 1
// Window 全局对象
8.总结
用一张流程图总结: