this有什么用处
this的用处在于,在没有变量名的情况下,函数就可以获取对应的引用。
比如这里👇
let sayHi = function(){
console.log(`你好,我叫` + person.name)
}
let person = {
name: 'frank',
'sayHi': sayHi
}
👆问题:
- person 如果改名,sayHi 函数就挂了
- sayHi 函数甚至有可能在另一个文件里面
- 所以我们不希望 sayHi 函数里出现 person 的引用
使用了this以后👇
let person = {
name: 'frank',
sayHi(~~this~~){
console.log(`你好,我叫` + this.name)
}
}
person.sayHi() 相当于 person.sayHi(person) ,然后 person 被传给 this 了(person 是个地址),这样,每个函数都能用 this 获取一个未知对象的引用了,person.sayHi()会隐式地把 person 作为 this 传给 sayHi
call、apply、bind 的用法分别是什么?
call 和 apply
call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
call apply 二者的作用完全一样,只是接受参数的方式不太一样。
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
例如,有一个函数 func1 定义如下:
var func1 = function(arg1, arg2) {};
就可以通过 func1.call(this, arg1, arg2); 或者 func1.apply(this, [arg1, arg2]); 来调用。其中 this 是你想指定的上下文,他可以任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来便利所有的参数。
bind
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
bind() 最简单的用法是创建一个函数,不论怎么调用,这个函数都有同样的 this 值。JavaScript新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,期望方法中的 this 是原来的对象(比如在回调中传入这个方法)。如果不做特殊处理的话,一般会丢失原来的对象。基于这个函数,用原始的对象创建一个绑定函数,巧妙地解决了这个问题:
this.x = 9; // 在浏览器中,this 指向全局的 "window" 对象
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var retrieveX = module.getX;
retrieveX();
// 返回 9 - 因为函数是在全局作用域中调用的
// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
如何判断this是什么
把代码转换为使用call或者apply写法,第一个参数就是this。对于[]语法,可以把 arr0 想象为arr.0( ),虽然后者的语法错了,但是可以用来判断this
arr[0]()
假想为 arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了 :)
网上的其他方法,仅供参考👇
不考虑箭头函数,那么一个函数里的this指向什么不取决于函数在哪定义,也不取决于函数在哪调用,而是取决于函数被如何调用,主要分以下4种方式:
- f()
- obj.f()
- f.call(obj)
- new f()
难点主要是很多时候用的哪种方式调用的不太明显,以及参数的传递(尤其是把函数传来传去的时候)导致你都不知道调的是哪个函数,甚至有些时候都不是自己调用的,比如你把函数传给addEventListener("click",f),或者是$().click(f),或者是[].map(f),这种时候决定f中this的不是你,而是这些函数内部的写法,取决于它们用了上面的哪种调法。
网上判断this方法总结
- 谁.的或谁[]的就谁
- call 、apply、bind ,绑定到指定的对象
- 自己没有 this 的一直找上层的,直到返回 Global
- 由 new 调用,绑定到新创建的对象。
- 间接 eval 中的 this 是 Global
- 其余非 UA 特殊包装的均为 Global
- 特殊 UA 包装的 this 人家包时候指定是啥就啥