JavaScript的this对象四条规则

145 阅读3分钟

表情包1.png

关于this

this关键字是JavaScript中最复杂的机制之一。不得不承认在缺乏清晰的认知下,this关键字就是TM的魔法。

this关键字是函数在运行时生成的一个内部对象,只能在函数内部使用。

var a = 2;
function fn() {
  var a = 4;
  console.log(this.a);  // 2
}
fn();
var a = 2;
function fn() {
  var a = 4;
  console.log(this.a); // 2
}
function bar() {
    var a = 5;
    function baz() {
        fn();
        console.log(this.a); // 2
    };
    baz();
}
bar();

观察这两段代码,虽然第二段代码看起来花里胡哨的。实际上这两段代码都表达一个意思:都是输出window对象属性名为a的值。

这样也就引出this对象的第一条规则:默认绑定

当函数作为普通函数调用时,this会指向全局对象,也就是默认绑定在window对象上。这也就解释了为什么上面 👆 的代码输出的结果都相同, 本质上 fn( ) 相当于 window.fn( ) 不过要注意:在严格模式下('use strict'),全局对象不能被默认绑定,this会绑定到undefined,会报错。

第二条规则:隐式绑定

接下来看下面两段代码

var a = 2;
var obj = {
    a:5,
    fn : fn
}

function fn() {
    console.log(this.a); // 5
}
obj.fn();
var a = 2;
var obj = {
    a:5,
    fn : fn
}

function fn() {
    console.log(this.a); // 2
}
setTimeout(obj.fn,100);

当fn以obj对象的方法调用时,此时this绑定在obj对象上,就像第一段代码表现得那样。可是奇怪的事情发生了,第二段代码也用了obj.fn的方式可是结果还是输出了window对象上的a 。这难道不是魔法?其实并不是,第二段的setTimeout的obj.fn作为参数传递进来,实际上是作为普通函数调用的,所以this指向的是window。

第三条规则:显式绑定

function fn () {
console.log(this.a); // 2
}
var a = 2;
var obj = {
    a: 5,
}
function bar () {
    fn()
}
bar();
function fn () {
console.log(this.a); // 5
}
var a = 2;
var obj = {
    a: 5,
}
function bar () {
    fn.call(obj)
}
bar();

显式绑定相比下就更好判断一些了,当运用显式绑定的方式时,fn调用函数的时候this就被手动绑定到obj对象上去了。通过显示绑定,我们就能指定this的绑定对象了。当然显示绑定还有aplly( )方法和bind( )方法。
call( )方法和aplly( )方法的区别在于参数,第一个参数都是this的指向 但是之后的参数call( )方法传递的参数要一个一个列出来,而apply( )用数组的方式传递参数。bind( )方法也可以改变this的指向,但是bind( )方法改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。

var o1 = { 
    name: "付总",
}
var o2 = {
    name: "小付"
}
function bar(o) {
    console.log(this.name,arguments);
    //付总 Arguments(3) ['付总', 1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    
}
function  bac(o) {
    console.log(this.name,arguments);
    //小付 Arguments(3) ['付总', 1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
bar.call(o1,"付总",1,2)
bar.apply(o2,["付总",1,2]) 

第四条规则:new绑定

 function Person(name,age) {
    this.name = name;
    this.age = age;
 }  
function myNew(constrctor,name,age) {
    const obj = {};
    obj.__proto__ = constrctor.prototype;
    constrctor.call(obj,name,age)
    return obj
}
let fu = myNew(Person,"付总",18);
//Person {name: '付总', age: 18}

用new操作符来调用构造函数时,实际上相当于上面伪代码的过程。第一步创建一个新的空对象,第二步将新对象的[[prototype]]链接到其构造函数的实例对象上,第三步构造函数调用时this绑定到了新对象上,第四步返回这个新对象。

关于规则的优先级补充

四条规则中的优先级排列顺序: new绑定 > 显式绑定 > 隐式绑定 > 默认绑定


当然this熟练掌握还需要多实践,毕竟实践出真知。


最后走过路过不如赞过!!谢谢

5evr1.gif