this 在各个场景中取什么值,是在函数执行的时候确认的,不是在函数定义的时候确认的。
普通函数中,无调用对象 —— 指向 window
- 在非严格模式下,this 指向全局对象 window
- 在严格模式下,this 为undefined
function fun() { console.log(this); // 打印 window 对象 console.log(this.name); // 打印 "全局的name属性" } var name = "全局的name属性"; fun();
通过 bind 绑定 —— 指向第一个参数
this 指向 bind 方法的第一个参数(对箭头函数无效)
function fn() { console.log(this); } const fn1 = fn.bind({ x: 200 }); fn1(); // 打印 { x: 200 }
通过 call 和 apply 调用 —— 指向第一个参数
this 指向call和apply方法的第一个参数(对箭头函数无效)
function fn() { console.log(this); } fn.call({ x: 100 }); // 打印 { x: 100 }
var some_obj = { name: 'Ninja', say: function(who){ return 'Haya ' + who + ', I am a ' + this.name; } }; > some_obj.say('Dude'); "Haya Dude, I am a Ninja" > var my_obj = {name: 'Scripting guru'}; > some_obj.say.call(my_obj, 'Dude'); "Haya Dude, I am a Scripting guru"
调用 say() 函数的对象方法 call() 时传递了两个参数:对象 my_obj 和字符串 ‘Dude’ 。
当say() 被调用时,其中的 this 被自动设置成了my_obj 对象的引用。
因而,this.name返回的不再是Ninja,而是Scripting guru。
函数作为对象方法被调用 —— 指向对象
this 指向该对象
function fun() { console.log(this); // 打印 obj2 对象 console.log(this.name); // 打印 "vae" } var obj2 = { name: "vae", sayName: fun }; var name = "全局的name属性"; //以方法的形式调用,this是调用方法的对象 obj2.sayName();
函数作为实例方法被调用 —— 指向实例
this 指向实例
// 创建一个构造函数,专门用来创建Person对象 function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; this.sayName = function() { console.log(this.name); // 打印 "孙悟空" }; } let per = new Person("孙悟空", 18, "男"); per.sayName()
如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的this将被丢弃。
箭头函数中的 this —— 指向外层的 this
继承外层函数的 this (使用 call , bind , apply 都无法改变 this 的指向)
经典问题如下:
var greeter = { default: "Hello ", greet: function (names){ names.forEach(function(name) { console.log(this.default + name); //此时的this是全局的window,不能读取对象的属性default }) } } console.log(greeter.greet(['world', 'heaven']))
传统的解决方案——将this赋值给一个临时变量,然后在回调函数中访问:
var greeter = { default: "Hello ", greet: function (names){ let that = this names.forEach(function(name) { console.log(that.default + name); }) } } console.log(greeter.greet(['world', 'heaven']))
箭头函数可直接解决此问题——this继承外层函数调用的this绑定,此时的this是对象greeter
var greeter = { default: "Hello ", greet: function (names){ names.forEach(name=> { console.log(this.default + name); //该子程序可以使用词法'this' }) } } console.log(greeter.greet(['world', 'heaven']))
- this 都指向当前对象 zhangsan
类的静态方法中的 this —— 指向类
// class 相关的 this class Foo { f1() { console.log('this1', this) } f2 = () => { console.log('this2', this) } f3 = () => { console.log('this3', this) } static f4() { console.log('this4', this) } } const f = new Foo() f.f1() // 打印 this1 f 实例方法中的this 指向 实例 f.f2() // 打印 this2 f 箭头函数中的this 指向外层 -- 也是实例 f.f3.call(this) // 打印 this3 f call 无法改变箭头函数的this指向,所以还是实例 Foo.f4() // 打印 this4 Foo 类的静态方法中的this指向类
自测题 1
答案:
1 undefined
- User.getCount() 是执行对象方法,this 指向该对象,其 count 属性值为 1
- func() 是普通函数,无调用对象,this 指向 window , 因全局没有 count 变量,window.count 为 undefined
自测题 2
const obj = { f1() { const fn = () => { console.log(this); }; fn(); fn.call(Window); }, f2: () => { function fn() { console.log(this); } fn(); fn.call(this); }, }; obj.f1(); obj.f2();
答案:
obj对象 obj对象 Window对象 Window对象
- 普通函数无调用对象,指向 Window
- 箭头函数指向外层 this
- call 无法改变箭头函数的 this 指向