предисловие

В процессе фактической разработки я накопил некоторые общие и очень полезные навыки работы с Javascript и фрагменты кода, в том числе скомпилированные навыки использования JS других великих богов. Сегодня я просмотрела 9 для вашей справки.

1. Динамически загружать файлы JS

В некоторых особых сценариях, особенно при разработке некоторых библиотек и фреймворков, мы иногда динамически загружаем и выполняем JS-файлы. Ниже приведена простая инкапсуляция с использованием Promise.

function loadJS(files, done) {
   // Get the head tag
   const head = document. getElementsByTagName('head')[0];
   Promise.all(files.map(file => {
     return new Promise(resolve => {
       // create script tag and add to head
       const s = document.createElement('script');
       s.type = "text/javascript";
       s.async = true;
       s.src = file;
       // Listen to the load event, resolve if the loading is complete
       s. addEventListener('load', (e) => resolve(), false);
       head.appendChild(s);
     });
   })).then(done); // everything is done, execute the user's callback event
}
loadJS(["test1.js", "test2.js"], () => {
   // user's callback logic
});There are two core points in the code above. One is to use Promise to process asynchronous logic, but to use script tags to load and execute js.

2. Внедрить механизм шаблонов

В следующем примере используется очень мало кода для реализации механизма динамического рендеринга шаблонов. Он не только поддерживает замену обычных динамических переменных, но также поддерживает логику динамического синтаксиса JS, включая циклы for, суждения if и т. д.

// This is a dynamic template that contains js code
var template =
'My avorite sports:' +
'<%if(this.showSports) {%>' +
     '<% for(var index in this.sports) { %>' +
     '<a><%this.sports[index]%></a>' +
     '<%}%>' +
'<%} else {%>' +
     '<p>none</p>' +
'<%}%>';
// This is the function string we're going to concatenate
const code = `with(obj) {
   var r=[];
   r.push("My avorite sports:");
   if(this. showSports) {
     for(var index in this. sports) {
       r. push("<a>");
       r.push(this.sports[index]);
       r. push("</a>");
     }
   } else {
     r.push("<span>none</span>");
   }
   return r.join("");
}`
// dynamically rendered data
const options = {
   sports: ["swimming", "basketball", "football"],
   showSports: true
}
// Build a feasible function and pass in parameters to change the direction of this when the function is executed
result = new Function("obj", code).apply(options, [options]);
console. log(result);

3. Используйте сокращение для преобразования структуры данных

Иногда клиентской части необходимо преобразовать данные из серверной части, чтобы адаптироваться к бизнес-логике клиентской части, или преобразовать формат данных компонента, а затем передать их серверной части для обработки и уменьшить очень мощный инструмент.

const arr = [
    { classId: "1", name: "Jack", age: 16 },
    { classId: "1", name: "Jon", age: 15 },
    { classId: "2", name: "Jenny", age: 16 },
    { classId: "3", name: "Jim", age: 15 },
    { classId: "2", name: "Zoe", age: 16 }
];
groupArrayByKey(arr, "classId");
function groupArrayByKey(arr = [], key) {
    return arr.reduce((t, v) => (!t[v[key]] && (t[v[key]] = []), t[v[key]].push(v), t), {})
}

Если многие сложные логики обрабатываются с помощью сокращения, они очень простые.

4. Добавьте значение по умолчанию

Иногда метод требует, чтобы пользователь передал параметр. Обычно у нас есть два способа справиться с этим. Если пользователь не передает, мы обычно даем значение по умолчанию, или пользователь должен передать параметр и выдать ошибку, если он не передан.

function double() {
     return value *2
}
// If not passed, give a default value of 0
function double(value = 0) {
     return value * 2
}
// The user must pass a parameter, and an error will be thrown if no parameter is passed
const required = () => {
     throw new Error("This function requires one parameter.")
}
function double(value = required()) {
     return value * 2
}
double(3) // 6
double() // throw Error

Метод listen используется для создания собственной http-службы NodeJS и прослушивания порта, создания контекста в функции обратного вызова службы, а затем вызова функции обратного вызова, зарегистрированной пользователем, и передачи сгенерированного контекста. Давайте посмотрим на реализацию createContext и handleRequest раньше.

5. Функция выполняется только один раз

В некоторых случаях у нас есть специальные сценарии, в которых определенную функцию разрешается выполнять только один раз, или связанный метод разрешается выполнять только один раз.

export function once (fn) {
   // Use the closure to determine whether the function has been executed
   let called = false
   return function () {
     if (! called) {
       called = true
       fn. apply(this, arguments)
     }
   }
}

6. Реализуйте карринг

Каррирование в JavaScript — это процесс преобразования функции, которая принимает несколько аргументов, в серию функций, которые принимают только один аргумент. Это позволяет более гибко использовать функции, уменьшает дублирование кода и повышает читабельность кода.

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}
function add(x, y) {
  return x + y;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)); // output 3
console.log(curriedAdd(1, 2)); // output 3

