JS的this指向

102 阅读3分钟

this指向是什么

函数在调用时,js会默认给this绑定一个值。 this的值只与调用方式和调用位置有关; this是在运行时被绑定的;

this的绑定规则

  1. 默认绑定 独立函数调用(函数没有被绑定在某个对象上进行调用)
  2. 隐式绑定 通过某个对象进行调用(调用位置是通过某个对象发起的)
  3. 显示绑定 隐式绑定需要在调用的对象内部有一个对函数的引用(比如属性),如果我们不希望在对象内部包含这个函数的引用,同时又希望在这个对象上进行强制调用,可以使用 apply、call、bind
  4. new绑定 js中函数可以当作一个类的构造函数来使用 使用new关键字调用的函数,会执行如下操作: 创建一个新的对象;新对象被执行prototype连接;新对象绑定到函数调用的this上;如果函数没有淡灰其他对象,表达式会返回这个新对象
    function Person(name) {
        console.log(this) //Person {}
        this.name = name // Person {name: "why"}
    }
    var p = new Person("why")
    console.log(p)

内置函数的绑定

当我们调用js的内置函数,或第三方库中的内置函数时,我们会传入另一个函数,js内部或第三方库会执行,这时候函数中的this需按经验判断

setTimeout —— window
forEach —— 数组中每一个对象;forEach第二个参数可以指定this绑定对象
div.onclick —— div

this规则之外

  1. 忽略显示绑定:如果显示绑定中,传入了null和undefined,那么显示绑定会被忽略,使用默认规则; 严格模式下this是null、undefined
function foo() {
    console.log(this)
}
var obj = {
    name = "why"
}
foo.call(obj); //obj
foo.call(null); //window
foo.call(undefined); /window

var bar = foo.bind(null);
bar(); //window
  1. 间接函数引用:创建一个函数的间接引用,使用默认绑定规则
function foo() {
    console.log(this)
}

var obj1 = {
    name: "obj1",
    foo: foo
}
var obj2 = {
    name: "obj2"
}

obj1.foo(); //obj1
(obj2.foo = obj1.foo)(); //window
  1. ES6箭头函数this 箭头函数不使用this的四种标准,根据外层作用域决定this

this的规则优先级

  1. 默认规则优先级最低
  2. 显示高于隐式
  3. new高于隐式
  4. new高于bind

apply、call、bind

function.apply(thisArg, [argsArray])
function.call(thisArg, arg1, arg2, ...)
function.bind(thisArg, arg1, arg2, ...)
bind()方法创建新的绑定函数,绑定函数是一个怪异函数对象ECMAScript 2015。
调用时除第一个参数,其他将作为新函数的参数,也可以在调用时传参

面试题

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


//window
//person
//person
//window
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
//person2

//window
//window

//window
//window
//person2

//person1
//person2
//person1
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('ps1');
var person2 = new Person('ps2');

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);

//ps1
//ps2

//ps1
//ps1

//window
//window
//ps2

//ps1
//ps2
//ps1
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('ps1');
var person2 = new Person('ps2');

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);

//window
//window
//ps2

//obj
//ps2
//obj