JS中的this关键词以及call、apply和bind方法
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 不会立即调用,它会生成一个新的函数,你想什么时候调就什么时候调