this的那些事
this用法
全局上下文
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this
都指向全局对象。
// 在浏览器中, window 对象同时也是全局对象: console.log(this === window); // true a = 37; console.log(window.a); // 37 this.b = "MDN"; console.log(window.b) // "MDN" console.log(b) // "MDN"
函数上下文
在函数内部,this的值取决于函数被调用的方式。
因为下面的代码不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象,浏览器中就是 window。
function f1(){ return this; } //在浏览器中: f1() === window; //在浏览器中,全局对象是window //在Node中: f1() === globalThis;
function f2(){ "use strict"; // 这里是严格模式 return this; } f2() === undefined; // true
在第二个例子中,this 应是 undefined,因为 f2 是被直接调用的,而不是作为对象的属性或方法调用的(如 window.f2())。有一些浏览器最初在支持严格模式时没有正确实现这个功能,于是它们错误地返回了window对象。
类上下文
class Example { constructor() { console.log("Example--this", this) const proto = Object.getPrototypeOf(this); console.log(Object.getOwnPropertyNames(proto)); } first(){} second(){} static third(){} } new Example(); // ['constructor', 'first', 'second'] // 注意:静态方法不是 this 的属性,它们只是类自身的属性。
// 对象可以作为 bind 或 apply 的第一个参数传递,并且该参数将绑定到该对象。 var obj = {a: 'Custom'}; // 声明一个变量,并将该变量作为全局对象 window 的属性。 var a = 'Global'; function whatsThis() { return this.a; // this 的值取决于函数被调用的方式 } whatsThis(); // 'Global' 因为在这个函数中 this 没有被设定,所以它默认为 全局/ window 对象 whatsThis.call(obj); // 'Custom' 因为函数中的 this 被设置为obj whatsThis.apply(obj); // 'Custom' 因为函数中的 this 被设置为obj
显示的改变的指向 call、apply、bind方法
this 和对象转换
function add(c, d) { return this.a + this.b + c + d; } var o = {a: 1, b: 3}; // 第一个参数是用作“this”的对象 // 其余参数用作函数的参数 add.call(o, 5, 7); // 16 // 第一个参数是用作“this”的对象 // 第二个参数是一个数组,数组中的两个成员用作函数参数 add.apply(o, [10, 20]); // 34
在非严格模式下使用 call
和 apply
时,如果用作 this
的值不是对象,则会被尝试转换为对象。null
和 undefined
被转换为全局对象。原始值如 7
或 'foo'
会使用相应构造函数转换为对象。因此 7
会被转换为 new Number(7)
生成的对象,字符串 'foo'
会转换为 new String('foo')
生成的对象。
function bar() { console.log(Object.prototype.toString.call(this)); } bar.call(7); // [object Number] bar.call('foo'); // [object String] bar.call(undefined); // [object global]
bind方法(返回的一个函数)
ECMAScript 5 引入了 Function.prototype.bind()。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
function f(){ return this.a; } var g = f.bind({a:"azerty"}); console.log(g()); // azerty var h = g.bind({a:'yoo'}); // bind只生效一次! console.log(h()); // azerty var o = {a:37, f:f, g:g, h:h}; console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty
隐式改变this指向
function A(name){ this.name=name console.log('A-->', this) } let a1 =new A('lucy') console.log('a1', a1.name, a1.__proto__, a1.__proto__==A.prototype)
可以看到实例a1. this指向构造函数
一般谁调用this指向谁,对象调用指向对象,函数调用指向函数,如果函数有返回值返回值不是对象类型,this还是指向函数的实例
箭头函数比较特殊
箭头函数在箭头函数中,this与封闭词法环境的this保持一致。在全局代码中,它将被设置为全局对象:
var globalObject = this; var foo = (() => this); console.log(foo() === globalObject); // true
注意:如果将this传递给call、bind、或者apply来调用箭头函数,它将被忽略。不过你仍然可以为调用添加参数,不过第一个参数(thisArg)应该设置为null。
// 接着上面的代码 // 作为对象的一个方法调用 var obj = {foo: foo}; console.log(obj.foo() === globalObject); // true // 尝试使用call来设定this console.log(foo.call(obj) === globalObject); // true // 尝试使用bind来设定this foo = foo.bind(obj); console.log(foo() === globalObject); // true
来几个例子
let name="globalname" const obj = { name: 'lily', age: ()=>{ console.log("obj-age", this, '--', this.name, '--name--',name) function demo(){ console.log("obj-demo", this, '--',this.name, '--name--',name) } demo() }, bar: function() { console.log('obj--bar>', this, '--',this.name) const x = (() => this.name); console.log('obj--x>', this, '--', x()) } }; obj.age() obj.bar()
在来几个例子
function fn1() { this.name = 'hello1'; return {}; } var a = new fn1(); console.log(a.name); //undefined function fn2() { this.age = 18; return function(){}; } var a = new fn2(); console.log(a.age); //undefined function fn3() { this.name = 'hello3'; return 1; } var a = new fn3; console.log(a.name); //hello3
obj={ name: 'hi', fn: function(){ setTimeout(() => { console.log(this, this.name) }, 200); } } obj.fn()
待更新