JavaScript基础(三)

一、this的绑定问题

  this是当前执行环境的一个属性,除了全局环境的this绑定的是全局对象之外,this都是运行时绑定,所以函数环境中的this指向取决于函数的调用(箭头函数例外,本文也会详细说),并且严格模式和非严格模式也会有一些不同。
  下面举例介绍this的五种绑定。

1)默认绑定

  当函数独立调用时,非严格模式下,this默认绑定全局对象(浏览器中就是window);严格模式下,this为undefined。

// 1、直接调用
function foo() {
  console.log(this)
}
foo()

// 2、对象中的函数被变量引用
var obj1 = {
  name: 'obj1',
  foo: foo
}
var fn1 = obj1.foo  //请思考:直接以obj1.foo()的方式调用会是同样的结果吗?
fn1()

// 3、函数嵌套调用
function foo1() {
  console.log('foo1', this)
}
function foo2() {
  console.log('foo2', this)
  foo1()
}
function foo3() {
  console.log('foo3', this)
  foo2()
}
foo3()

// 4、通过闭包调用
var obj2 = {
  name: 'obj2',
  bar: function () {
    name: 'bar'
    return function () {
      console.log(this)
    }
  }
}
obj2.bar()()

  ! 运行结果

  这几种调用下,this都是默认绑定。

2)隐式绑定

  调用函数的对象内部有对函数的引用,接着上边的例子看:

obj1.foo()
var obj3 = {
  name: 'obj3',
  bar: function () {
    console.log(this)
  }
}
obj3.bar()
var obj4 = {
  name: 'obj4',
  baz: obj3.bar
}
obj4.baz()

  ! 运行结果

  通过对比代码和结果,可以发现:函数是由哪个对象调用的,其this绑定的就是哪个对象。以上这三种调用方式都属于隐式绑定。

3)显式绑定

  对象内部没有这个函数的引用,但又希望通过对象强制调用(把this的值从一个运行环境传到另一个),使用call / apply / bind 进行显式绑定。

var obj5 = {
  name: 'obj5',
}
foo.call(obj5)
foo.apply(obj5)
foo.call("xxx")

  ! 运行结果

  foo默认this是绑定window的,这里通过call和apply来改变了this的绑定。bind方法改变绑定的效果是一样的,只不过bind返回的不是函数运行结果,而是改变后的函数(具体请单独查询bind的使用)。

4)new绑定

  通过new关键字来创建构造函数的实例,绑定this。MDN中将这部分单独分在了this在类中的绑定,其实本质上一样,类就是通过构造函数实现的。

function Person(name, age) {
  this.name = name
  this.age = age
}
const p1 = new Person('mmm', 18)
const p2 = new Person('ppp', 25)
console.log(p1)
console.log(p2)

  ! 运行结果

  此时this指向的是通过new创建的实例对象。

5)几种特殊绑定

  1. 箭头函数
    在箭头函数中,this与封闭词法环境的this保持一致;在全局代码中,它将被设置为全局对象。说白了就是,箭头函数的this绑定的是上级作用域,找外层。
  2. 忽略显示绑定
    当显示绑定的值为 null/undefined 时,this直接绑定全局对象。
  3. 间接函数引用
var obj1 = {
  name: 'obj1',
  foo: function () {
    console.log(this)
  }
}
var obj2 = {
  name: 'obj2'
};
obj2.baz = obj1.foo;
obj2.baz();
(obj2.bar = obj1.foo)();

  ! 运行结果
  两种方式所绑定的this不同,第二种方式进行了赋值调用,实际上是间接函数引用。(obj2.bar = obj1.foo)这里返回了赋值的结果,再加上一个小括号,就直接调用赋值的结果函数。

二、this绑定的优先级

  先说结果,一中除特殊绑定之外的四种绑定优先级顺序为:new关键字 > 显式绑定 > 隐式绑定 > 默认绑定

//隐式绑定优先级高于默认绑定
var name = 'global'
function foo() {
  console.log(this.name)
}
var obj = {
  name: 'obj',
  foo: foo
}
obj.foo()  //:obj

//显示绑定优先级高于隐式绑定
var obj1 = {
	 name: 'obj1',
	 foo: foo.bind('obj2')
}
obj1.foo()  //:obj2

//new关键字优先级高于显式绑定
function bar(){
  console.log(this.name)
}
var obj3 = {
  name: 'obj3'
}
var fn = bar.bind(obj3) 
fn() //:obj3
new fn()  //:bar {}

  最后的例子,当同时存在于new关键字绑定和显示绑定时,this绑定了foo构造函数,所以new关键字的优先级高于显示绑定。

参考文章:彻底弄懂js中this指向

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值