JavaScript中与Python的format()函数相对应的是什么?

79

Python有一个非常好用的函数,可以将这个东西转换成:

bar1 = 'foobar'
bar2 = 'jumped'
bar3 = 'dog'

foo = 'The lazy ' + bar3 + ' ' + bar2 ' over the ' + bar1
# The lazy dog jumped over the foobar

变成了这样:

bar1 = 'foobar'
bar2 = 'jumped'
bar3 = 'dog'

foo = 'The lazy {} {} over the {}'.format(bar3, bar2, bar1)
# The lazy dog jumped over the foobar

JavaScript 有这样的函数吗?如果没有,我该如何创建一个与 Python 实现相同语法的函数?


2
请查看此线程以获取解决方案:https://dev59.com/YXRB5IYBdhLWcg3weXOX - Daniel Doezema
我经常在许多网站中使用jQuery,所以它不会有什么坏处。JS允许你对字符串对象进行子类化或添加函数吗? - Blender
1
“原型”是语言的一个特性。prototypejs库是完全独立的。 - user113716
@Stefano:那个问题是在将近两年后提出的,回答也较少。 - Blender
显示剩余4条评论
19个回答

69

另一种方法是使用 String.prototype.replace 方法,将一个“替换器”函数作为第二个参数:

String.prototype.format = function () {
  var i = 0, args = arguments;
  return this.replace(/{}/g, function () {
    return typeof args[i] != 'undefined' ? args[i++] : '';
  });
};

var bar1 = 'foobar',
    bar2 = 'jumped',
    bar3 = 'dog';

'The lazy {} {} over the {}'.format(bar3, bar2, bar1);
// "The lazy dog jumped over the foobar"

2
好的,明白了。http://jsfiddle.net/wFb2p/6/ 我之前没有意识到该函数会针对每个匹配项运行一次。+1 - user113716
2
使用函数进行替换也意味着您可以相当容易地扩展它以支持非空占位符,例如{1} - Duncan
不鼓励扩展原生类。您应该使用函数或定义自己的类/子类。这有助于其他程序员区分本机和非本机功能。它还可以避免代码干扰的风险 - 其他人也可能定义String.Prototype.format - loxaxs
为什么这不是 JavaScript 的标准部分呢? - default123
我在每个JS项目中都使用这个函数,谢谢! - Pedro Lobito
为什么这个答案不是SO上最著名的答案?+1 - sjsam

64

有一种方法,但不完全使用 format。

var name = "John";
var age = 19;
var message = `My name is ${name} and I am ${age} years old`;
console.log(message);

jsfiddle - 链接


11
这很有趣,但这并没有解决问题。如果我们无法传递特定的上下文,那么 ES6 中的方法在许多情况下都是无意义的。你所写的大部分只是用于字符串连接的语法糖。 - Loïc Faure-Lacroix
4
这确实解决了问题,如果你没有上下文,你可以轻松地执行诸如var message = `My name is ${name || 'default'} and I am ${age || 'default'} years old`;这样的操作。 - HussienK
2
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals - shrewmouse
4
在Python 3.6中,你可以使用f'My name is {name} and I am {age}'来表达“我的名字是{name},我今年{age}岁”的意思。 - Blender
1
@shrewmouse,谢谢。这份文档对我非常重要。我使用了${name},但它没有起作用。我读了你提到的文档,发现"模板文字用反引号(`)而不是双引号或单引号括起来"。所以我意识到自己犯了什么错误。 - vainquit
显示剩余3条评论

35

简述

foo = (a, b, c) => `The lazy ${a} ${b} over the ${c}`

为什么仅有模板字符串是不够的

ES6 模板字符串 提供了一个类似于 Python 字符串格式化的功能。然而,在构造字符串之前,您必须知道变量:

var templateString = `The lazy ${bar3} ${bar2} over the ${bar1}`;

为什么要使用格式化?

Python的str.format允许您在甚至不知道要插入哪些值之前就指定字符串,例如:

foo = 'The lazy {} {} over the {}'

bar1 = 'foobar'
bar2 = 'jumped'
bar3 = 'dog'

foo.format(bar3, bar2, bar1)

解决方案

使用箭头函数,我们可以优雅地封装模板字符串以供后续使用:

foo = (a, b, c) => `The lazy ${a} ${b} over the ${c}`

