You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询Safari与Chrome中this.toSource()的等效替代实现方案

如何替代Firefox专属的toSource()方法以兼容Chrome/Safari等浏览器?

我有一段仅能在Firefox中正常运行的代码,原因是this.toSource()方法在Safari和Chrome浏览器中无法生效。请问如何编写一个可兼容Safari、Chrome及其他部分浏览器的替代函数?我曾尝试使用this.toString()进行替换,但未能达到预期效果。

以下是我的代码:

var elements = []; 
var rect = function() { 
  this.x = 0; 
  this.y = 0; 
  this.width = 100; 
  this.height = 100; 
  this.background = "black"; 
  this.name = "rect" 
}; 
rect.prototype.render = function() { 
  if(this.toSource() != null) { 
    elements[elements.length] = this.toSource(); 
  } 
  // c = this.toString(); 
  // elements[elements.length] = c; 
  var returnThing; 
  for(var i in this) { 
    returnThing += this[i] 
  } 
  returnThing = returnThing.replace(/NaNblackrect3D30/g, ''); 
  returnThing = returnThing.replace(/function()/g, ''); 
  returnThing = returnThing.replace(") {", ''); 
  elements[elements.length] = returnThing; 
};

这个问题很常见——Firefox的toSource()是个非标准方法,Chrome和Safari根本不支持,而且你用toString()的思路本身就不对(默认toString()只会返回"[object Object]"),手动拼接属性值再靠正则擦屁股的方式也太脆弱了。咱们来写个靠谱的兼容方案:

方案1:自定义一个toSource替代函数

这个函数会模拟Firefox toSource()的行为,返回对象的字面量形式,同时只处理对象自身的属性(不会混入原型链上的方法):

function objectToSource(obj) {
  // 处理null和基本类型
  if (obj === null) return 'null';
  if (typeof obj !== 'object') return String(obj);
  
  // 处理数组
  if (Array.isArray(obj)) {
    return '[' + obj.map(item => objectToSource(item)).join(', ') + ']';
  }
  
  // 处理普通对象
  const props = [];
  for (const key in obj) {
    // 只取对象自己的属性,跳过原型上的(比如你的render方法)
    if (obj.hasOwnProperty(key)) {
      // 处理属性名:如果是合法标识符就直接用,否则加引号
      const keyStr = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : `"${key}"`;
      const valueStr = objectToSource(obj[key]);
      props.push(`${keyStr}: ${valueStr}`);
    }
  }
  return `({${props.join(', ')}})`;
}

然后修改你的render方法,用这个函数替代原生toSource():

rect.prototype.render = function() {
  // 用自定义函数生成兼容的对象字面量字符串
  const sourceStr = objectToSource(this);
  elements.push(sourceStr);
  
  // 你原来的手动拼接和正则替换逻辑可以完全删掉了,上面的函数已经能生成正确的结果
};

方案2:用JSON.stringify(适合纯数据对象)

如果你的rect对象里没有函数、undefined这类JSON不支持的类型,直接用JSON.stringify会更简单,只要稍微调整格式就能接近toSource()的输出:

rect.prototype.render = function() {
  // JSON.stringify会自动忽略原型属性,只序列化自身可枚举属性
  const jsonStr = JSON.stringify(this);
  // 给JSON字符串套个括号,模拟toSource()的格式
  const sourceStr = `(${jsonStr})`;
  elements.push(sourceStr);
};

为什么你的toString()尝试没用?

Object.prototype.toString()的默认行为是返回对象的类型标识(比如"[object Object]"),只有当你给对象自定义了toString方法时,才会返回你想要的内容。显然你的rect实例没有自定义这个方法,所以完全达不到toSource()的效果。而你手动遍历拼接的方式,本质是把所有属性值拼接成一个长字符串,再靠正则去修正,这种方式完全依赖固定的属性值顺序和内容,一旦属性值变化,正则就失效了,非常不可靠。

内容的提问来源于stack exchange,提问作者Ronan Leonard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:14:26