前端 js 之 this 的绑定规则 04

嘿,加油

文章目录

  • 一、this?
  • 二、this 的指向
  • 三、默认绑定(独立函数调用)
  • 四、隐式绑定
  • 五、显式绑定 (apply call bind)
  • 六、new绑定 (后面会详细再补充)
  • 七、apply call bind 区别
  • 八、内置函数的绑定思考
  • 九、规则优先级
  • 十、说明
  • 十一、this 规则之外
    • 1. 忽略显示绑定
    • 2. ES6箭头函数


一、this?

        在其他面向对象编程中,this 一般会出现在类的方法里,但是在js中,this更灵活,无论是它出现的位置还是它代表的含义。首先this在全局里指向window, 但是,开发中很少直接在全局作用于下去使用this,通常都是在函数中使用,在之前文章里说过,当我们函数调用时,会创建一个执行上下文,这个上下文记录着函数的调用栈,AO对象,还有其他,当然还记录着一个很重要的东西,this

二、this 的指向


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

      // 1.调用方式一:直接调用;
      foo(); //window


      // 2.调用方式二:将foo放到一个对象中,再调用
      var obj = { name: "why", foo2: foo };
      obj.foo2(); //obj对象


      // 3.调用方式三:通过ca1l/apply调用
      foo.call("abc"); // String {"abc"子对象}
      

根据这个案例,我们可以发现

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

那么this到底是怎么样的绑定规则呢?

  1. 绑定一:默认绑定;
  2. 绑定二:隐式绑定;
  3. 绑定三:显示绑定;
  4. 绑定四:new绑定

三、默认绑定(独立函数调用)


当独立函数调用时,JavaScript会默认给this绑定一个值: windows

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

前端 js 之 this 的绑定规则 04_第1张图片

四、隐式绑定

另外一种比较常见的调用方式是通过某个对象进行调用,也就是它的调用位置中,是通过某个对象发起的函数调用。
前端 js 之 this 的绑定规则 04_第2张图片

五、显式绑定 (apply call bind)


隐式绑定有一个前提条件:

  1. 必须在调用的对象内部有一个对函数的引用(比如一个属性);
  2. 如果没有这样的引用,在进行调用时,会报找不到该函数的错误;
  3. 正是通过这个引用,间接的将this绑定到了这个对象上;

如果我们不希望在 对象内部 包含这个函数的引用,同时又希望在这个对象上进行强制调用,该怎么做呢?

  1. JavaScript所有的函数都可以使用call和apply方法(这个和Prototype有关)。

  2. 这两个函数的第一个参数都要求是一个对象,这个对象的作用是什么呢?就是给this准备的

  3. 在调用这个函数时,会将this绑定到这个传入的对象上。

  4. 因为上面的过程,我们明确的绑定了this指向的对象,所以称之为 显示绑定。

六、new绑定 (后面会详细再补充)


JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字。

使用new关键字来调用函数是,会执行如下的操作:

  1. 首先他会创建一个全新的对象;
  2. 这个新对象会被执行prototype连接;
  3. 这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成);
  4. 如果函数没有返回其他对象,表达式会返回这个新对象;

前端 js 之 this 的绑定规则 04_第3张图片

我们通过一个new关键字调用一个函数时(构造器),这个时候this是再调用这个构造器时创建出来的对象,this=创建出来的对象,这个绑定过程也称为new绑定

七、apply call bind 区别


 	//比如夏夏有个充电宝,它可以使用charge这个充电宝给自己的手机电池phoneBattery任意充电
 	
    const xiaxia={
      name:'xiaxia',
      phoneBattery:70,
      charge:function (level){
        this.phoneBattery=level
      }
    },
    xiaxia.charge(100)


   //但是haha手机没电了,也不想买充电宝,但是它可以借xiaxia的
    const haha={
      name:'haha',
      phoneBattery:40,
    },
    xiaxia.charge.call(haha,100)


    //方便演示apply 的用法,假设充电宝必须冲两次
    const xiaxia={
      name:'xiaxia',
      phoneBattery:70,
      charge:function (level,newlevel){
        this.phoneBattery=level+newlevel
      }
    }
    
	// 如果使用 call 方式
	xiaxia.charge.call(haha,2050)
	
	// 如果使用 apply 方式
	xiaxia.charge.apply(haha,[2050])


	// bind 方式,其实是借了充电宝,但不是立即使用,而是过一会使用
	const hahaMethods=xiaxia.charge.apply(haha)
	haha.hahaMethods(20,50)
	

八、内置函数的绑定思考

有些时候,我们会调用一些JavaScript的内置函数,或者一些第三方库中的内置函数。这些内置函数会要求我们传入另外一个函数; 我们自己并不会显示的调用这些函数,而且JavaScript内部或者第三方库内部会帮助我们执行;这些函数中的this又是如何绑定的呢?

前端 js 之 this 的绑定规则 04_第4张图片


可以通过上图发现,对于内置函数,他们的this情况,比如对于setTimeout ,他是一个独立执行,默认绑定;看第四张图,它有提示thisArg ,其实是说我们可以自己更改他的this指向,比如第三张图,如果我们传入第二个参数为obj,就把他的this执行为obj了

九、规则优先级

学习了四条规则,接下来开发中我们只需要去查找函数的调用应用了哪条规则即可,但是如果一个函数调用位置应用了多条规则,优先级谁更高呢?

  1. 默认规则的优先级最低
    毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this
  2. 显示绑定优先级高于隐式绑定 (案例一) (案例二 )
  3. new绑定优先级高于隐式绑定 (案例三)
  4. new绑定优先级高于bind ( 因为new关键字是不能和apply/call 一起使用的)
    new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高
    new绑定可以和bind一起使用,new绑定优先级更高
	var obj={
		name:'obj'
		foo:function(){
		console.log(this)
		}
	}
	// 当这个有显示绑定(call)和隐式绑定(obj)时,发现他的this指向为 abc 
	// 说明显示绑定优先级高于隐式绑定
	obj.foo.call('abc') 
	
	var obj={
		name:'obj'
		foo:function(){
		console.log(this)
		}
	}
	// 虽然这个指向指向的是 abc,但是并不能体现 显示绑定优先级高于隐式绑定
	// 因为现在执行的是 obj 的返回的函数,绑定到abc上
	// 当foo2执行时 与obj其实是没关系的,只是执行的时候引用了而已
	var foo2 = obj.foo.bind('abc') 
	foo2()



	function foo(){
		console.log(this)
	}
	var obj={
		name:'obj'
		foo:foo.bind('aaa')
	}
	obj.foo()  //这样会更明显   指向的是aaa


	

	var obj={
		name:'obj'
		foo:function(){
		console.log(this)
		}
	}
	var f = new obj.foo()  //指向的是foo  说明new的高于隐式
	

十、说明

不管函数在什么位置声明,在内存中都是在堆内存中单独分配的空间,得到该函数地址的变量都可以对函数进行调用,所以函数中的this指向与调用位置无关,也就是谁调用就指向谁

十一、this 规则之外

1. 忽略显示绑定

apply / call /bind : 当传入 null / undefined 时, 那么这个显示绑定会被忽略,使用默认规则


	function foo(){
		console.log(this)
	}
	
	foo.apply('abc')
	foo.apply({})

	foo.apply(null)
	foo.apply(undefined)

2. ES6箭头函数

箭头函数并不绑定this对象,那么this引用就会从上层作用于中找到对应的this

你可能感兴趣的:(Js.,前端,javascript)