为什么 ES6 的 Proxy 在 class 的方法中使用时不起作用?
Why do ES6's Proxy doesn't work when used inside a method of class?
当在 class 的方法内部使用时,逻辑不起作用,但如果我以函数式风格使用它,则逻辑在外面起作用。
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const handler = {
apply: function (target, thisArg, args){
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === this.object) {
return "Hooked String"
}
return target.apply(thisArg, args)
}
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())
我应该怎么做才能让它在 class 中工作?
“问题”不在于代理 - 所有调用都已通过它。问题是 how the this
keyword works. In short, it's determined at call time, so this.object
will have a different meaning depending on when and how the function is called. In this case, the value of this
is "lost" not unlike how you lose it in a callback.
的古老细节
如果你需要具体指代某事,你有几个选择
词法绑定 this
使用箭头函数 () => {}
一个箭头函数 在创建时,所以它在调用时不会变化:
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const handler = {
apply: (target, thisArg, args) => { //<--- arrow function
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === this.object) {
return "Hooked String"
}
return target.apply(thisArg, args)
}
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())
使用 Function#bind
手动绑定 this
这对于箭头函数来说基本上是多余的,但仍然是一个选项:
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const handler = {
apply: function (target, thisArg, args){
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === this.object) {
return "Hooked String"
}
return target.apply(thisArg, args)
}.bind(this) //<--- bind `this` from creation time
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())
捕获变量中的值
这避免了 this
的使用,方法是在创建时使用 const obj = this.object
捕获 this.object
的值,然后仅使用 obj
,后者将始终具有相同的值:
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const obj = this.object; //<--- capture
const handler = {
apply: function (target, thisArg, args){
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === obj) { //<--- use
return "Hooked String"
}
return target.apply(thisArg, args)
}
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())
当在 class 的方法内部使用时,逻辑不起作用,但如果我以函数式风格使用它,则逻辑在外面起作用。
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const handler = {
apply: function (target, thisArg, args){
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === this.object) {
return "Hooked String"
}
return target.apply(thisArg, args)
}
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())
我应该怎么做才能让它在 class 中工作?
“问题”不在于代理 - 所有调用都已通过它。问题是 how the this
keyword works. In short, it's determined at call time, so this.object
will have a different meaning depending on when and how the function is called. In this case, the value of this
is "lost" not unlike how you lose it in a callback.
如果你需要具体指代某事,你有几个选择
词法绑定 this
使用箭头函数 () => {}
一个箭头函数
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const handler = {
apply: (target, thisArg, args) => { //<--- arrow function
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === this.object) {
return "Hooked String"
}
return target.apply(thisArg, args)
}
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())
使用 Function#bind
手动绑定 this
这对于箭头函数来说基本上是多余的,但仍然是一个选项:
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const handler = {
apply: function (target, thisArg, args){
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === this.object) {
return "Hooked String"
}
return target.apply(thisArg, args)
}.bind(this) //<--- bind `this` from creation time
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())
捕获变量中的值
这避免了 this
的使用,方法是在创建时使用 const obj = this.object
捕获 this.object
的值,然后仅使用 obj
,后者将始终具有相同的值:
class Hook {
constructor(object) {
this.object = object;
}
toStringProperty() {
const obj = this.object; //<--- capture
const handler = {
apply: function (target, thisArg, args){
if (thisArg === Function.prototype.toString) {
return 'function toString() { [native code] }'
}
if (thisArg === obj) { //<--- use
return "Hooked String"
}
return target.apply(thisArg, args)
}
}
Function.prototype.toString = new Proxy(Function.prototype.toString, handler)
}
}
let hook = new Hook(HTMLAudioElement);
hook.toStringProperty();
// Interesting enough this when called (I use Devtools) logs Proxy Object itself but only happen if I use a Class
console.log(Function.prototype.toString)
console.log(HTMLAudioElement.toString())