daily-interview / fe-interview

:smiley: 每日一道经典前端面试题,一起共同成长。
https://blog.csdn.net/u010494753
MIT License
173 stars 22 forks source link

谈一谈你对this指针的理解 #13

Open artdong opened 5 years ago

artdong commented 5 years ago

谈一谈你对this指针的理解

artdong commented 5 years ago

为什么要用this

this提供了一种更优雅的方法来隐式传递一个对象的引用,因此可以将API设计得更加简洁并且易于复用。

什么是 this

this 就是一个指针,指向我们调用函数的对象。

this的值由什么决定

this的值并不是由函数定义放在哪个对象里面决定,而是函数执行时由谁来唤起决定。

什么是执行上下文

执行上下文 是语言规范中的一个概念,用通俗的话讲,大致等同于函数的执行“环境”。具体的有:变量作用域(和 作用域链条,闭包里面来自外部作用域的变量),函数参数,以及 this 对象的值。

现在起,我们专注于查明 this 关键词到底指向哪。因此,我们现在要思考的就一个问题:

为了理解这个关键概念,我们来测一下下面的代码。

let person = {
    name: "Jay",
    greet: function() {
        console.log("hello, " + this.name);
    }
};
person.greet();

谁调用了 greet 函数?是 person 这个对象对吧?在 greet() 调用的左边是一个 person 对象,那么 this 关键词就指向 person,this.name 就等于 "Jay"。现在,还是用上面的例子,我加点料:

let greet = person.greet; // 将函数引用存起来;
greet(); // 调用函数

你觉得在这种情况下控制台会输出什么?“Jay”?undefined?还是别的?

正确答案是 undefined。这说明this 的值并不是由函数定义放在哪个对象里面决定,而是函数执行时由谁来唤起决定。

思考题

找出 this 的指向

let name = "Jay Global";
let person = {
    name: 'Jay Person',
    details: {
        name: 'Jay Details',
        print: function() {
            return this.name;
        }
    },
    print: function() {
        return this.name;
    }
};
console.log(person.details.print());  // ?
console.log(person.print());          // ?
let name1 = person.print;
let name2 = person.details;
console.log(name1()); // ?
console.log(name2.print()) // ?

词法作用域

词法作用域也就是在词法阶段定义的作用域,也就是说词法作用域在代码书写时就已经确定了。箭头函数就是遵循词法作用域。

this 和 箭头函数

在 ES6 里面,不管你喜欢与否,箭头函数被引入了进来。对于那些还没用惯箭头函数或者新学 JavaScript 的人来说,当箭头函数和 this 关键词混合使用时会发生什么,这个点可能会给你带来小小的困惑和蛋蛋的忧伤。

当涉及到 this 关键词,箭头函数 和 普通函数 主要的不同是什么?

箭头函数按词法作用域来绑定它的上下文,所以 this 实际上会引用到原来的上下文。

思考题

找出this指向

let object = {
    data: [1,2,3],
    dataDouble: [1,2,3],
    double: function() {
        console.log("this inside of outerFn double()");
        console.log(this);
        return this.data.map(function(item) {
            console.log(this);      // 这里的 this 是什么??
            return item * 2;
        });
    },
    doubleArrow: function() {
        console.log("this inside of outerFn doubleArrow()");
        console.log(this);
        return this.dataDouble.map(item => {
            console.log(this);      // 这里的 this 是什么??
            return item * 2;
        });
    }
};
object.double();
object.doubleArrow();