[Js茶话会]-this你到底指向谁

265 阅读4分钟

this到底指向谁

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

多种场景下的例子

基础

//1
function a(){
    var user = "tt";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a(); // 相当于window.a

//2
var o = {
    user:"tt",
    fn:function(){
        console.log(this.user);  //tt
    }
}
o.fn(); //o调用的fn, this指向o

//3 当函数中包含this,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
//this指向为“就近原则”
o.b.fn();

事件函数的this

var box=document.getElementById("box");
box.onmouseover=function(){
    console.log(this);//box
}

箭头函数中的this

this指向定义的位置,而不是调用的位置

// 上例中
box.onmouseover = ()=> {console.log(this)} // this为window

//
var a=1;
var obj={
    a:2,
    fn1:()=>{
        console.log(this.a); //this指向window
    },
    fn2:function(){
        console.log(this.a);
    }
}

obj.fn1(); //1
obj.fn2(); //2

自执行函数中的this

非严格模式,this指向window

let obj = {
    name'1',
    getNamefunction(){
        return this.name
    }
}

(function(){
 console.log(arguments[0]()); //this指向window
})(obj.getName)

特别注意

this永远指向的是最后调用它的对象,这里obj.getName赋值给了test,最终调用的还是window.test

let obj = {
    a'1',
    getNamefunction() {
        console.log(this.a); //this指向window,undefined
    }
}
let test = obj.getName
test()

// 当遇到构造函数时,实际是new了一份对象实例赋值给了a,所以a里有user属性
function Fn(){
    this.user = "追梦子";
}
var a = new Fn();
console.log(a.user);

call,apply,bind

都是修改this指向的方法

demo

let name = 'jh'
let age = 12
let obj = {
    name"hello",
    agethis.age,
    getfunction() {
        console.log(this.name + this.age)
    }
}

obj.age // undefined
obj.get() // 'hello',undefined

使用apply,call,bind修改this指向

let name = 'jh'
let age = 12
let obj = {
    name: "hello",
    age: this.age,
    get: function() {
        console.log(this.name + this.age)
    }
}

let kk = {
    name: 'kk',
    age: 11
}

obj.get.call(kk) // kk11
obj.get.apply(kk) //kk11
obj.get.bind(kk)() //kk11

bind返回了一个更改了this指向新函数

apply和call的区别

  • call的参数是用逗号隔开 obj.xx.call(kk,'a','b')

  • apply参数是用的数组 obj.xx.apply(kk,['a','b'])

  • 有些人说call 的性能要比 apply 好一些(尤其是传递给函数的参数超过三个的时候),这个没有验证,暂时先放这吧

bind

bind实际是call的封装,返回一个不是立即执行的函数

Function.prototype.bind = function (context){
    const _this = this
    const args = Array.prototype.slice.call(arguments,1)
    return function (){
        const innerArgs = Array.prototype.slice.call(arguments)
        context.call(_this,args.contact(innerArgs))
    }
}

应用

  • arguments 转数组
Array.prototype.splice.call(arguments)

注意

  • apply或者call传入null或者undefined, this指向window
obj = {
    name'1',
    testfunction (){
        console.log(this.name)
    }
}
obj.test.call(undefined)
  • 一个函数多次被bind,则后续的bind都无效 原因: bind之后相当于把this指向了第一个对象,这时再包裹就无用了。可以参考bind实现方法
test= {
    name: '1',
    getName: function (){
        console.log(this.name)
    }
}

let a = {
    name: '2'
}

let b = {
    name: '3'
}

test.getName.bind(a).bind(b)() //2