是否可以在JavaScript中自动进行字符串化?

sim*_*one 18 javascript

我知道我可以toString()在一个对象上创建一个函数,这样每次打印或处理它就像一个字符串时,它将首先使用该函数对该对象进行字符串化.

有可能直接这样做,所以我可以在对象上使用String对象函数吗?

var SomeObject = function(a, b){
    this.a = a;
    this.b = b
}

SomeObject.prototype.toString = function(){
    return [ this.a, this.b ].join(' ')
}

var objInstance = new SomeObject('this', 'that');

console.log(objInstance + '')                // This that
console.log(("" + objInstance).split(''))    // [ 't', 'h', 'i', 's', ' ', 't', 'h', 'a', 't' ]
console.log(objInstance.split())             // Error
Run Code Online (Sandbox Code Playgroud)

当调用String函数时,是否可以这样做,使对象"行为"像一个字符串?

换句话说,我希望得到与之objInstance.split()相同的结果("" + objInstance).split(''),objInstance.length或者objInstance.match(/something/)等等.

Ber*_*rgi 29

您可以让对象继承,String以便所有字符串方法都可用:

class SomeObject extends String {
  constructor(a, b) {
    super(a + " " + b);
    this.a = a;
    this.b = b;
  }
}

var obj = new SomeObject('this', 'that');
console.log(obj.split(""));
Run Code Online (Sandbox Code Playgroud)

无需使用复杂的Proxy解决方案:-)

所有的String.prototype方法(除.toString,.valueOf[Symbol.iterator])为" 有意通用的; [它们]不要求它的this值是一个String.对象因此,[它们]可以转移到其他类型的对象,其用作方法 "你可以叫它们在任何值上,它们都会将它强制转换为字符串(使用.toString().valueOf像往常一样).

您甚至不需要使用ES6 class extends继承内置(这也使您的字符串值不可变),它也适用于ES5:

function SomeObject(a, b) {
  this.a = a;
  this.b = b;
}
SomeObject.prototype = Object.create(String.prototype);
SomeObject.prototype.constructor = SomeObject;
SomeObject.prototype.toString = function() {
    return this.a + " " + this.b;
};

var obj = new SomeObject('this', 'that');
console.log(obj.split(""));
Run Code Online (Sandbox Code Playgroud)

  • 这被认为是好习惯吗?这似乎是对继承的滥用. (5认同)
  • @usr也许是,我不知道OP的用例.但是,如果他们想在自定义实例上使用所有`String`s方法,那听起来有点像子类型. (2认同)

Cer*_*nce 23

一种选择是返回一个Proxy检查属性是否存在的命令String.prototype,如果存在,则使用表示该对象的字符串调用该属性:

// Declare the proxy handler up front here
// to avoid unnecessary creation of duplicate handler objects
const handler = {
  get(obj, prop) {
    if (obj[prop] !== undefined) {
      return obj[prop];
    }
    const stringMethod = String.prototype[prop];
    if (stringMethod) {
      return stringMethod.bind(obj.a + ' ' + obj.b);
    }
  },
};

const SomeClass = function(a, b) {
  this.a = a;
  this.b = b
  return new Proxy(this, handler);
}

const instance = new SomeClass('this', 'that');

// String methods:
console.log(instance.trim());
console.log(instance.includes('this'));
console.log(instance.includes('somethingelse'));
console.log(instance.split(''));

// Can still assign and retrieve values directly on the object as normal:
instance.foo = 'foo';
console.log(instance.foo);
Run Code Online (Sandbox Code Playgroud)

  • 我建议在构造函数之外声明处理程序对象,原因与你应该在原型上定义方法的原因相同.然后你也可以使用`target`参数而不是关闭`this`. (3认同)
  • +1.备注:此定义仅适用于ecmascript 6或更高版本.[参考文献](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) (2认同)