Js this绑定规则细节和面试分析

this绑定规则细节和面试分析

默认绑定

独立函数调用的情况下默认绑定

独立的函数调用我们可以理解成函数没有绑定到某个对象进行调用

【案例】:

function foo() {
	console.log(this)
}

foo() // window
function test1() {
	console.log(this) // window
    test2()
}

function test2() {
	console.log(this) // window
    test3()
}

function test3() {
	console.log(this) // window
}

test1();
function foo(func){
    func()
}

var obj = {
	name:"why",
    bar: function() {
        console.log(this) // window
    }
}

foo(obj.bar)

隐式绑定

它的调用位置中,是通过某个对象发起的函数调用

【案例】

function foo() {
	console.log(this)
}

var obj = {
	name:"why",
    foo:foo
}

obj.foo()  // obj
function foo() {
	console.log(this)
}

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

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

obj2.obj1.foo() // obj1
function foo() {
    console.log(this)
}

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

var bar = obj1.foo()

bar() // window 

显示绑定

通过callapply绑定this对象

  • 显示绑定后,this久会明确的指向绑定的对象
function foo() {
	console.log(this)
}

foo.call(window)
foo.call({name:'why'})
foo.call(123)
  • 如果我们希望一个函数总是显示得绑定到以一个对象上,可以这样做
function foo() {
    console.log(this)
}

var obj = {
	name:'why'
}

var bar = foo.bind(obj)

bar() // obj对象
bar() // obj对象
bar() // obj对象

new绑定

  • JavaScript中得函数可以当作一个类的构造函数来使用,也就是使用new关键字
  • 使用new关键字来调用函数,会执行如下的操作:
    • 创建一个全新的对象
    • 这个新对象会执行prototype连接
    • 这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成)
    • 如果函数没有发回其他对象,表达式会返回这个新对象
function Person(name) {
    console.log(this)
    this.name = name;
}

var p = new Person("why")
console.log(p)

内置函数的绑定

定时器,内部应该采取默认调用

setTimeout(() => {
    console.log(this) // window
},1000)

事件回调,内容使用了显示绑定

const boxDiv = document.querySelector('.box')
boxDiv.onclick = function() {
    console.log(this)
}

boxDiv.onclick() //boxDiv

数组 forEach/map/filter/find

var name = ["abc","cba","nba"]

names.forEach(function(item){
    console.log(item,this) // window
})

我们可以通过传递第二个参数来绑定this

 var name = ["abc","cba","nba"]
 names.forEach(function(item){
     console.log(item,this) // abc
 }, "abc")

规则优先级

如果一个函数调用位置应用了多条规则,优先级怎么判断

  • 默认规则的优先级最低

    • 毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this
  • 显示绑定优先级高于隐式绑定

    function foo() {
        console.log(this)
    }
    
    var obj = {
    	name:"obj",
        foo:foo.bind("aaa")
    }
    
    obj.foo() // aaa
    
  • new绑定优先级高于隐式绑定

    var obj = {
    	name:"obj",
        foo:function(){
    		console.log(this)
        }
    }
    
    var f = new obj.foo()  // foo,它new的是obj.foo 
    
  • new绑定优先级高于显示绑定

    // 结论:new关键字不能和apply/call一起来使用
    
    // 我们使用new和bind进行比较
    function foo() {
        console.log(this)
    }
    
    var bar = foo.bind('aaa')
    
    var obj = new bar() // foo
    

this规则之外

忽略显示绑定

apply/call/bind:当传入null/undefined时,自动将this绑定成全局对象

function foo() {
	console.log(this)
}

foo.apply(null) // window
foo.apply(undefined) // window

间接函数

另外一种情况,创建一个函数的间接引用,这种情况使用默认绑定规则

var obj1 = {
    name:"obj1",
    foo:function() {
        console.log(this)
    }
}

var obj2 = {
    name:"obj2"
}; // 切记此处要有分号,不然代码不会被正常识别, 而变成一下情况var obj2 = {name:"obj2"}(obj2.bar = obj1.foo)()
 
// console.log(obj2.bar = obj1.foo) //  function() { console.log(this) }
(obj2.bar = obj1.foo)()  // window

以下代码也是没有加分号的问题:

function foo(el) {
    console.log(el,this.id)
}

var obj = {
    id:"awesome"
} // 加上;即可	

[1,2,3].forEach(foo.obj) // Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')

箭头函数

箭头函数是ES6之后增加的一种编写函数的方法,并且它比函数表达式更加简洁

  • 箭头函数不会绑定thisarguments属性
  • 箭头函数不能作为构造函数来使用(不能和new一起来使用,会抛出错误)
  • 箭头函数不适用this的四种标准规则,而是根据外层作用域来决定this

即使对箭头函数使用callbind,也无法对其this进行绑定

var foo = () => {
    console.log(this)
}

foo.call('as') // window

面试题

一、

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

function sayName () {
    var sss = person.sayName;
    sss(); // window
    person.sayName(); // person
    (person.sayName)(); //person
    (b = person.sayName)() // window, 创建一个函数的间接引用,这种情况使用默认绑定规则
}

sayName()

二、

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() // person
person1.foo2.call(person2) //person2

person1.foo2() // window
person1.foo2.call(person2) // window,因为箭头函数不能显示绑定

person1.foo3()() // window
person1.foo3.call(person2)() // window
person.foo3().call(person2) // person2

person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(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("person1");
var person2 = new Person("person2");

person1.foo1(); // person1
person1.foo1.call(person2); // person2

person1.foo2(); // person1
person1.foo2.call(person2); // person1

person1.foo3()(); // window
person1.foo3.call(person2)(); // window
person1.foo3().call(person2); // person2

person1.foo4()(); // person1
person1.foo4.call(person2)(); // person2
person1.foo4().call(person2); // person1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值