С помощью каррирования мы можем модулировать некоторые общие функции, такие как проверка, кэширование и так далее. Это улучшает ремонтопригодность и читабельность кода и снижает вероятность ошибок.

7. Реализуйте одноэлементный режим

Одноэлементный режим JavaScript является широко используемым режимом проектирования. Он может гарантировать, что у класса будет только один экземпляр, и предоставить глобальную точку доступа к экземпляру. Он имеет широкий спектр сценариев приложений в JS, таких как корзины покупок, объекты кеша, глобальное управление состоянием и многое другое.

let cache;
class A {
  // ...
}
function getInstance() {
  if (cache) return cache;
  return cache = new A();
}
const x = getInstance();
const y = getInstance();
console.log(x === y); // true

8. Реализуйте спецификацию CommonJs

Основная идея спецификации CommonJS заключается в том, чтобы рассматривать каждый файл как модуль, каждый модуль имеет свою собственную область видимости, а переменные, функции и объекты в нем являются приватными и не могут быть доступны извне. Чтобы получить доступ к данным в модуле, вы должны экспортировать и требовать.

// id: full file name
const path = require('path');
const fs = require('fs');
function Module(id){
     // Used to uniquely identify the module
     this.id = id;
     // Properties and methods used to export modules
     this.exports = {};
}
function myRequire(filePath) {
     // Directly call the static method of Module to load the file
     return Module._load(filePath);
}
Module._cache = {};
Module._load = function(filePath) {
     // First address the absolute path of the file through the filePath passed in by the user
     // Because in CommnJS, the unique identifier of the module is the absolute path of the file
     const realPath = Module._resoleveFilename(filePath);
     // Cache priority, if it exists in the cache, it will directly return the exports property of the module
     let cacheModule = Module._cache[realPath];
     if(cacheModule) return cacheModule. exports;
     // If it is loaded for the first time, a new module is required, and the parameter is the absolute path of the file
     let module = new Module(realPath);
     // Call the load method of the module to compile the module
     module.load(realPath);
     return module. exports;
}
// The node file is not discussed yet
Module._extensions = {
    // Process the js file
   ".js": handleJS,
   // process the json file
   ".json": handleJSON
}
function handleJSON(module) {
  // If it is a json file, read it directly with fs.readFileSync,
  // Then use JSON.parse to convert and return directly
   const json = fs.readFileSync(module.id, 'utf-8')
   module.exports = JSON.parse(json)
}
function handleJS(module) {
   const js = fs. readFileSync(module. id, 'utf-8')
   let fn = new Function('exports', 'myRequire', 'module', '__filename', '__dirname', js)
   let exports = module. exports;
   // The assembled function can be executed directly
   fn.call(exports, exports, myRequire, module, module.id, path.dirname(module.id))
}
Module._resolveFilename = function (filePath) {
   // Splice the absolute path, and then search it, if it exists, it will return
   let absPath = path. resolve(__dirname, filePath);
   let exists = fs.existsSync(absPath);
   if (exists) return absPath;
   // If it does not exist, try splicing .js, .json, .node in sequence
   let keys = Object.keys(Module._extensions);
   for (let i = 0; i < keys. length; i++) {
     let currentPath = absPath + keys[i];
     if (fs.existsSync(currentPath)) return currentPath;
   }
};
Module.prototype.load = function(realPath) {
   // Get the file extension and hand it over to the corresponding method for processing
   let extname = path.extname(realPath)
   Module._extensions[extname](this)
}

Выше приведена простая реализация спецификации CommonJs. Ядро решает проблему изоляции области и предоставляет метод Myrequire для загрузки методов и свойств.

9. Получите свойства объекта рекурсивно

Если бы мне нужно было выбрать наиболее широко используемый шаблон проектирования, я бы выбрал шаблон наблюдателя. Если бы мне пришлось выбирать наиболее алгоритмическое мышление, с которым я сталкивался, это должна была бы быть рекурсия. Рекурсия делит исходную задачу на структуры с одинаковой структурой. подзадачи, а затем решить эти подзадачи по очереди и объединить результаты подзадач, чтобы, наконец, получить ответ на исходную проблему.

const user = {
   info: {
     name: "Jacky",
     address: { home: "MLB", company: "AI" },
   },
};
// obj is the object to get the property, path is the path, and fallback is the default value
function get(obj, path, fallback) {
   const parts = path. split(".");
   const key = parts. shift();
   if (typeof obj[key] !== "undefined") {
     return parts. length > 0 ?
       get(obj[key], parts. join("."), fallback) :
       obj[key];
   }
   // return fallback if key not found
   return fallback;
}
console.log(get(user, "info.name")); // Jacky
console.log(get(user, "info.address.home")); // MLB
console.log(get(user, "info.address.company")); // AI
console.log(get(user, "info.address.abc", "fallback")); // fallback

Выше отобраны 9 навыков JS, которые автор считает более полезными, и я надеюсь, что они будут полезны всем.