关于 this 的问题,我们只需要记住一个原则,谁调用的我,我的 this 就指向谁(尖头函数和 new 的情况除外除外)。
普通函数的 this
题目:请写出输出值,并解释为什么
this.a = 20;function go() {console.log(this.a);this.a = 30;}go.prototype.a = 40;var test = {a: 50,init: function (fn) {fn();console.log(this.a);return fn;}};console.log((new go()).a);test.init(go);var p = test.init(go);p();
- 普通函数的
this是谁调用它,this就指向谁!
var name = "window";var o = {name: "o",init: function() {console.log(this.name);}}o.init(); // ovar init = o.init;init(); // window
- 调用实例化对象的属性时,是先从构造函数中查找,如果没有找到则在原型链上逐级寻找
所以输出如下
- 40 // 因为在
console时构造函数中还没有定义属性a,所有会找到原型链上的a - 30 // 此时构造函数上中已经定义了属性
a了,所以输出 30 - 20 //
test.init中的fn是直接调用,并没有依附任何对象,所以fn中的this指向window,所以输出 20,注意这一步又把window的a赋值为 30 了 - 50 //
init因为是从test调用的,所以this指向test,所以输出 50 - 30 //
fn的this依然是window,因为上一步window.a被修改了,所以输出 30 - 50 //
init因为是从test调用的,所以this指向test,所以输出 50 - 30 //
fn被return出来了,但是依然是直接调用的,this还是指向window,所以输出还是 30箭头函数的 this
题目:请写出输出值,并解释为什么 ```javascript this.a = 50;
var app = { start: function () { var test2 = { a: 30, demo: { a: 70, init: () => { console.log(this) console.log(this.a) } } } test2.demo.init(); var init = test2.demo.init; init() } }
app.start();
const start = app.start; start();
箭头函数的 `this` 永远和当前执行环境的 `this` 相同!```javascriptapp.start();
当前环境的 this 指向 app ,所以 init 不管怎么调用, this 都指向 app
const start = app.start;start();
当前环境的 this 指向 window ,所以 init 不管怎么调用, this 都指向 window
属性查找优先级
题目:请写出输出值,并解释为什么
function C1(name) {if (name) this.name = name;}function C2(name) {this.name = name;}function C3(name) {this.name = name || 'fe';}C1.prototype.name = "yideng";C2.prototype.name = "lao";C3.prototype.name = "yuan";console.log((new C1().name) + (new C2().name) + (new C3().name));
所有的构造函数都没有传参
- C1 因为判断了
name是否有效,不会在构造函数中创建属性a,所以会在原型链中寻在,输出为"yideng" - C2
name没有传所以值为undefined,输出为undefined - C3 因为有
||,所以name被赋值为"fe",输出为“fe”
所以最终输出为 "yidengundefinedfe"
🚀 推荐阅读
