Начало
со многими новичкамиJavascript
Я, как новичок, поначалу тоже пользовался формой сращивания струн,JSON
встраивание данныхHTML
середина. Объем кода в начале небольшой, что пока приемлемо. Но когда структура страницы усложняется, ее недостатки становятся невыносимыми:
- Написание бессвязное. Каждый раз, когда вы пишете переменную, вы должны разбивать и вставлять + и ". Это очень подвержено ошибкам.
- Не может быть использован повторно.
HTML
Фрагменты представляют собой дискретные данные, и из них трудно извлечь повторяющиеся части. - нельзя хорошо использовать
<template>
Этикетка. ЭтоHTML5
Новая этикетка в стандарте настоятельно рекомендуетHTML
шаблон поставить<template>
теги, чтобы сделать код более кратким.
В то время мое настроение было таким: это TMD издевается надо мной?
Так это вышло позжеES6
,Строки шаблона ES6Пользоваться действительно удобно.Для старых проектов проект неwebpack
,gulp
и другие инструменты сборки, не могут быть использованыES6
синтаксис, но хотим научиться этому прекрасному способу обработки склейки строк, мы могли бы также попытаться написать его самостоятельно, в основном для идей, которые вы можете использоватьES6
Моделирование синтаксисаСтроки шаблона ES6этой функции.
Бэкэнд обычно возвращаетсяJSON
Формат данных, поэтому мы моделируем по следующим правилам.
Описание требования
Реализуйте метод render(template, context) для заполнения заполнителей в шаблоне контекстом.
Требовать:
Никаких компонентов потока управления (таких как циклы, условия и т. д.) не требуется, только подстановка переменных.
Каскадные переменные также могут быть расширены
Экранированные разделители { и } не должны отображаться, между разделителями и переменными допускаются пробелы.
var obj = {name:"二月",age:"15"};
var str = "{{name}}很厉害,才{{age}}岁";
输出:二月很厉害,才15岁。
PS: эта статья должнарегулярное выражениеесть некоторое понимание, если еще нетрегулярное выражение, Рекомендуется изучить его в первую очередь. Регуляризация также является необходимым навыком для собеседования и письменного теста. В конце ссылки выше есть много ссылок на регулярное обучение.
Если бы это были вы, как бы вы этого добились? Можно попробовать сначала написать самому, это не сложно реализовать.
Я не буду говорить своей реализации, я поставил этот вопрос к другим друзьям, не одинаковую реализацию, мы смотрим, чтобы достичь нескольких детских туфлей, а затем находить общие мифы на их основе и недостаточно для достижения элегантного места.
Детская обувь февраля:
let str = "{{name}}很厉害,才{{age}}岁"
let obj = {name: '二月', age: 15}
function test(str, obj){
let _s = str.replace(/\{\{(\w+)\}\}/g, '$1')
let result
for(let k in obj) {
_s = _s.replace(new RegExp(k, 'g'), obj[k])
}
return _s
}
const s = test(str, obj)
Самое основное это реализовать, но в коде еще много не рассмотренных проблем.Прежде всего значение ключа Object не обязательно просто \w, а если строка такая:
let str = "{{name}}很name厉害,才{{age}}岁"`
会输出 :二月很厉害二月害,才15岁
Здесь вам нужно понять регулярную группировку, чтобы понять$1
Смысл, ошибка очевидна, не заменять исходную строкуname
Он также был заменен.Из кода мы можем увидеть идею февраля.
- Цель кодекса состоит в том, чтобы
str
, первое совпадение с обычным{{name}}
а также{{age}}
, затем используйте группировку, чтобы получить скобкиname
,age
, и, наконец, используйтеreplace
метод положить{{name}}
а также{{age}}
заменитьname
а такжеage
, последняя строка становитсяИмя очень мощное, только возраст,наконецfor in
Когда цикл используется, он вызывает замену всех из них. - использовать
for in
Нет необходимости в цикле вообще.for in
попробуй не использоватьfor in
,for in
Он будет проходить через себя и все свойства цепочки прототипов.
Детская обувь Zhiqin:
var str = "{{name}}很厉害,才{{age}}岁";
var str2 = "{{name}}很厉name害,才{{age}}岁{{name}}";
var obj = {name: '周杰伦', age: 15};
function fun(str, obj) {
var arr;
arr = str.match(/{{[a-zA-Z\d]+}}/g);
for(var i=0;i<arr.length;i++){
arr[i] = arr[i].replace(/{{|}}/g,'');
str = str.replace('{{'+arr[i]+'}}',obj[arr[i]]);
}
return str;
}
console.log(fun(str,obj));
console.log(fun(str2,obj));
Мысль правильная, зная, что последнее, что нужно заменить, это{{name}}
а также{{age}}
Целая, не последняя замена, как февральская детская обувьname
, все запущено будет без проблем, реализация реализована, но немного чувствуется, что то, что мы хотим обсудить, это строчка кода, то есть чем меньше кода, тем лучше.
Детская обувь Xiaowei:
function a(str, obj) {
var str1 = str;
for (var key in obj) {
var re = new RegExp("{{" + key + "}}", "g");
str1 = str1.replace(re, obj[key]);
}
console.log(str1);
}
const str = "{{name}}很厉name害{{name}},才{{age}}岁";
const obj = { name: "jawil", age: "15" };
a(str, obj);
Реализация проста и понятна, т.е.obj
изkey
значение обхода, а затем прописано{{key}}
, и, наконец, используйтеobj[key]
то естьvalue
Пучок{{key}}
Заменено все, идея очень хорошая, такая же как и у меня в оригинале.
Моя реализация:
function parseString(str, obj) {
Object.keys(obj).forEach(key => {
str = str.replace(new RegExp(`{{${key}}}`,'g'), obj[key]);
});
return str;
}
const str = "{{name}}很厉name害{{name}},才{{age}}岁";
const obj = { name: "jawil", age: "15" };
console.log(parseString(str, obj));
На самом деле здесь есть еще некоторые проблемы, во-первых, я бесполезен.for...in
Цикл существует для учета ненужных циклов, потому чтоfor...in
Цикл будет проходить через все перечисляемые свойства цепочки прототипов, вызывая ненужные циклы.
Мы можем просто посмотреть на пример и увидетьfor...in
ужасающий.
// Chrome v63
const div = document.createElement('div');
let m = 0;
for (let k in div) {
m++;
}
let n = 0;
console.log(m); // 231
console.log(Object.keys(div).length); // 0
Атрибут узла DOM имеет так много атрибутов, что этот пример просто для всехfor in
Эффективность обхода, не легко использоватьfor in
цикл через этоDOM
Количество узлов также можно понять в определенной степени.React
изVirtual DOM
идеи и превосходство.
помимо использованияfor in
получение петлиobj
изkey
значение, вы также можете использоватьObject.key()
Получать,Object.getOwnPropertyNames()
так же какReflect.ownKeys()
Вы также можете получить его, так в чем разница между этими двумя? Вот краткое описание некоторых их отличий.
for...in
Цикл: он будет проходить свойства самого объекта, а также свойства прототипа,for...in
Цикл проходит только по перечислимому (исключаяenumerable
дляfalse
)Атрибуты. картинаArray
а такжеObject
Объекты, созданные с помощью встроенных конструкторов, наследуются отObject.prototype
а такжеString.prototype
неперечислимые свойства ;
Object.key()
: вы можете получить свои собственные перечисляемые свойства, но не свойства в цепочке прототипов;
Object.getOwnPropertyNames()
: вы можете получить все его собственные свойства (в том числе неперечислимые), но вы не можете получить свойства в цепочке прототипов, и вы также не можете получить свойство Symbols.
Reflect.ownKeys
: этот метод используется для возврата всех свойств объекта, в основном эквивалентныхObject.getOwnPropertyNames()
а такжеObject.getOwnPropertySymbols
Сумма.
Вышеизложенное может быть более абстрактным и недостаточно интуитивным. Вы можете видеть, что я написалDEMO
, все просто и понятно.
const parent = {
a: 1,
b: 2,
c: 3
};
const child = {
d: 4,
e: 5,
[Symbol()]: 6
};
child.__proto__ = parent;
Object.defineProperty(child, "d", { enumerable: false });
for (var attr in child) {
console.log("for...in:", attr);// a,b,c,e
}
console.log("Object.keys:", Object.keys(child));// [ 'e' ]
console.log("Object.getOwnPropertyNames:", Object.getOwnPropertyNames(child)); // [ 'd', 'e' ]
console.log("Reflect.ownKeys:", Reflect.ownKeys(child)); // [ 'd', 'e', Symbol() ]
наконец понял
Вышеупомянутая реализация на самом деле очень проста, но все же есть некоторые недостатки.MDNСначала давайте разберемсяreplaceПрименение.
написано в документеstr.replace(regexp|substr, newSubStr|function)
, мы можем узнать, чтоreplaceметод может быть передан вfunction
Перезвоните,
function (replacement)
Функция, используемая для создания новой подстроки, возвращаемое значение которой заменит результат, соответствующий первому аргументу. обратитесь к этомуУкажите функцию в качестве параметра.
С этим предложением, на самом деле, очень легко добиться, сначала посмотрите на конкретный код, а затем выполните следующий анализ.
function render(template, context) {
return template.replace(/\{\{(.*?)\}\}/g, (match, key) => context[key]);
}
const template = "{{name}}很厉name害,才{{age}}岁";
const context = { name: "jawil", age: "15" };
console.log(render(template, context));
Вы можете проанализировать его в соответствии с вышеуказанным документом:Возвращаемое значение этой функции (obj[key]=jawil
) заменит первый аргумент (match=={{name}}
) соответствует результату.
Кратко проанализируйте:.*?
Это регулярное фиксированное использование коллокации, указывающее на то, чтоНе жадный матчОбразец, совпадайте как можно меньше, что это значит? Возьмем простой пример.
Давайте посмотрим на пример:
源字符串:aa<div>test1</div>bb<div>test2</div>cc
正则表达式一:<div>.*</div>
匹配结果一:<div>test1</div>bb<div>test2</div>
正则表达式二:<div>.*?</div>
匹配结果二:<div>test1</div>(这里指的是一次匹配结果,不使用/g,所以没包括<div>test2</div>)
скопировать код
В соответствии с приведенным выше примером проанализируйте совпадающее поведение, чтоЖадное и нежадное сопоставлениемодель.
использоватьнежадный матчмодуль соответствует всем{{name}}
,{{age}}
, упомянутый вышеРегулярная группировка, групповое соответствиеname
, то есть,function
второй параметрkey
.
Таким образом, смысл этой строки кода очень ясен, обычные совпадения с{{name}}
, сгруппируйтесьname
, затем поставьте{{name}}
заменитьobj[name](jawil)
.
Конечно, позже я узнал, что есть небольшая проблема, если есть пробел, совпадение не удастся, как это пишет:
const template = "{{name }}很厉name害,才{{age }}岁";
Поэтому, исходя из вышеизложенного, необходимо убрать пробелы.На самом деле это очень просто.Используйте обычные илиString.prototype.trim()
метод подойдет.
function render(template, context) {
return template.replace(/\{\{(.*?)\}\}/g, (match, key) => context[key.trim()]);
}
const template = "{{name }}很厉name害,才{{age }}岁";
const context = { name: "jawil", age: "15" };
console.log(render(template, context));
Подключите функцию к цепочке прототипов String, чтобы получить окончательную версию.
Даже мы можем добиться некоторых крутых эффектов, изменив цепочку прототипов:
String.prototype.render = function (context) {
return this.replace(/\{\{(.*?)\}\}/g, (match, key) => context[key.trim()]);
};
Если середина {} не является числом, сам {} не нужно экранировать, поэтому последний наиболее лаконичный код:
String.prototype.render = function (context) {
return this.replace(/{{(.*?)}}/g, (match, key) => context[key.trim()]);
};
После этого мы можем назвать это так:
"{{name}}很厉name害,才{{ age }}岁".render({ name: "jawil", age: "15" });
награда
Через реализацию небольшой строки шаблона я понял, что реализовать функцию несложно, но добиться совершенства действительно сложно.Нужно иметь твердое понимание основы, иметь определенную осадку, а затем продолжать отшлифовать его, чтобы он был более элегантным.Реализация многих точек знаний часто может быть расширена из маленькой точки.