js|this绑定方式

112 阅读5分钟

一、this默认绑定

函数调用前没有指定任何的对象,默认绑定this指向全局对象,浏览器下是window,node.js下是global

function fn1() {
    let fn2 = function () {
        console.log(this); // window
        fn3();
    }
    fn2();
}
function fn3() {
    console.log(this); //window
}
fn1(); // fn1里实现fn2并调用 //fn2调用fn3 

二、this隐式绑定

1、隐式绑定对象

函数调用时,前面存在对象的情况,this就会隐式的绑定到这个对象上

let obj = {
    name: '花非花,雾非雾',
    func: function () {
        console.log(this.name);
    }
}
obj.func();// 花非花,雾非雾

2、不继承

去掉obj中name属性,返回undefined,因为obj和obj1是2个不同的对象,原型链不同,不存在继承关系

function fn() {
    console.log(this.name);
}
let obj = {
    // name: '花非花,雾非雾',
    func: fn
}
let obj1 = {
    name:'雾里看花',
    o:obj
}
obj1.o.func() //undefined

3、原型继承

虽然obj没有name属性,但是他继承了自己原型上的name属性,所以会输出值

function Fn() { };
Fn.prototype.name = "雾里看花";
function fn() {
    console.log(this.name);
}
let obj = new Fn(); //obj会继承Fn的name属性
obj.func = fn; //设置obj的属性
let obj1 = {
    name: '这是雾都',
    o: obj
}
obj1.o.func(); // 雾里看花

4、隐式丢失:变量赋值

传递参数的时候,this并没有和obj绑定到一起,所以隐式丢失,this指向全局对象

var name = "梦里看花";
let obj = {
    name:'雨天散步',
    fn:function(){
        console.log(this.name);
    }
}
function fn1 (param){
    param();
}
fn1(obj.fn) //浏览器环境下输出 梦里看花

5、隐式丢失:指向新的对象

隐式丢失不全都指向全局对象,如果在调用的过程中,出现了重新调用就会指向新的对象

var name = "看山不是山";
let obj = {
    name: '看水不是水',
    fn: function () {
        console.log(this.name);
    }
}
let obj1 = {
    name: '看花不是花'
}
obj1.fn = obj.fn;
obj1.fn(); //看花不是花

三、this显示绑定

this的显示绑定主要通过call、apply、bind来实现

四、new绑定

js中的构造函数只是使用new来调用普通函数

function Fn(){
  this.name = '雾非雾';
}
let test = new Fn();
console.log(test.name); //雾非雾

五、this绑定优先级

显示绑定>隐式绑定>默认绑定

new绑定>隐式绑定>默认绑定

显示绑定和new绑定不能同时存在,不做比较

六、箭头函数this

箭头函数没有自己的this,箭头函数的this指向取决于外层作用域中的this

箭头函数的this一旦绑定就不会再次修改

七、面试题

1、第一题

var name = 'window';
var obj1 = {
    name: "花非花",
    fn1: function () { //正常属性
        console.log(this.name);
    },
    fn2: () => console.log(this.name), //箭头函数
    fn3: function () { //闭包
        return function () {
            console.log(this.name);
        }
    },
    fn4: function () {
        return () => console.log(this.name); //返回箭头函数
    }
}
var obj2 = {
    name: '雾非雾'
};
obj1.fn1();//花非花
obj1.fn1.call(obj2);//雾非雾

obj1.fn2();//undefined
obj1.fn2.call(obj2);//undefined

obj1.fn3()();//undefined
obj1.fn3().call(obj2);//雾非雾
obj1.fn3.call(obj2)();//undefined

obj1.fn4()();//花非花
obj1.fn4().call(obj2);//花非花
obj1.fn4.call(obj2)();//雾非雾

第一个输出花非花,属于正常输出

第二个输出雾非雾,属于正常的显式改变this指向

第3个输出window,fn2的特殊性是箭头函数,箭头函数的this是外部作用域,obj1不是函数,无法形成函数作用域,所以this只能指向全局作用域,window

第4个输出window,箭头函数的this一旦指定,就不会因为显示绑定而改变

第5个输出window,fn3是个闭包等价于以下代码 执行fn()等价于执行window.fn();所以返回window

var fn = obj1.fn3();
fn();

第6个输出雾非雾,等价于以下代码

 var fn  = obj1.fn3();
fn.call(obj2); // 改变了this的指向

第7个输出window,等价于以下代码

var fn = obj1.fn3.call(obj2);
window.fn(); //默认绑定

第8个输出花非花,fn4返回一个箭头函数,箭头函数的作用域是外部,外部是函数fn4(),fn4的this是obj1

第9个输出花非花,这种写法可以理解成,想改变fn4内部箭头函数this的指向,但是箭头函数this不可以改变

第10个输出雾非雾这种写法理解成,改变的是fn4的指向,fn4的指向变了,this自然就变了

2、第二题

var name = "window";
function Person(name) {
    this.name = name;
    this.fn1 = function () {
        console.log(this.name);
    },
        this.fn2 = () => console.log(this.name),
        this.fn3 = function () {
            return function () {
                console.log(this.name);
            }
        },
        this.fn4 = function () {
            return () => console.log(this.name);
        }
}
var obj1 = new Person('花非花');
var obj2 = new Person('雾非雾');
obj1.fn1(); //花非花
obj1.fn1.call(obj2);//雾非雾

obj1.fn2();//花非花
obj1.fn2.call(obj2);//花非花

obj1.fn3()();//undefined
obj1.fn3().call(obj2);//雾非雾
obj1.fn3.call(obj2)();//undefined

obj1.fn4()();//花非花
obj1.fn4().call(obj2);//花非花
obj1.fn4.call(obj2)();//雾非雾

2种方式只有在箭头函数fn2处,输出不同

image (4).png

第一个输出花非花,属于正常输出

第二个输出雾非雾,属于正常的显式改变this指向

第3个输出的是花非花,因为对于对象obj1{}来说,无法创建自己的函数作用域,只能用全局的作用域,但是对于new obj1()来说,创建了自己函数作用域,所以箭头函数this继承函数作用域

第4个输出window,箭头函数的this一旦指定,就不会因为显示绑定而改变

第五个输出window,返回闭包本质上被window调用,this被修改。

第六个输出雾非雾,返回闭包后利用call方法显式绑定指向obj2。

第七个输出window,返回闭包还是被window调用。

第8个输出花非花,fn4返回一个箭头函数,箭头函数的作用域是外部,外部是函数fn4(),fn4的this是obj1

第9个输出花非花,这种写法可以理解成,想改变fn4内部箭头函数this的指向,但是箭头函数this不可以改变

第10个输出雾非雾这种写法理解成,改变的是fn4的指向,fn4的指向变了,this自然就变了

参考👀

js 五种绑定彻底弄懂this,默认绑定、隐式绑定、显式绑定、new绑定、箭头函数绑定详解

js 从两道面试题加深理解闭包与箭头函数中的this