一 this相关的面试题

1.1 面试题一

var name = "window";  
var person = {  
  name: "person",  
  sayName: function () {  
    console.log(this.name);  
  }  
};  
function sayName() {  
  var sss = person.sayName;  
  sss();   
  person.sayName();   
  (person.sayName)();   
  (= person.sayName)();   
}  
sayName();

这道面试题非常简单,无非就是绕一下,希望把面试者绕晕:

function sayName() {  
  var sss = person.sayName;  
  // 独立函数调用,没有和任何对象关联  
  sss(); // window  
  // 关联  
  person.sayName(); // person  
  (person.sayName)(); // person  
  (= person.sayName)(); // window  
}

1.2 面试题二

var name = 'window'  
var person1 = {  
  name: 'person1',  
  foo1: function () {  
    console.log(this.name)  
  },  
  foo2: () => console.log(this.name),  
  foo3: function () {  
    return function () {  
      console.log(this.name)  
    }  
  },  
  foo4: function () {  
    return () => {  
      console.log(this.name)  
    }  
  }  
}  
  
var person2 = { name: 'person2' }  
  
person1.foo1();   
person1.foo1.call(person2);   
  
person1.foo2();  
person1.foo2.call(person2);  
  
person1.foo3()();  
person1.foo3.call(person2)();  
person1.foo3().call(person2);  
  
person1.foo4()();  
person1.foo4.call(person2)();  
person1.foo4().call(person2);

下面是代码解析:

// 隐式绑定,肯定是person1  
person1.foo1(); // person1  
// 隐式绑定和显示绑定的结合,显示绑定生效,所以是person2  
person1.foo1.call(person2); // person2  
  
// foo2()是一个箭头函数,不适用所有的规则  
person1.foo2() // window  
// foo2依然是箭头函数,不适用于显示绑定的规则  
person1.foo2.call(person2) // window  
  
// 获取到foo3,但是调用位置是全局作用于下,所以是默认绑定window  
person1.foo3()() // window  
// foo3显示绑定到person2中  
// 但是拿到的返回函数依然是在全局下调用,所以依然是window  
person1.foo3.call(person2)() // window  
// 拿到foo3返回的函数,通过显示绑定到person2中,所以是person2  
person1.foo3().call(person2) // person2  
  
// foo4()的函数返回的是一个箭头函数  
// 箭头函数的执行找上层作用域,是person1  
person1.foo4()() // person1  
// foo4()显示绑定到person2中,并且返回一个箭头函数  
// 箭头函数找上层作用域,是person2  
person1.foo4.call(person2)() // person2  
// foo4返回的是箭头函数,箭头函数只看上层作用域  
person1.foo4().call(person2) // person1

1.3 面试题三

var name = 'window'  
function Person (name) {  
  this.name = name  
  this.foo1 = function () {  
    console.log(this.name)  
  },  
  this.foo2 = () => console.log(this.name),  
  this.foo3 = function () {  
    return function () {  
      console.log(this.name)  
    }  
  },  
  this.foo4 = function () {  
    return () => {  
      console.log(this.name)  
    }  
  }  
}  
var person1 = new Person('person1')  
var person2 = new Person('person2')  
  
person1.foo1()  
person1.foo1.call(person2)  
  
person1.foo2()  
person1.foo2.call(person2)  
  
person1.foo3()()  
person1.foo3.call(person2)()  
person1.foo3().call(person2)  
  
person1.foo4()()  
person1.foo4.call(person2)()  
person1.foo4().call(person2)

下面是代码解析:

// 隐式绑定  
person1.foo1() // peron1  
// 显示绑定优先级大于隐式绑定  
person1.foo1.call(person2) // person2  
  
// foo是一个箭头函数,会找上层作用域中的this,那么就是person1  
person1.foo2() // person1  
// foo是一个箭头函数,使用call调用不会影响this的绑定,和上面一样向上层查找  
person1.foo2.call(person2) // person1  
  
// 调用位置是全局直接调用,所以依然是window(默认绑定)  
person1.foo3()() // window  
// 最终还是拿到了foo3返回的函数,在全局直接调用(默认绑定)  
person1.foo3.call(person2)() // window  
// 拿到foo3返回的函数后,通过call绑定到person2中进行了调用  
person1.foo3().call(person2) // person2  
  
// foo4返回了箭头函数,和自身绑定没有关系,上层找到person1  
person1.foo4()() // person1  
// foo4调用时绑定了person2,返回的函数是箭头函数,调用时,找到了上层绑定的person2  
person1.foo4.call(person2)() // person2  
// foo4调用返回的箭头函数,和call调用没有关系,找到上层的person1  
person1.foo4().call(person2) // person1

1.4 面试题四

var name = 'window'  
function Person (name) {  
  this.name = name  
  this.obj = {  
    name: 'obj',  
    foo1: function () {  
      return function () {  
        console.log(this.name)  
      }  
    },  
    foo2: function () {  
      return () => {  
        console.log(this.name)  
      }  
    }  
  }  
}  
var person1 = new Person('person1')  
var person2 = new Person('person2')  
  
person1.obj.foo1()()  
person1.obj.foo1.call(person2)()  
person1.obj.foo1().call(person2)  
  
person1.obj.foo2()()  
person1.obj.foo2.call(person2)()  
person1.obj.foo2().call(person2)

下面是代码解析:

// obj.foo1()返回一个函数  
// 这个函数在全局作用于下直接执行(默认绑定)  
person1.obj.foo1()() // window  
// 最终还是拿到一个返回的函数(虽然多了一步call的绑定)  
// 这个函数在全局作用于下直接执行(默认绑定)  
person1.obj.foo1.call(person2)() // window  
person1.obj.foo1().call(person2) // person2  
  
// 拿到foo2()的返回值,是一个箭头函数  
// 箭头函数在执行时找上层作用域下的this,就是obj  
person1.obj.foo2()() // obj  
// foo2()的返回值,依然是箭头函数,但是在执行foo2时绑定了person2  
// 箭头函数在执行时找上层作用域下的this,找到的是person2  
person1.obj.foo2.call(person2)() // person2  
// foo2()的返回值,依然是箭头函数  
// 箭头函数通过call调用是不会绑定this,所以找上层作用域下的this是obj  
person1.obj.foo2().call(person2) // obj