JavaScript中的this指向

1.函数在调用时,JavaScript会默认给this绑定一个值;
2.this的绑定和定义的位置(编写的位置)没有关系;
3.this的绑定和调用方式以及调用的位置有关系;
4.this是在运行时被绑定的;

this的绑定规则

规则一:默认绑定

在函数独立调用时使用默认绑定,可以理解为函数没有被绑定到某个对象上

常见的默认绑定

  // 函数独立调用
    function foo{
  console.log(`this指向${this}`)
  }
  foo()//this指向的是window
  // 函数在对象中但是是独立调用
    const obj = {
    fn:function(){
      console.log(`this指向${this}`)
    }
  }
  const bar = obj.fn
  bar()//this指向window
  // 函数的参数默认调用
  function baz(fn){
         fn()
  }
  baz(obj.fn)//this指向window

规则二:隐式绑定

◼另外一种比较常见的调用方式是通过某个对象进行调用的:
  也就是它的调用位置中,是通过某个对象发起的函数调用。
◼ 隐式绑定有一个前提条件:
      必须在调用的对象内部有一个对函数的引用(比如一个属性);const obj={fn:function(){console.log(this)}}
      如果没有这样的引用,在进行调用时,会报找不到该函数的错误;
      正是通过这个引用,间接的将this绑定到了这个对象上;
     function foo(){
      console.log("this指向",this)
    }
    const obj = {
      bar : foo
        }
    obj.bar()//this指向obj

规则三 new绑定

◼ JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字。
◼ 使用new关键字来调用函数是,会执行如下的操作:
    1.创建一个全新的对象:const obj = {}
    2.将这个空对象赋值给this:this = obj
    3.将构造函数的显式原型赋值给这个对象的隐式原型:obj.__proto__ =Person.prototype
    4.执行构造函数的代码
    5.如果没有返回一个非空对象那么则返回这个对象:return obj
```JavaScript
function foo(name){  
  console.log("foo函数",this)
  this.name = name
  console.log(name)
  }
const bar = new foo("bar")//name值为bar
const baz = new foo("baz")//name值为baz
```

规则四 显式绑定 apply()方法,call()方法,bind()方法

 ◼ 隐式绑定有一个前提条件:
      必须在调用的对象内部有一个对函数的引用(比如一个属性);const obj={fn:function(){console.log(this)}}
      如果没有这样的引用,在进行调用时,会报找不到该函数的错误;
      正是通过这个引用,间接的将this绑定到了这个对象上;
 ◼ 如果我们不希望在对象内部包含这个函数的引用,同时又希望在这个对象上这时候可以用到显式绑定
 ◼ JavaScript所有的函数都可以使用call和apply方法。

apply()和call方法

    func.apply(thisArg,[argsArray])
    func.call(thisArg,arg1,arg2,.....)
   第一个参数是相同的,要求传入一个对象;
        ✓ 这个对象的作用是什么呢?就是给this准备的。
        ✓ 在调用这个函数时,会将this绑定到这个传入的对象上。
      后面的参数,apply为数组,call为参数列表;
  ``` JavaScript
    function foo(name,age,height){
          console.log("foo函数被调用:",this)
          console.log("打印参数:",name,age,height)
        }
    // ()调用
        foo("hdc","18","1.88")
     // apply
     // 第一个参数绑定this
     // 第二个参数传入额外的实参,以数组形式
        foo.apply("apply",["kobe","30","1.98"])
     // call
     // 第一个参数绑定this
     // 第二个参数传入额外的实参,以数组形式
        foo.call("call","james","35","2.01")
  
  ```

bind()方法绑定this

  ◼ 如果我们希望一个函数总是显示的绑定到一个对象上可以使用bind()方法绑定this
  使用bind方法,bind() 方法创建一个新的绑定函数(bound function,BF);
  绑定函数是一个exotic function object(怪异函数对象,ECMAScript 2015 中的术语)
  在bind() 被调用时,这个新函数的this 被指定为bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
  ```JavaScript
function foo(name,age,height,address){
  console.log("foo:",this)
  console.log("参数:",name,age,height,address)
}
var obj = {name:"hdc"}

// 调用foo总是绑定到obj对象身上,并且不希望obj对象身上存在foo函数
var bar = foo.bind(obj,"kobe",18,1.88)

bar("james")//this指向obj
            //参数: kobe 18 1.88 james
  ```

this绑定的优先级

new > bind > apply/call > 隐式绑定 > 默认绑定

  ◼ 1.默认规则的优先级最低
  毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this
  ◼ 2.显示绑定优先级高于隐式绑定
      obj.foo.apply("abc")
  ◼ 3.new绑定优先级高于隐式绑定
      new obj.foo()
  ◼ 4.new绑定优先级高于bind
  new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高
  new绑定可以和bind一起使用,new绑定优先级更高

绑定之外的情况

this规则之外– 忽略显示绑定

如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则:

  function foo(){
    console.log("this指向",this)
  }
  foo.apply(undefined)//this指向window

this规则之外- 间接函数引用

情况二:创建一个函数的间接引用,这种情况使用默认绑定规则。
赋值(obj2.foo = obj1.foo)的结果是foo函数;
foo函数被直接调用,那么是默认绑定;

  var obj1 = {
        name :"obj1",
        foo : function(){
          console.log("foo:",this)
        }
      }
      var obj2 = {
        name:"obj2"
      };
      obj2.foo = obj1.foo
      obj2.foo();//this指向obj2
      (obj2.foo = obj1.foo)()//this指向window

this规则之外– ES6箭头函数

◼ 箭头函数不使用this的四种标准规则(也就是不绑定this),而是根据外层作用域来决定this。
◼ 我们来看一个模拟网络请求的案例:
      这里我使用setTimeout来模拟网络请求,请求到数据后如何可以存放到data中呢?
      我们需要拿到obj对象,设置names;
      但是直接拿到的this是window,我们需要在外层定义:var _this = this
      在setTimeout的回调函数中使用_this就代表了obj对象
  function request(url,callbackFn){
    var result = ["aaa","bbb","bbb"]
    setTimeout(function(){
         callback(result)
      },2000)
  }
  const obj={
      names:["aaa111"],
      network:function(){
       //不使用箭头函数
        const _this = this
        request("/hhh",function(res){
            _this.names = _this.names.concat(res) 
        })
       // 使用箭头函数
       request("/xxx",res=>{this.names = this.names.concat(res)})
    }
  }
obj.network()
console.log(obj.names)//(4) ['aaa111', 'abc', 'cba', 'nba']
posted @ 2024-10-19 23:36  韩德才  阅读(6)  评论(0编辑  收藏  举报