JS中的this关键词以及call、apply和bind方法

2019-11-25  本文已影响0人  空压机百科

JS中的 this 代表的是当前行为执行的主体;JS中的 context 代表的是当前行为执行的环境(区域)。
this 和函数在哪定义,在哪执行的没有任何关系。
例如:小明在海底捞吃火锅,this指的是小明,context 指的是海底捞。

如何区分 this:

1、函数执行,首先看函数名前面是否有 “.” ,有的话 “.”前面是谁 this 就是谁;没有的话 this 就是 window,例如:

function fn(){
   console.log(this)
}
var obj = {fn : fn}
fn()  // this == window
obj.fn()  // this == obj
function sum(){
   fn()  // this == window
}
sum()  // this == window

2、自执行函数中的 this 永远是 window。
3、给元素的某一个事件绑定方法,当事件触发的时候,执行的对应的方法,方法中的 this 是当前的元素。例如:

xxx.onclick = function(){console.log(this)}  // this == xxx

4、在构造函数模式中,类中(函数体中)出现的 this 是当前类的一个实例。
5、使用 call / apply 来改变 this 的指向(一旦遇到前面1-4条都没用)
在原型模式中,this 常用的两种情况:
a、在类中的 this.xxx = xxx;this 当前类的实例(第4种)
b、在某个方法中的 this 看执行的时候 “.” 前面是谁 this 就是谁(第1种)注意:
需要先确定 this 的指向(this 是谁),把 this 替换成对应的代码,按照原型链查找机制,一步步查找结果。
this案例:

var num = 20
var obj = {
   num: 30,
   fn: (function (num){
      this.num *= 3
      num += 15
      var num = 45
      return function(){
         this.num *= 4
         num += 20
         console.log(num)
      }
   })(num)
}
var fn = obj.fn
fn()  // 65
obj.fn()  // 85
console.log(window.num,obj.num)  // 240  120
内存图

理解原型上方法的执行过程:

Array.prototype.slice = function(){}
var ary = [12,13,14]

ary.slice ary这个实例通过原型链的查找机制找到 Array.prototype 上的 slice 方法
ary.slice()让找到的 slice 方法执行,在执行 slice 方法过程中,才把 ary 数组进行截取

call 方法的作用:

var obj = {name: "张三"};
function fn(){
   console.log(this)
}
fn.call(obj)

首先让原型上的 call 方法执行,在执行 call 方法的时候,让 fn 方法中的 this 变为第一个参数值 obj;然后再把 fn 这个函数执行。
简单模拟内置的 call 方法来理解 call:

Function.prototype.myCall = function (context){
   // myCall 方法中的 this 就是当前要操作和改变其 this 关键字的那个函数名
   // 1、让 fn 中的 this 关键字变为 context 的值为 obj(可以理解为:让 this 这个函数中的 “this 关键字”变为 context.)
   eval(this.toString().replace("this","obj"))  //解释:得到 this 这个函数的字符串,并将字符串里面的“this 关键字”替换为 obj 然后再用 eval 方法把字符串变为 JS 表达式
   // 2、让 fn 方法在执行(可以理解为让 this 这个方法执行)
   this()
}
fn.call(obj)

案例讲解:

function fn1(){console.log(1)}
function fn2(){console.log(2)}
fn1.call(fn2)   // ==> 1
fn1.call.call(fn2)  // ==> 2
fn1.call.call.call.call.call(fn2)  // ==> 2
Function,prototype.call(fn1)  // ==> undefined  Function,prototype 是一个空函数
Function,prototype.call.call.call(fn1)  // ==> 1 

fn1.call(fn2) : 首先 fn1 通过原型链查找机制找到 Function.prototype 上的 call 方法,并让 call 方法执行,此时 call 方法中 this 就是要操作的 fn1 ,在 call 方法执行过程中首先让 fn1 中 this关键字变为 fn2 ,然后再让 fn1 方法执行 ==> 1
fn1.call.call(fn2) :首先通过原型链查找到 Function.prototype 上的 call 方法,然后通过 call 方法通过原型链找到 Function 上的 call 方法,在第二次找到 call 方法的时候让方法执行,方法中的 this 是 fn1.call ,首先让这个方法中的 this 变为 fn2,让后再让 fn1.call 方法执行 ==> 2
如果 call 方法中没有传参数或者是 null undefined 的时候,this 为 window。若是在严格模式下 this 就是传入的参数
apply方法:
apply 和 call 方法是一摸一样的,都是用来改变方法中的this关键字并且把方法执行。但是 apply 传参数值的时候统一放在一个数组中进行操作。fn(obj,[num1,num2])
使用 apply 方法获取数组最大值:

var arr = [12,5,55,21,6,22]
var max = Math.max.apply(null,arr)
console.log(max)

bind方法:
事先把方法中的 this 改变为我们想要的结果,并且把相应的参数值也准备好,以后要用到直接执行即可。
bind 不会立即调用,它会生成一个新的函数,你想什么时候调就什么时候调

\color{#ccc}{本文正在参与”写编程博客瓜分千元现金“活动,关注”饥人谷“回复”编程博客}

上一篇 下一篇

猜你喜欢

热点阅读