/* ------------------------------
// 字符串模板1,语法严格,不能混用,效率相对较高
// 使用 {{ }} 作为标记是为了允许在模板中使用 JSON 字符串
// 用法 1(对象参数,对象可多次调用):
var say = "对 象:{{hi}}, {{to}}! {{hello}}, {{world}}!"
say = say.format({hi:"Hello", to:"World"})
.format({hello:"你好", world:"世界"})
console.log(say)
// 用法 2(数组参数):
var say = "数 组:{{0}}, {{1}}! {{0}}!"
say = say.format(["Hello", "World"])
console.log(say)
// 用法 3(字符串参数,最后一个字符串可以重复使用):
var say = "字符串:{{.}}, {{.}}! {{.}}!"
say = say.format("Hello", "World")
console.log(say)
// 用法 4(多次调用,字符串和数组不能共用,字符串必须首先处理):
// 无数组
var say = "{{.}}:3 2 1, {{hi}}, {{to}}! {{hello}}, {{world}}!"
say = say.format("多 次")
.format({hi: "Hello"})
.format({to: "World"})
.format({hello: "你好", world: "世界"})
console.log(say)
// 无字符串
var say = "多 次:{{2}} {{1}} {{0}}, {{hi}}, {{to}}! {{hello}}, {{world}}!"
say = say.format({hi: "Hello"})
.format({to: "World"})
.format([1,2,3])
.format({hello: "你好", world: "世界"})
console.log(say)
// 字符串和数组共用
var say = "{{.}}:{{2}} {{1}} {{0}}, {{hi}}, {{to}}! {{hello}}, {{world}}!"
say = say.format("出问题")
.format({hi: "Hello"})
.format({to: "World"})
.format([1,2,3])
.format({hello: "你好", world: "世界"})
console.log(say)
// 没有首先处理字符串
var say = "出问题:{{.}}, {{hi}}, {{to}}! {{hello}}, {{world}}!"
say = say.format({hi: "Hello"})
.format("3 2 1")
.format({to: "World"})
.format({hello: "你好", world: "世界"})
console.log(say)
------------------------------ */
String.prototype.format = function(arg) {
// 安全检查(长度不能小于 {{.}},为后面下标引用做准备)
var len = this.length
if (len < 5) { return this }
var start = 0, result = "", argi = 0
for (var i=0; i<=len; i++) {
// 处理 {{ }} 之外的内容
if (this[i] === "{" && this[i-1] === "{") {
result += this.slice(start, i-1)
start = i-1
} else if (this[i] === "}" && this[i-1] === "}") {
// 获取 {{ }} 中的索引
var index = this.slice(start+2, i-1)
if (index === ".") { // 字符串
result += arguments[argi]
// 最后一个字符串会重复使用
if (argi < (arguments.length - 1)) {
argi++
}
start = i+1
} else { // 对象或数组
if (arg[index] != null) {
result += arg[index]
start = i+1
}
}
}
}
// 处理最后一个 {{ }} 之后的内容
result += this.slice(start)
return result
}
/* ------------------------------
// 字符串模板2,语法*,使用灵活,效率相对较低(基本上模板1就够用了)
// 使用 {{ }} 作为标记是为了允许在模板中使用 JSON 字符串
// 用法 1(对象参数,对象可多次提供):
var say = "对 象:{{hi}}, {{to}}! {{hello}}, {{world}}!"
say = say.template({hi:"Hello", to:"World"}, {hello:"你好"}, {world:"世界"})
console.log(say)
// 用法 2(数组参数):
var say = "数 组:{{0}}, {{1}}! {{0}}!"
say = say.template(["Hello", "World"]);
console.log(say)
// 用法 3(字符串参数,最后一个字符串可以重复使用):
var say = "字符串:{{.}}, {{.}}! {{.}}!"
say = say.template("Hello", "World");
console.log(say)
// 用法 4(混用,对象、数组、字符串可以在参数的任意位置,对象可多次提供):
var say = "{{.}}:{{2}} {{1}} {{0}}, {{hi}}, {{to}}! {{.}}, {{.}}!"
say = say.template([1,2,3], "混 用", {hi: "Hello", to: "World"}, "你好", "世界");
console.log(say)
// 用法 5(多次调用,字符串参数要一次处理完,对象可多次提供):
var say = "{{.}}:{{2}} {{1}} {{0}}, {{hi}}, {{to}}! {{.}}, {{.}}!"
say = say.template([1,2,3])
.template({hi: "Hello"})
.template("多 次", "你好", "世界")
.template({to: "World"});
console.log(say)
------------------------------ */
String.prototype.template = function() {
// 安全检查(长度不能小于 {{.}},为后面下标引用做准备)
var len = this.length
if (len < 5) { return this }
var start = 0, result = ""
var objs = [], strs = [], stri = 0
// 参数分类
for (var i in arguments) {
switch (typeof arguments[i]) {
case "object": objs.push(arguments[i]);break // 对象(包括数组,可以有多个)
default : strs.push(arguments[i]) // 其它(当做字符串处理)
}
}
for (var i=0; i<len; i++) {
// 处理 {{ }} 之外的内容
if (this[i] === "{" && this[i-1] === "{") {
result += this.slice(start, i-1)
start = i-1
} else if (this[i] === "}" && this[i-1] === "}") {
// 获取 {{ }} 中的索引
var index = this.slice(start+2, i-1)
if (index === "." && strs.length > 0) { // 字符串
result += strs[stri]
// 最后一个字符串会重复使用
if (stri < strs.length - 1) {
stri++
}
start = i+1
} else { // 对象或数组
for (var obji in objs) {
if (objs[obji][index] != null) {
result += objs[obji][index]
start = i+1
continue
}
}
}
}
}
// 处理最后一个 {{ }} 之后的内容
result += this.slice(start)
return result
}