Вы можете использовать Array # map и Array # join вместо $ .each.Я нахожу это намного более читабельным (субъективным).
Также использующий, деструктурирующий и распространяющий синтаксис.
const data=[{"name":"메뉴1","permission":"1","link":"http://naver.com"},{"name":"메뉴2","permission":"2","link":"http://daum.net","sub":[{"name":"메뉴2-1","permission":"1","link":"http://google.com"},{"name":"메뉴2-2","permission":"1","link":"http://yahoo.com"}]}]
function generateHTML({link,permission,name}, sub) {
return `
<li>
<a href="${link}" title="${permission}">
${name}
</a>
${sub||""}
</li>
`
}
const res = data.map(item => {
let sub = "";
if (item.sub) {
sub = `<ul>${item.sub.map(ele=>generateHTML(ele)).join("")}</ul>`
}
return generateHTML(item, sub);
}).join("");
$("nav").html(`<ul>${res}</ul>`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav></nav>
Альтернативная рекурсивная версия (работает с любой глубиной подэлементов):
const data = [{"name":"메뉴1","permission":"1","link":"http://naver.com"},{"name":"메뉴2","permission":"2","link":"http://daum.net","sub":[{"name":"메뉴2-1","permission":"1","link":"http://google.com"},{"name":"메뉴2-2","permission":"1","link":"http://yahoo.com","sub":[{"name":"메뉴2-2-1","permission":"1","link":"http://google.com"},{"name":"메뉴2-2-2","permission":"1","link":"http://yahoo.com"}]}]}]
function generateHTML({link,permission,name, sub}) {
return `
<li>
<a href="${link}" title="${permission}">
${name}
</a>
${sub ? `<ul>${sub.map(generateHTML).join("")}</ul>` : ""}
</li>
`
}
const res = data.map(generateHTML).join("");
$("nav").html(`<ul>${res}</ul>`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav></nav>