bar1 = 'foobar';
bar2 = 'jumped';
bar3 = 'dog';

foo(bar3, bar2, bar1)

当然,这也适用于常规函数,但箭头函数使我们能够将其变成一行代码。这两个功能在大多数浏览器和运行时环境中都可用:


4
这个回答忽略了使用xx.format()的一个重要原因,与Yash Mehrotra的答案具有相同的缺点,即要格式化的字符串可能需要是动态的而不是硬编码的。 - mwag
2
这应该是最佳答案。谢谢! - Peijun Zhu

12

寻找与此相同问题的答案,我刚刚发现了这个:https://github.com/davidchambers/string-format,它是“受Python的str.format()启发的JavaScript字符串格式化”。它似乎与Python的format()函数基本相同。


我正在寻找的东西。目前它还不支持Python填充功能。 - loxaxs

7

来自YAHOO库:

YAHOO.Tools.printf = function() { 
  var num = arguments.length; 
  var oStr = arguments[0];   
  for (var i = 1; i < num; i++) { 
    var pattern = "\\{" + (i-1) + "\\}"; 
    var re = new RegExp(pattern, "g"); 
    oStr = oStr.replace(re, arguments[i]); 
  } 
  return oStr; 
} 

调用方式:

bar1 = 'foobar'
bar2 = 'jumped'
bar3 = 'dog'

foo = YAHOO.Tools.printf('The lazy {0} {1} over the {2}', bar3, bar2, bar1); 

6

您可以在JS中使用模板字面量。

const bar1 = 'foobar'
const bar2 = 'jumped'
const bar3 = 'dog'
foo = `The lazy ${bar3} ${bar2} over the ${bar1}`

我认为这很有帮助。


4
这是我的第一次尝试。欢迎指出缺陷。
示例: http://jsfiddle.net/wFb2p/5/
String.prototype.format = function() {
    var str = this;
    var i = 0;
    var len = arguments.length;
    var matches = str.match(/{}/g);
    if( !matches || matches.length !== len ) {
        throw "wrong number of arguments";
    }
    while( i < len ) {
        str = str.replace(/{}/, arguments[i] );
        i++;
    }
    return str;
};

编辑:通过在while语句中消除.match()调用,使其更加高效。

编辑:更改后,如果您未传递任何参数,则会抛出相同的错误。


哇!那真是太快了。谢谢! - Blender
2
请确保检查 arguments[i] 是否存在。 - zzzzBov
@zzzzBov:好观点。我正要更新,如果参数数量与找到的“{}”数量不匹配,则会抛出错误。编辑:已更新。 - user113716

2

使用分割函数:

String.prototype.format = function (args) {
    var text = this
    for(var attr in args){
        text = text.split('${' + attr + '}').join(args[attr]);
    }
    return text
};

json = {'who':'Gendry', 'what':'will sit', 'where':'in the Iron Throne'}
text = 'GOT: ${who} ${what} ${where}';

console.log('context: ',json);
console.log('template: ',text);
console.log('formated: ',text.format(json));

Usando Regex:

String.prototype.format = function (args) {
    var text = this
    for(var attr in args){
        var rgx = new RegExp('\\${' + attr + '}','g');
        text = text.replace(rgx, args[attr]);
    }
    return text
};

json = {'who':'Gendry', 'what':'will sit', 'where':'in the Iron Throne'}
text = 'GOT: ${who} ${what} ${where}';

console.log('context: ',json);
console.log('template: ',text);
console.log('formated: ',text.format(json));


方便。我在原型之外实现了这个函数,并添加了一个 hasOwnProperty 检查:const format = (s, args) => { for (let attr in args) if (args.hasOwnProperty(attr)) s = s.split('${' + attr + '}').join(args[attr]); return s || ''; }; - A T

1

不使用额外函数的简单实现

[bar1, bar2, bar3].reduce(
  (str, val) => str.replace(/{}/, val),
  'The lazy {} {} over the {}'
)

1
String.prototype.format = function(args){
  //args - hash of params
  var text = this
  for(var attr in args){
    text = text.split('${' + attr + '}').join(args[attr]);
  }
  return text
}

用法:'Hello, ${NAME}。这是${FORMAT}'。format({NAME:'guys',FORMAT:'format()'})
更新:Python的f结尾字符串:
Python: f'string {expr}'
JavaScript: `string ${expr}`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接