题目
浏览器环境下,请写出下题的打印内容
var age = 18
function fn() {
console.log(this.age)
}
var hunter = {
age: 27,
getAge: function (fn) {
fn()
return this.age
}
}
console.log(hunter.getAge(fn)) // 输出 => __________
var foo = hunter.getAge
console.log(foo(fn)) // 输出 => ___________
分析题目
对于上面这道题,我们首先从上到下过一遍,可以很清楚的知道这道题的考点是考察我们对this指向的掌握情况,既然知道了要考察的点,那我们大脑里要很快梳理出来关于this指向相关的特点。
用一句话来总结的话就是:谁调用了当前的函数,那么这个函数的this就指向谁。下面我们展开来说,整体大致分为以下这几种情况:
- 作为函数调用,this指向全局对象
- 作为对象的方法调用,该对象即为调用上下文,this指向该对象。
- 作为构造函数调用,构造函数试图初始化这个新创建的对象,并将这个对象作为其调用上下文,this 指向这个新创建的对象。
- 通过函数的call/apply方法间接调用, call/apply方法的第一个参数是调用上下文,在函数体内,通过this获得对它的引用。
- 使用bind()方法改变this指向,同时返回一个新的函数,并且使用这个新函数来作为构造函数的时候,执行时this指向会失效。
知道了这些知识点对于上面这道题就是小儿科了,下面我们从上到下来一步一步进行分析:
- 在全局上下文中定义了变量
age和函数fn及对象hunter。 - 在函数
fn内部打印了this.age,在对象hunter中有两个属性,age: 27和getAge函数,getAge函数接收了一个函数fn作为参数,并在内部直接调用了fn,同时返回this.age - 接下来输出执行了
hunter.getAge(fn),结合上面总结的this指向的特点,我们先抛开形参fn不管,getAge函数的调用者是hunter,那么它的this指向肯定指向hunter,hunter对象内有age属性,那么函数体内的return this.age得到的结果一定是27了。 - OK ,再来看
fn这个参数,这个fn是由外部定义的fn传进来的,这里面又涉及到一个知识点词法作用域,函数在执行时,分为两个阶段:预编译阶段和执行阶段,在预编译阶段也就是创建执行上下文,执行上下文初始化属性创建作用域链、使用arguments创建活动对象、初始化活动对象(形参,函数声明,变量声明 ),将活动对象压入作用域链顶端。那么对于这道题来说,fn函数在全局上下文中声明创建存在了一条作用域链,此时的this是window,而getAge函数体内的形参fn的引用是指向外部的fn的,所以fn打印出来的是18。 - 下面接着往下看,
var foo = hunter.getAge, 这段代码是将函数getAge赋值给了新定义的变量foo,此时的foo相当于window.foo,因此下面的打印结果全部都是18了。
打印结果
打印结果分别为:18 27 18 18
以上就是今天的全部内容了。