this 常见的面试题汇总

2019-10-12  本文已影响0人  饥人谷1904_陈俊锋

上一节我们了解到了 call 和 apply,通过他俩 我们来看看函数执行的本质是什么

当我们执行一个函数,有以下几种调用方式等价

函数直接调用情况下

"use strict" 
function fn(a, b) {
  console.log(this)
}
fn(1, 2)
// 等价于
fn.call( undefined, 1, 2 )
fn.apply( undefined, [1, 2] )

可以看到:

对象方法调用的情况下

var obj = {
    fn: function(a, b){
        console.log(this)
    },
    child: {
        fn2: function(){
            console.log(this)
        }
    }
}
obj.fn(1, 2)
//等价于
obj.fn.call(obj, 1, 2)         // 所以 this 是 obj
obj.fn.apply(obj, [1, 2])

obj.child.fn2()
//等价于
obj.child.fn2.call(obj.chid)    // 所以 this 是 obj.child

通过 call 和 apply 我们理解了原理之后来看看下面的测试题

let name = '饥人谷'
let people = {
    name: '若愚',
    sayName: function(){
        console.log(this.name)
    }
}
let sayAgain = people.sayName
function sayName(){
    console.log(this.name)
}

sayName()
/*
 解析:相当于 `sayName.call(undefined)` ,因为是非严格模式,所以 this 被替换成 Window,所以这里输出全局的 name 即 "饥人谷"
*/
people.sayName()
/*
解析: 相当于 `people.sayName.call(people)` ,所以这里输出 `people.name` 即 "若愚"
*/

sayAgain()
/*
解析: 相当于 `sayAgain.call(undefined)` ,,因为是非严格模式,所以 this 被替换成 Window,所以这里输出全局的 name 即 "饥人谷"
*/

var arr = []
for(var i=0; i<3; i++){
    arr[i] = function(){ console.log(this) }
}
var fn = arr[0]

arr[0]()
/*
解析: 因为函数是个特殊的对象,所以 arr 相当于 { '0': function(){}, '1': function(){}, '2': function(){}, length:3}
arr[0]相当于 `arr['0']` 相当于 `arr.0` (当然这种写法不符合规范),所以 arr[0]等价于 arr.0.call(arr), this就是 arr
*/

fn()
/*
解析: 相当于 `fn.call(undefined)`, 所以 fn 里面的 this 是 Window
*/

bind

bind 的作用和 call 与 apply 类似,区别在使用上
bind 的执行结果返回的是绑定了一个对象的新函数

先看一个简单一点的例子

var obj = {name: '饥人谷'}
function sayName(){
    console.log(this.name)
}
var fn = sayName.bind(obj)  // 注意 这里 fn 还是一个函数,功能和 sayName 一模一样,区别只在于它里面的 this 是 obj
fn() // 输出: '饥人谷'

再看一个实际一点的例子

var app = {
    container: document.querySelector('body'),
    bind: function(){
        this.container.addEventListener('click', this.sayHello)                  //点击的时候会执行 sayHello,sayHello 里面的 this 代表 body 对象
        this.container.addEventListener('click', this.sayHello.bind(this))  //点击的时候会执行 sayHello,sayHello 里面的 this 代表 app 对象
    },
    sayHello: function(){
       console.log(this)
    }
}
app.bind()

箭头函数

ES6 标准中,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

同样先看一个简单点的例子

let app = {
    fn1: function(a){
        console.log(this)  //app
    },
    fn2(a) {
        consoel.log(this)  //app
    },
    fn3: (a)=>{
        console.log(this)  //window
    }
}

粗略一看,fn1、fn2、fn3 貌似都一样,实际上 fn1和 fn2完全等价,但 fn3是有区别的
以上代码等同于

app.fn2.call(app)
app.fn3.call( 它的上一级的 this )

再看一个复杂点的例子就清楚了

var app = {
    init() {
        var menu = {
            init: ()=>{
                console.log(this)
            },
            bind() {
                console.log(this)   
            }
        }
        menu.init() 
         /*相当于  menu.init.call(menu 所在的环境下的 this)  , 所以 init 里面的 this 也就是 app。
         (假设 app.init 也是箭头函数,想想 menu.init 里面的 this 是什么?)          
         (答案是:window)
         */
        menu.bind() 
        /*相当于 menu.bind.call(menu),也就是 menu,所以 bind 里面的 this 就是 menu
        */
    }
}
app.init()

理解了原理之后,我们再来看看下面的题目

var app = {
    fn1() {
        setTimeout(function(){
            console.log(this)
        }, 10)
    },
    fn2() {
        setTimeout(()=>{
            console.log(this)
        },20)
    },
    fn3() {
        setTimeout((function(){
            console.log(this)
        }).bind(this), 30)        
    },
    fn4: ()=> {
        setTimeout(()=>{
            console.log(this)
        },40)        
    }
}
app.fn1()
app.fn2()
app.fn3()
app.fn4()

以上代码相当于

var app = {
    fn1() {
        function fn(){
            console.log(this)
        }
        //过10ms 后执行
        //fn.call(undefined) ,所以输出 Window
    },
    fn2() {
        //过20ms 执行箭头函数
        //箭头函数里面没资格有 自己的 this,借用 setTimeout 外面的 this,也就是 app
    },
    fn3() {
        // 创建了一个新函数,这个新函数里面绑定了 外面的this,也就是 app
        // 20 ms 后执行新函数,输出 this,也就是刚刚绑定的 app    
    }
    fn4: ()=> {
        //过40ms 执行箭头函数
        //箭头函数里面没资格有 this,用 setTimeout 外面的 this
        //setTimeout 所在的 fn4也是箭头函数,没资格拥有自己的 this,借用外面的 this ,也就是 Window     
    }
}

转载自 饥人谷this 常见面试题汇总

上一篇下一篇

猜你喜欢

热点阅读