用可变变量访问 JavaScript 类、对象的方法(动态访问 JS 类、对象的方法)

JavaScript中,用可变变量访问对象方法或类静态方法,如果访问的方法中 this,此时 this 将会是 undefined
用对象解构赋值获得函数名(如:xxx)后,用函数名后面加括号(如:xxx())执行函数,this 也是 undefined

问题复现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 动态访问方法
class Cls1 {
fn () {
console.log(this);
}
}

const obj = new Cls1();

// ❌ 错误方法
const fn1 = obj.fn;
fn1(); // this undefined

// 解构赋值取得
const { fn } = obj;

// ❌ 错误方法
fn(); // this undefined

1、用箭头函数

箭头函数中的 this 总是指向其上级对象,用箭头函数声明方法,可解决上面的两个问题,但不是完美的。箭头函数中不能用 super 关键字,导致我们不能在子类中指定调用父类的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 动态访问方法
class Cls1 {
fn = () => {
console.log(this);
};
}

const obj = new Cls1();

// 变量函数
const fn1 = obj.fn;
fn1(); // ok

// 解构赋值取得
const { fn } = obj;
fn(); // ok

2、用原型方法

这里举例用 call() 原型方法实现,apply()bind() 方法可同样实现,只有参数调用上的却别。

要了解详情,请阅读《JavaScript 原型方法:call、apply、bind 的使用》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 动态访问方法
class Cls1 {
fn () {
console.log(this);
}
}

const obj = new Cls1();

// 变量函数
const fn1 = obj.fn;
fn1.call(obj); // ok

// 解构赋值取得
const { fn } = obj;
fn.call(obj); // ok

静态方法可以把方法中的 this 换成类名就可以,也可以用 call 方法,把对象实例换成类名就可以。

3、用 bind 改良 call

每次执行函数的时候,期待 fn() 就可以,但总是要加上 call 变成 fn.call(obj),真实不方便。

bind 的常规用法:

1
2
3
const { fn } = obj;
const fb = fn.bind(obj) // 把对象实例绑到函数上
fb(); // 可以这样执行函数

这样是不是感觉问题更大了,要先 bind,执行的又是跟原先函数名不一样的函数。
我们转换一项思路,把绑定的这个步骤放到构造函数中去,这样就可以预先绑定对象实例了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Cls1 {
constructor () {
this.fn = this.fn.bind(this); // 给 fn 绑上对象实例
}

fn () {
console.log(this);
}
}

const obj = new Cls1();
obj.fn();

const { fn } = obj;
fn();

还有一种解决方法是使用 Proxy,访问方法的时候,将自动绑定 this

用可变变量访问 JavaScript 类、对象的方法(动态访问 JS 类、对象的方法)

https://coderpan.com/front-end/javascript-variable-variables-callback.html

作者

CoderPan

发布于

2023-02-10

更新于

2024-05-08

许可协议

评论