这其实是同一个问题,这么理解:绑定(bind)、call、apply、箭头函数其实都是为了改变this指向;换句话说,想要改变this指向,可以用这几种方式:.bind()、.call()、.apply()、箭头函数。
一、函数的调用中的this指向问题(调用方式不同,this指向也不同)
1.普通函数调用,此时 this 指向 window
function fn() {
console.log(this); // window
}
fn(); // window.fn(),此处默认省略window
2.构造函数调用, 此时 this 指向 实例对象
function Person(age, name) {
this.age = age;
this.name = name
console.log(this) // 此处 this 分别指向 Person 的实例对象 p1 p2
}
var p1 = new Person(18, 'zs')
var p2 = new Person(18, 'ww')
突然醒悟,这里跟java后台很像,如下:
//Student类
public class Student{
public String name;
public Int age;
}
Student st = new Student('zs',16)
system.outprint(st.name)//zs
3.对象方法调用, 此时 this 指向 该方法所属的对象
var obj = {
fn: function () {
console.log(this); // obj
}
}
obj.fn();
4.通过事件绑定的方法, 此时 this 指向 绑定事件的对象
<body>
<button id="btn">hh</button>
<script>
var oBtn = document.getElementById("btn");
oBtn.onclick = function() {
console.log(this); // btn
}
</script>
</body>
5.定时器函数, 此时 this 指向 window
setInterval(function () {
console.log(this); // window
}, 1000);
二、更改this指向的三个方法
1.call() 方法
var Person = {
name:"lixue",
age:21
}
function fn(x,y){
console.log(x+","+y);
console.log(this);
}
fn("hh",20);
没错,就像上面说的,普通函数的this指向window,现在让我们更改this指向
var Person = {
name:"lixue",
age:21
}
function fn(x,y){
console.log(x+","+y);
console.log(this);
console.log(this.name);
console.log(this.age);
}
fn.call(Person,"hh",20);
看,现在this就指向person了
call方法除了第一个参数以外还可以添加多个参数,如下:
var a = {
user:"taro",
fn:function(e,ee){
console.log(this.user); //taro
console.log(e+ee); //3
}
}
var b = a.fn;
b.call(a,1,2);
2.apply() 方法
apply() 与call()非常相似,也可以有多个参数,不同之处在于提供参数的方式,apply()使用参数数组,如下:
var a = {
user:"追梦子",
fn:function(e,ee){
console.log(this.user); //追梦子
console.log(e+ee); //11
}
}
var b = a.fn;
b.apply(a,[10,1]);
//注意如果call和apply的第一个参数写的是null,那么this指向的是window对象
var a = {
user:"追梦子",
fn:function(){
console.log(this); //Window {external: Object, chrome: Object, document: document, a: Object, speechSynthesis: SpeechSynthesis…}
}
}
var b = a.fn;
b.apply(null);
3.bind()方法
bind()创建的是一个新的函数(称为绑定函数),与被调用函数有相同的函数体,当目标函数被调用时this的值绑定到 bind()的第一个参数上
bind方法和call、apply方法有些不同,如下:
var a = {
user:"taro",
fn:function(){
console.log(this.user);
}
}
var b = a.fn;
b.bind(a); //代码没有被打印
我们发现代码没有被打印,对,这就是bind和call、apply方法的不同,实际上bind方法返回的是一个修改过后的函数。
var a = {
user:"追梦子",
fn:function(){
console.log(this.user);
}
}
var b = a.fn;
var c = b.bind(a);
console.log(c); //function() { [native code] }
函数c看看,能不能打印出对象a里面的user
var a = {
user:"追梦子",
fn:function(){
console.log(this.user); //追梦子
}
}
var b = a.fn;
var c = b.bind(a);
c();
同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的。
var a = {
user:"追梦子",
fn:function(e,d,f){
console.log(this.user); //追梦子
console.log(e,d,f); //10 1 2
}
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);
例:定时器使用.bind()改变this指向
var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function(){
setTimeout(function(){
console.log(this);
},1000)
}
var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function(){
setTimeout(function(){
console.log(this);
}.bind(this),1000)
}
因为在定时器外,在绑定事件中的this肯定指向绑定事件的对象div啊,用call和apply都行
三、箭头函数
看个例子
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this);//b {a: 12, fn: ƒ}
}
},
fn1:function(){
console.log(this.a); //10
}
}
o.fn1();
o.b.fn();
var o = {
a:10,
b:{
// a:12,
fn:()=>{
console.log(this);//window
}
},
fn1:function(){
console.log(this.a); //10
}
}
o.fn1();
o.b.fn();
把普通函数换成箭头函数过后,this的指向也发生了变化,原因是:
箭头函数:箭头函数本身是没有this和arguments的,在箭头函数中引用this实际上是调用的是定义时的上一层作用域的this。
这里强调的是上一层作用域,是因为对象是不能形成独立的作用域的。
思考: 那么,想让o.b.fn()打印出来的this指向o对象,该怎么改?
var o = {
a:10,
b:function(){
// a:12,
var fn=()=>{
console.log(this);//o {a: 10, b: ƒ, fn1: ƒ}
}
fn()
},
fn1:function(){
console.log(this.a); //10
}
}
o.fn1();
o.b();
参考文档:
https://blog.csdn.net/xuehangongzi/article/details/80841167
https://blog.csdn.net/qq_37467034/article/details/78311591