반응형
반응형

프런트엔드 개발자를 위해 꼭 알아야 할 10가지 JavaScript 팁

https://medium.com/@london.lingo.01/10-must-know-javascript-tips-for-front-end-developers-b78b4afe6ad3

 

10 Must-Know JavaScript Tips for Front-End Developers

JavaScript is one of the most popular and powerful programming languages for web development. It allows you to create dynamic and…

medium.com

JavaScript는 웹 개발을 위한 가장 널리 사용되고 강력한 프로그래밍 언어 중 하나입니다. 이를 통해 동적 및 대화형 웹 페이지를 만들고, DOM을 조작하고, 서버와 통신하는 등의 작업을 수행할 수 있습니다. 그러나 JavaScript는 작업하기가 어렵고 좌절스러울 수도 있습니다. 특히 다른 언어에 익숙한 초보자나 개발자에게는 더욱 그렇습니다. 깨끗하고 효율적이며 유지 관리가 가능한 코드를 작성하기 위해 알아야 할 많은 단점, 함정 및 모범 사례가 있습니다.

이번 포스팅에서는 프론트엔드 개발자로서 기술과 생산성을 향상시키는 데 도움이 될 꼭 알아야 할 JavaScript 팁 10가지를 공유하겠습니다. 이 팁에서는 변수, 함수, 문자열, 배열, 개체, 비동기 작업, 모듈, 클래스, 약속 및 콘솔 메서드와 같은 JavaScript의 가장 중요하고 유용한 기능과 개념 중 일부를 다룹니다. 이를 효과적으로 사용하고 일반적인 실수나 오류를 방지하는 방법을 배우게 됩니다. 이 게시물을 마치면 JavaScript에 대해 더 잘 이해하고 더 읽기 쉽고 성능이 뛰어나며 디버그 가능한 코드를 작성하는 방법을 알게 될 것입니다.

그럼 시작해 보겠습니다! 프런트엔드 개발자가 꼭 알아야 할 10가지 JavaScript 팁은 다음과 같습니다.



Tip 1: Use const and let instead of var
One of the most common and confusing issues in JavaScript is the declaration and scope of variables. In the past, JavaScript only had one way to declare variables: using the var keyword. However, var has some drawbacks and limitations that can lead to bugs and errors. For example, var variables are function-scoped, meaning they are accessible within the function where they are declared, but not outside. This can cause problems when you have nested functions or loops that use the same variable name. Also, var variables are hoisted, meaning they are moved to the top of their scope before the code is executed. This can cause problems when you try to access a variable before it is declared or initialized.

To avoid these issues, ES6 introduced two new ways to declare variables: using the const and let keywords. Const and let variables are block-scoped, meaning they are accessible within the block where they are declared, but not outside. This can prevent accidental overwriting or leakage of variables. Also, const and let variables are not hoisted, meaning they are only available after they are declared and initialized. This can prevent accessing undefined or uninitialized variables.

Another difference between const and let is that const variables cannot be reassigned after they are declared. This means that once you assign a value to a const variable, you cannot change it later. This can prevent accidental or intentional modification of variables that should remain constant. Let variables, on the other hand, can be reassigned after they are declared. This means that you can change the value of a let variable as many times as you want.

Here is an example of using const and let to declare variables:

// Using var
var name = "John";
var age = 25;
var hobbies = ["reading", "gaming", "coding"];

function sayHello() {
  var name = "Jane"; // This will overwrite the global name variable
  console.log("Hello, " + name); // Hello, Jane
}

sayHello();
console.log(name); // Jane

// Using const and let
const name = "John"; // This will create a constant name variable
let age = 25; // This will create a let age variable
const hobbies = ["reading", "gaming", "coding"]; // This will create a constant hobbies array

function sayHello() {
  let name = "Jane"; // This will create a local name variable
  console.log("Hello, " + name); // Hello, Jane
}

sayHello();
console.log(name); // John

// You can change the value of a let variable
age = 26;
console.log(age); // 26

// You cannot change the value of a const variable
name = "Jack"; // TypeError: Assignment to constant variable.
hobbies.push("music"); // You can modify the elements of a const array, but not reassign it
console.log(hobbies); // ["reading", "gaming", "coding", "music"]
As you can see, using const and let can make your code more readable, performant and debuggable. It can also help you avoid common errors and bugs that can occur with var variables. Therefore, you should always use const and let instead of var when declaring variables in JavaScript.

Tip 2: Use arrow functions for concise and clean syntax
Another common and important feature of JavaScript is functions. Functions are blocks of code that can be defined and executed to perform a specific task or operation. Functions can also accept parameters and return values. However, functions can also be verbose and complex to write and use, especially when dealing with the this keyword or binding issues.

To simplify and improve the syntax and functionality of functions, ES6 introduced arrow functions. Arrow functions are a shorter and more expressive way to write functions in JavaScript. Arrow functions use the => symbol to separate the parameters and the body of the function. Arrow functions can also omit the parentheses around the parameters if there is only one parameter, and the curly braces and return keyword around the body if there is only one expression.

Here is an example of using arrow functions to write shorter and more expressive code:

// Using regular functions
function add(a, b) {
  return a + b;
}

function greet(name) {
  return "Hello, " + name;
}

function square(x) {
  return x * x;
}

console.log(add(2, 3)); // 5
console.log(greet("John")); // Hello, John
console.log(square(4)); // 16

// Using arrow functions
const add = (a, b) => a + b;
const greet = name => "Hello, " + name;
const square = x => x * x;

console.log(add(2, 3)); // 5
console.log(greet("John")); // Hello, John
console.log(square(4)); // 16
As you can see, using arrow functions can make your code more concise and clean. It can also help you avoid some of the pitfalls and confusion that can occur with regular functions. For example, arrow functions do not have their own this keyword, meaning they inherit the this value from their enclosing scope. This can prevent issues with losing or changing the context of this when using callbacks or methods. Arrow functions also do not have their own arguments object, meaning they rely on the named parameters or the rest operator to access the arguments passed to them. This can prevent issues with accessing or modifying the arguments object in nested or strict mode functions.

Therefore, you should always use arrow functions instead of regular functions when writing concise and clean code in JavaScript.

Tip 3: Use template literals for dynamic and multi-line strings
One of the most common and useful data types in JavaScript is strings. Strings are sequences of characters that can be used to store and manipulate text, such as names, messages, URLs, etc. However, strings can also be tricky and tedious to work with, especially when you need to create dynamic or multi-line strings. For example, you need to use the + operator or the concat method to concatenate strings and variables, and you need to use the \n character or the backslash () to create new lines or escape characters.

To simplify and improve the creation and manipulation of strings, ES6 introduced template literals. Template literals are a new way to write strings in JavaScript that use the backtick (`) character instead of the single (‘) or double (“) quotes. Template literals allow embedding expressions and variables inside strings using the ${} syntax. Template literals also allow creating multi-line strings without using any special characters or escaping.

Here is an example of using template literals to create dynamic and multi-line strings with ease:

// Using regular strings
var name = "John";
var age = 25;
var message = "Hello, " + name + ".\nYou are " + age + " years old.";
console.log(message);
// Hello, John.
// You are 25 years old.

// Using template literals
const name = "John";
const age = 25;
const message = `Hello, ${name}.
You are ${age} years old.`;
console.log(message);
// Hello, John.
// You are 25 years old.
As you can see, using template literals can make your code more readable, interpolation and escaping. It can also help you avoid some of the errors and bugs that can occur with regular strings. For example, template literals do not require any quotation marks around the embedded expressions or variables, meaning they can handle any data type or value without causing syntax errors. Template literals also do not require any special characters or escaping for creating new lines or other characters, meaning they can handle any format or layout without causing display issues.

Therefore, you should always use template literals instead of regular strings when creating dynamic or multi-line strings in JavaScript.

Tip 4: Use destructuring assignment for extracting values from objects and arrays
Another common and useful data type in JavaScript is objects and arrays. Objects and arrays are collections of values that can be used to store and manipulate data, such as properties, methods, elements, etc. However, objects and arrays can also be complex and cumbersome to work with, especially when you need to extract or assign values from them. For example, you need to use the dot (.) or the bracket ([]) notation to access or modify the properties or elements of objects or arrays, and you need to use multiple variables or statements to extract or assign multiple values from them.

To simplify and improve the extraction and assignment of values from objects and arrays, ES6 introduced destructuring assignment. Destructuring assignment is a new way to write assignments in JavaScript that use the {} or [] syntax to unpack values from objects or arrays into variables. Destructuring assignment can also use the = symbol to provide default values or the … symbol to collect the remaining values into a new variable.

Here is an example of using destructuring assignment to simplify code and avoid repetition:

// Using regular assignments
var person = {
  name: "John",
  age: 25,
  hobbies: ["reading", "gaming", "coding"]
};

var name = person.name;
var age = person.age;
var hobbies = person.hobbies;

console.log(name); // John
console.log(age); // 25
console.log(hobbies); // ["reading", "gaming", "coding"]

// Using destructuring assignment
const person = {
  name: "John",
  age: 25,
  hobbies: ["reading", "gaming", "coding"]
};

const { name, age, hobbies } = person;

console.log(name); // John
console.log(age); // 25
console.log(hobbies); // ["reading", "gaming", "coding"]
As you can see, using destructuring assignment can make your code more readable, performant and convenient. It can also help you avoid some of the errors and bugs that can occur with regular assignments. For example, destructuring assignment can handle nested or complex objects or arrays without causing syntax errors. Destructuring assignment can also handle missing or undefined values without causing reference errors.

Therefore, you should always use destructuring assignment instead of regular assignments when extracting or assigning values from objects or arrays in JavaScript.

Tip 5: Use spread and rest operators for manipulating arrays and objects
Another common and important feature of JavaScript is the ability to manipulate arrays and objects. Arrays and objects are collections of values that can be used to store and manipulate data, such as properties, methods, elements, etc. However, arrays and objects can also be difficult and tedious to manipulate, especially when you need to copy, merge or split them. For example, you need to use the slice, concat or splice methods to copy, merge or split arrays, and you need to use the Object.assign or Object.keys methods to copy or merge objects.

To simplify and improve the manipulation of arrays and objects, ES6 introduced the spread and rest operators. The spread operator (…) allows expanding or spreading the values of an array or an object into individual values. The rest operator (…) allows collecting or gathering the remaining values of an array or an object into a new variable.

Here is an example of using the spread and rest operators to manipulate arrays and objects with ease:

// Using regular methods
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];

// Copying an array
var arr3 = arr1.slice();
console.log(arr3); // [1, 2, 3]

// Merging two arrays
var arr4 = arr1.concat(arr2);
console.log(arr4); // [1, 2, 3, 4, 5, 6]

// Splitting an array
var arr5 = arr4.splice(0, 3);
console.log(arr5); // [1, 2, 3]
console.log(arr4); // [4, 5, 6]

var obj1 = { name: "John", age: 25 };
var obj2 = { hobbies: ["reading", "gaming", "coding"] };

// Copying an object
var obj3 = Object.assign({}, obj1);
console.log(obj3); // { name: "John", age: 25 }

// Merging two objects
var obj4 = Object.assign({}, obj1, obj2);
console.log(obj4); // { name: "John", age: 25, hobbies: ["reading", "gaming", "coding"] }

// Using spread and rest operators
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// Copying an array
const arr3 = [...arr1];
console.log(arr3); // [1, 2, 3]

// Merging two arrays
const arr4 = [...arr1, ...arr2];
console.log(arr4); // [1, 2, 3, 4, 5, 6]

// Splitting an array
const [first, second, third] = arr1;
console.log(first); // 1
console.log(second); // 2
console.log(third); // 3

const [head,...tail] = arr4;
console.log(head); // 1
console.log(tail); // [2 ,3 ,4 ,5 ,6]

const obj1 = { name: "John", age: 25 };
const obj2 = { hobbies: ["reading", "gaming", "coding"] };

// Copying an object
const obj3 = {...obj1};
console.log(obj3); // { name: "John", age: 25 }

// Merging two objects
const obj4 = {...obj1,...obj2};
console.log(obj4); // { name: "John", age: 25,hobbies: ["reading", "gaming", "coding"] }
As you can see, using the spread and rest operators can make your code more readable flexibility and immutability. It can also help you avoid some of the errors and bugs that can occur with regular methods. For example, the spread operator can handle nested or complex arrays or objects without causing syntax errors. The rest operator can handle missing or undefined values without causing reference errors.

Therefore, you should always use the spread and rest operators instead of regular methods when manipulating arrays or objects in JavaScript.

Tip 6: Use async/await for handling asynchronous operations
Another common and important feature of JavaScript is the ability to handle asynchronous operations. Asynchronous operations are tasks or functions that can run in the background without blocking the main thread of execution. Asynchronous operations can be used to perform tasks such as fetching data from a server, reading or writing files, setting timers, etc. However, asynchronous operations can also be challenging and complex to handle, especially when dealing with callbacks, promises or errors.

To simplify and improve the handling of asynchronous operations, ES8 introduced async/await. Async/await is a new way to write asynchronous code in JavaScript that uses the async and await keywords. The async keyword allows defining an asynchronous function that returns a promise. The await keyword allows pausing the execution of an asynchronous function until a promise is resolved or rejected.

Here is an example of using async/await to handle asynchronous operations with ease:

// Using callbacks
function fetchData(url, callback) {
  // Simulate fetching data from a server
  setTimeout(() => {
    const data = "Some data from " + url;
    callback(null, data);
  }, 1000);
}

function processData(data, callback) {
  // Simulate processing data
  setTimeout(() => {
    const result = "Processed " + data;
    callback(null, result);
  }, 1000);
}

function displayData(data, callback) {
  // Simulate displaying data
  setTimeout(() => {
    console.log(data);
    callback(null, "Done");
  }, 1000);
}

// Using nested callbacks to handle asynchronous operations
fetchData("https://example.com", (err1, data1) => {
  if (err1) {
    console.error(err1);
  } else {
    processData(data1, (err2, data2) => {
      if (err2) {
        console.error(err2);
      } else {
        displayData(data2, (err3, data3) => {
          if (err3) {
            console.error(err3);
          } else {
            console.log(data3); // Done
          }
        });
      }
    });
  }
});

// Using async/await
async function fetchData(url) {
  // Simulate fetching data from a server
  return new Promise(resolve => {
    setTimeout(() => {
      const data = "Some data from " + url;
      resolve(data);
    }, 1000);
  });
}

async function processData(data) {
  // Simulate processing data
  return new Promise(resolve => {
    setTimeout(() => {
      const result = "Processed " + data;
      resolve(result);
    }, 1000);
  });
}

async function displayData(data) {
  // Simulate displaying data
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(data);
      resolve("Done");
    }, 1000);
  });
}

// Using async/await to handle asynchronous operations
async function main() {
  try {
    const data1 = await fetchData("https://example.com");
    const data2 = await processData(data1);
    const data3 = await displayData(data2);
    console.log(data3); // Done
  } catch (error) {
    console.error(error);
  }
}

main();
As you can see, using async/await can make your code more readable error handling and simplicity. It can also help you avoid some of the pitfalls and confusion that can occur with callbacks or promises. For example, async/await can handle nested or sequential asynchronous operations without causing callback hell or promise chaining. Async/await can also handle errors or rejections using the try/catch blocks or the .catch() method.

Therefore, you should always use async/await instead of callbacks or promises when handling asynchronous operations in JavaScript.

Tip 7: Use modules for organizing and reusing code
Another common and important feature of JavaScript is the ability to organize and reuse code. Code organization and reuse can help you write code that is more readable, maintainable and modular. However, code organization and reuse can also be difficult and tedious to achieve, especially when dealing with multiple files or dependencies.

To simplify and improve the organization and reuse of code, ES6 introduced modules. Modules are a new way to write code in JavaScript that use the import and export keywords. Modules allow dividing code into separate files that can be imported and exported as needed. Modules can also use the default or named syntax to specify what values or features are exported or imported.

Here is an example of using modules to organize and reuse code with ease:

// math.js file
// Exporting a default value
export default function add(a, b) {
  return a + b;
}

// Exporting named values
export function subtract(a, b) {
  return a - b;
}

export function multiply(a, b) {
  return a * b;
}

export function divide(a, b) {
  return a / b;
}

// app.js file
// Importing a default value
import add from "./math.js";

console.log(add(2, 3)); // 5

// Importing named values
import { subtract, multiply, divide } from "./math.js";

console.log(subtract(5, 2)); // 3
console.log(multiply(2, 3)); // 6
console.log(divide(6, 2)); // 3

// Importing all values as an object
import * as math from "./math.js";

console.log(math.add(2, 3)); // 5
console.log(math.subtract(5, 2)); // 3
console.log(math.multiply(2, 3)); // 6
console.log(math.divide(6, 2)); // 3
As you can see, using modules can make your code more readable maintainability and modularity. It can also help you avoid some of the errors and bugs that can occur with regular scripts or dependencies. For example, modules can handle scope or naming conflicts without causing syntax errors. Modules can also handle loading or caching issues without causing performance or memory issues.

Therefore, you should always use modules instead of regular scripts or dependencies when organizing and reusing code in JavaScript.

Tip 8: Use classes for creating objects with shared properties and methods
Another common and useful data type in JavaScript is objects. Objects are collections of values that can be used to store and manipulate data, such as properties, methods, etc. However, objects can also be complex and cumbersome to create and use, especially when you need to create multiple objects with a common structure and behavior.

To simplify and improve the creation and use of objects, ES6 introduced classes. Classes are a new way to write objects in JavaScript that use the class keyword. Classes allow defining a constructor, properties and methods for an object. Classes can also use the extends or super keywords to implement inheritance or polymorphism.

Here is an example of using classes to create objects with shared properties and methods with ease:

// Using regular objects
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function () {
  console.log("Hello, I am " + this.name + " and I am " + this.age + " years old.");
};

function Student(name, age, course) {
  Person.call(this, name, age);
  this.course = course;
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.study = function () {
  console.log("I am studying " + this.course + ".");
};

var john = new Person("John", 25);
var jane = new Student("Jane", 22, "Computer Science");

john.greet(); // Hello, I am John and I am 25 years old.
jane.greet(); // Hello, I am Jane and I am 22 years old.
jane.study(); // I am studying Computer Science.

// Using classes
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, I am ${this.name} and I am ${this.age} years old.`);
  }
}

class Student extends Person {
  constructor(name, age, course) {
    super(name, age);
    this.course = course;
  }

  study() {
    console.log(`I am studying ${this.course}.`);
  }
}

const john = new Person("John", 25);
const jane = new Student("Jane", 22, "Computer Science");

john.greet(); // Hello, I am John and I am 25 years old.
jane.greet(); // Hello, I am Jane and I am 22 years old.
jane.study(); // I am studying Computer Science.
As you can see, using classes can make your code more readable encapsulation and inheritance. It can also help you avoid some of the errors and bugs that can occur with regular objects. For example, classes can handle constructor or prototype issues without causing syntax errors. Classes can also handle inheritance or polymorphism issues without causing reference errors.

Therefore, you should always use classes instead of regular objects when creating objects with shared properties and methods in JavaScript.

Tip 9: Use promises for handling asynchronous operations
Another common and important feature of JavaScript is the ability to handle asynchronous operations. Asynchronous operations are tasks or functions that can run in the background without blocking the main thread of execution. Asynchronous operations can be used to perform tasks such as fetching data from a server, reading or writing files, setting timers, etc. However, asynchronous operations can also be challenging and complex to handle, especially when dealing with callbacks or errors.

To simplify and improve the handling of asynchronous operations, ES6 introduced promises. Promises are a new way to write asynchronous code in JavaScript that use the Promise object. Promises represent the eventual completion or failure of an asynchronous operation. Promises can also use the then or catch methods to handle the resolution or rejection of an asynchronous operation.

Here is an example of using promises to handle asynchronous operations with ease:

// Using callbacks
function fetchData(url, callback) {
  // Simulate fetching data from a server
  setTimeout(() => {
    const data = "Some data from " + url;
    callback(null, data);
  }, 1000);
}

function processData(data, callback) {
  // Simulate processing data
  setTimeout(() => {
    const result = "Processed " + data;
    callback(null, result);
  }, 1000);
}

function displayData(data, callback) {
  // Simulate displaying data
  setTimeout(() => {
    console.log(data);
    callback(null, "Done");
  }, 1000);
}

// Using nested callbacks to handle asynchronous operations
fetchData("https://example.com", (err1, data1) => {
  if (err1) {
    console.error(err1);
  } else {
    processData(data1, (err2, data2) => {
      if (err2) {
        console.error(err2);
      } else {
        displayData(data2, (err3, data3) => {
          if (err3) {
            console.error(err3);
          } else {
            console.log(data3); // Done
          }
        });
      }
    });
  }
});

// Using promises
function fetchData(url) {
  // Simulate fetching data from a server
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const data = "Some data from " + url;
      resolve(data);
    }, 1000);
  });
}

function processData(data) {
  // Simulate processing data
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const result = "Processed " + data;
      resolve(result);
    }, 1000);
  });
}

function displayData(data) {
  // Simulate displaying data
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(data);
      resolve("Done");
    }, 1000);
  });
}

// Using promises to handle asynchronous operations
fetchData("https://example.com")
  .then(data1 => processData(data1))
  .then(data2 => displayData(data2))
  .then(data3 => console.log(data3)) // Done
  .catch(error => console.error(error));
As you can see, using promises can make your code more readable error handling and simplicity. It can also help you avoid some of the pitfalls and confusion that can occur with callbacks or errors. For example, promises can handle nested or sequential asynchronous operations without causing callback hell or pyramid of doom. Promises can also handle errors or rejections using the catch method or the reject function.

Therefore, you should always use promises instead of callbacks or errors when handling asynchronous operations in JavaScript.

Tip 10: Use console methods for debugging and testing code
Another common and important feature of JavaScript is the ability to debug and test code. Debugging and testing code can help you find and fix errors or bugs in your code, as well as improve its performance or functionality. However, debugging and testing code can also be difficult and tedious to do, especially when dealing with complex or large code.

To simplify and improve the debugging and testing of code, JavaScript provides various console methods. Console methods are built-in functions that can be used to log, inspect or test values in the browser console. Console methods can also use various parameters or options to customize the output or behavior of the console.

Here is an example of using console methods to debug and test code with ease:

// Using console.log
console.log("Hello, world!"); // Hello, world!
console.log(2 + 3); // 5
console.log({ name: "John", age: 25 }); // { name: "John", age: 25 }

// Using console.table
console.table(["apple", "banana", "orange"]); // Displays a table with index and value columns
console.table({ name: "John", age: 25 }); // Displays a table with key and value columns

// Using console.assert
console.assert(2 > 3, "2 is not greater than 3"); // Assertion failed: 2 is not greater than 3
console.assert(3 > 2, "3 is greater than 2"); // No output

// Using console.time and console.timeEnd
console.time("Loop"); // Starts a timer with the label Loop
for (let i = 0; i < 1000000; i++) {
  // Do something
}
console.timeEnd("Loop"); // Ends the timer and logs the elapsed time
// Loop: 3.456 ms

// Using console.group and console.groupEnd
console.group("Animals"); // Starts a group with the label Animals
console.log("Cat");
console.log("Dog");
console.log("Bird");
console.groupEnd(); // Ends the group
// Animals:
//   Cat
//   Dog
//   Bird
As you can see, using console methods can make your code more readable performance and troubleshooting. It can also help you avoid some of the errors and bugs that can occur with regular logging or testing. For example, console methods can handle different data types or values without causing syntax errors. Console methods can also handle formatting or grouping issues without causing display issues.

Therefore, you should always use console methods instead of regular logging or testing when debugging and testing code in JavaScript.

반응형
반응형

 

[javascript]  마우스 우클릭 금지

 

1. <head></head> 사이에 script 코드를 삽입.
<script type="text/javascript">
document.oncontextmenu = function(){return false;}
</script>
 

2. <body> 아래에 html 코드를 삽입.
<body oncontextmenu="return false" onselectstart="return false" ondragstart="return false" onkeydown="return false">
 

3. 명칭
oncontextmenu = "return false" : 우클릭 방지
onseletstart = "return false" : 마우스 드래그 방지
ondragstart =  "return false" : 이미지 복사 드래그 방지
onkeydown = "return false" : 키보드 단축키 복사 방지

반응형
반응형

setInterval()

setInterval(code)
setInterval(code, delay)

setInterval(func)
setInterval(func, delay)
setInterval(func, delay, arg0)
setInterval(func, delay, arg0, arg1)
setInterval(func, delay, arg0, arg1, /* … ,*/ argN)


Window 및 Worker 인터페이스에서 제공되는 setInterval() 메서드는 각 호출 사이에 고정된 시간 지연으로 함수를 반복적으로 호출하거나 코드 스니펫을 실행합니다.

이 메서드는 간격(interval)을 고유하게 식별할 수 있는 interval ID를 반환하므로 나중에 clearInterval() (en-US) 함수를 호출하여 제거할 수 있습니다.

myArray = ["zero", "one", "two"];

myArray.myMethod = function (sProperty) {
  alert(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // "zero,one,two"가 출력됩니다
myArray.myMethod(1); // "one"가 출력됩니다
setTimeout(myArray.myMethod, 1000); // 1초 후 "[object Window]"가 출력됩니다
setTimeout(myArray.myMethod, 1500, "1"); // 1,5초 후에 "undefined"가 출력됩니다

// myArray.myMethod 내에서 this의 값을 변경하려는 동안
// setTimeout 내부에서 this의 값을 변경하기 때문에
// .call과 함께 'this'객체를 전달하는 것은 동작하지 않습니다
// 사실 setTimeout 코드는 this가 window 객체가 될 것으로 예상하기 때문에 오류가 발생합니다
setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // 위와 동일한 에러가 발생합니다
반응형
반응형

모던 JavaScript 튜토리얼

https://ko.javascript.info/

 

모던 JavaScript 튜토리얼

 

ko.javascript.info

반응형
반응형

코딩 스타일

https://ko.javascript.info/coding-style

 

코딩 스타일

 

ko.javascript.info

이제, 각 규칙과 규칙이 생긴 이유에 대해 자세히 알아봅시다.

‘무조건’ 따라야 할 규칙은 없습니다.

본 튜토리얼에서 제안하고 있는 규칙 모두를 종교 신조마냥 무조건 따르지 않아도 됩니다. 스타일에 대한 선호에 따라 규칙을 따를 수도, 따르지 않을 수도 있습니다.

중괄호

대부분의 자바스크립트 프로젝트에서 여는 중괄호는 ‘이집션(Egyptian)’ 스타일을 따라 새로운 줄이 아닌 상응하는 키워드와 같은 줄에 작성합니다. 여기에 더하여 여는 중괄호 앞엔 공백이 하나 있어야 합니다. 아래와 같이 말이죠.

if (condition) {
  // 코드 1
  // 코드 2
  // ...코드 n...
}

if (condition) doSomething()과 같은 단 한 줄짜리 구문은 중요하게 다뤄야 할 에지 케이스입니다. 이런 예외상황에도 중괄호를 써야 할까요?

어떻게 코드를 작성해야 가독성이 좋을지 직접 판단해 보시라고 주석과 함께 몇 가지 예시를 만들어보았습니다.

  1. 😠 초보 개발자들은 아래처럼 코드를 작성하곤 하는데, 중괄호가 필요하지 않기 때문에 추천하지 않습니다.
    if (n < 0) {alert(`Power ${n} is not supported`);}
  2. 😠 중괄호 없이 새로운 줄에 코드를 작성할 수도 있는데, 이렇게 하면 새로운 코드 라인을 추가할 때 에러가 발생합니다. 절대 이 방법은 쓰지 마세요.
    if (n < 0)
      alert(`Power ${n} is not supported`);
  3. 😏 코드가 짧다면 중괄호 없이 한 줄에 쓰는 방법도 괜찮습니다.
    if (n < 0) alert(`Power ${n} is not supported`);
  4. 😃 가장 추천하는 방법은 다음과 같습니다.
    if (n < 0) {
      alert(`Power ${n} is not supported`);
    }

if (cond) return null처럼 코드가 간단하다면 세 번째 예시같이 한 줄에 몰아서 작성해도 괜찮습니다. 그렇지만 네 번째 예시처럼 코드 블록을 사용하는 방법이 가장 가독성이 좋으므로 이 방법을 추천합니다.

가로 길이

가로로 길게 늘어진 코드를 읽는 걸 좋아하는 개발자는 없습니다. 코드의 가로 길이가 길어진다면 여러 줄로 나눠 작성하는 게 좋습니다.

예시:

// 백틱(`)을 사용하면 문자열을 여러 줄로 쉽게 나눌 수 있습니다.
let str = `
  ECMA International's TC39 is a group of JavaScript developers,
  implementers, academics, and more, collaborating with the community
  to maintain and evolve the definition of JavaScript.
`;

if문이라면 아래와 같이 작성할 수 있을겁니다.

if (
  id === 123 &&
  moonPhase === 'Waning Gibbous' &&
  zodiacSign === 'Libra'
) {
  letTheSorceryBegin();
}

최대 가로 길이는 팀원들과 합의해 정하는게 좋습니다. 대개 80자나 120자로 제한하는 게 일반적입니다.

들여쓰기

들여쓰기에는 두 종류가 있습니다.

  • 가로 들여쓰기: 스페이스 두 개 혹은 네 개를 사용해 만듦탭 대신 스페이스를 이용했을 때의 장점 중 하나는 들여쓰기 정도를 좀 더 유연하게 변경할 수 있다는 점입니다.
    show(parameters,
         aligned, // 스페이스 다섯 개를 이용해 들여쓰기 함
         one,
         after,
         another
      ) {
      // ...
    }
  • 아래 예시처럼 인수 모두의 위치를 여는 괄호와 맞출 수 있죠.
  • 가로 들여쓰기는 스페이스 두 개 혹은 네 개를 사용하거나 탭 키(Tab)를 이용해 만들 수 있습니다. 어떤 방법을 쓸지에 대한 논쟁은 오래전부터 있었는데, 요즘엔 탭 대신 스페이스를 이용하는 게 더 우위에 있는 것 같습니다.
  • 세로 들여쓰기: 논리 블록 사이에 넣어 코드를 분리해주는 새 줄
    function pow(x, n) {
      let result = 1;
      //              <--
      for (let i = 0; i < n; i++) {
        result *= x;
      }
      //              <--
      return result;
    }
    이렇게 여분의 줄을 넣어주면 코드의 가독성이 좋아집니다. 읽기 쉬운 코드를 만들려면 세로 들여쓰기 없이 코드를 아홉 줄 이상 연속해서 쓰지 마세요.
  • 함수 하나에 논리 블록 여러 개가 들어갈 수 있습니다. 아래 예시에서 변수 선언, 반복문, 리턴문 사이에 세로 들여쓰기를 해주는 빈 줄을 넣어 코드를 분리해 보았습니다.

세미콜론

자바스크립트 엔진에 의해 무시되더라도 모든 구문의 끝엔 세미콜론을 써주는 것이 좋습니다.

구문 끝에 세미콜론을 적는 게 완전히 선택사항인 언어가 몇몇 있는데 이런 언어들에선 세미콜론을 잘 쓰지 않습니다. 그러나 자바스크립트에선 줄 바꿈이 세미콜론으로 해석되지 않는 몇몇 상황이 있기 때문에 세미콜론을 생략하고 코딩하는 습관을 들이면 에러를 발생시키는 코드를 만들 수 있습니다. 자세한 사례는 코드 구조 챕터에서 살펴보세요.

경험이 많은 자바스크립트 개발자라면 StandardJS에서 제시하는 스타일 가이드처럼 세미콜론 없이 코드를 작성할 수도 있습니다. 초보 개발자라면 에러를 만들 확률을 줄이기 위해서라도 세미콜론을 사용하는 게 좋습니다.

중첩 레벨

가능하면 너무 깊은 중첩문은 사용하지 않도록 합시다.

반복문을 사용할 때 중첩문의 깊이가 깊어지면 continue 지시자를 쓰는 게 좋은 대안이 될 수도 있습니다.

if문으로 조건을 처리하는 예시를 통해 이를 살펴봅시다.

for (let i = 0; i < 10; i++) {
  if (cond) {
    ... // <- 중첩 레벨이 하나 더 늘어났습니다.
  }
}

위 코드는 continue를 써서 아래와 같이 바꿀 수 있습니다.

for (let i = 0; i < 10; i++) {
  if (!cond) continue;
  ...  // <- 추가 중첩 레벨이 추가되지 않습니다.
}

if/else와 return문을 조합하면 위 예시와 유사하게 중첩 레벨을 줄여 코드의 가독성을 높일 수 있습니다.

아래 두 예시는 동일하게 동작합니다.

예시 1:

function pow(x, n) {
  if (n < 0) {
    alert("'n'은 음수가 될 수 없습니다.");
  } else {
    let result = 1;

    for (let i = 0; i < n; i++) {
      result *= x;
    }

    return result;
  }
}

예시 2:

function pow(x, n) {
  if (n < 0) {
    alert("'n'은 음수가 될 수 없습니다.");
    return;
  }

  let result = 1;

  for (let i = 0; i < n; i++) {
    result *= x;
  }

  return result;
}

n < 0인 '특별한 상황’을 앞에 두고, 그 안에 return문을 추가해주었더니 가독성이 훨씬 좋아졌습니다. 특별한 상황인지를 확인하고 조건을 통과하면 추가 중첩 없이 ‘주요’ 코드 흐름으로 넘어가게 코드를 짰기 때문입니다.

함수의 위치

‘헬퍼’ 함수 여러 개를 만들어 사용하고 있다면 아래와 같은 방법을 사용해 코드 구조를 정돈할 수 있습니다.

  1. 헬퍼 함수를 사용하는 코드 위에서 헬퍼 함수를 모아 선언하기
  2. // 함수 선언
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
    
    // 헬퍼 함수를 사용하는 코드
    let elem = createElement();
    setHandler(elem);
    walkAround();
  3. 코드를 먼저, 함수는 그 다음에 선언하기
  4. // 헬퍼 함수를 사용하는 코드
    let elem = createElement();
    setHandler(elem);
    walkAround();
    
    // --- 헬퍼 함수 ---
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
  5. 혼합: 코드 바로 위에서 필요한 헬퍼 함수 그때그때 선언하기

대개는 두 번째 방법으로 코드를 정돈하는 걸 선호합니다.

사람들은 이 코드가 '무엇을 하는지’를 생각하며 코드를 읽기 때문에 코드가 먼저 나오는 것이 자연스럽기 때문입니다. 이름만 보고도 헬퍼 함수의 역할을 쉽게 유추할 수 있게 헬퍼 함수 이름을 명명했다면 함수 본문을 읽을 필요도 없습니다.

스타일 가이드

코딩 스타일 가이드는 코드를 '어떻게 작성할지’에 대한 전반적인 규칙을 담은 문서로, 어떤 따옴표를 쓸지, 들여쓰기할 때 스페이스를 몇 개 사용할지, 최대 가로 길이는 몇까지 제한할지 등의 내용이 담겨있습니다.

팀원 전체가 동일한 스타일 가이드를 따라 코드를 작성하면, 누가 코드를 작성했나에 관계없이 동일한 스타일의 코드를 만들 수 있습니다.

팀원들이 모여 팀 전용 스타일 가이드를 만들 수도 있는데, 요즘엔 이미 작성된 가이드 중 하나를 선택해 팀의 가이드로 삼는 편입니다.

유명 스타일 가이드:

초보 개발자라면 상단 치트 시트를 시작으로 본인만의 스타일을 가이드를 만들어 보시기 바랍니다. 유명 스타일 가이드 등을 살펴보며 아이디어를 얻고, 마음에 드는 규칙은 본인의 스타일 가이드에 반영해 보시기 바랍니다.

Linter

Linter라는 도구를 사용하면 내가 작성한 코드가 스타일 가이드를 준수하고 있는지를 자동으로 확인할 수 있고, 스타일 개선과 관련된 제안도 받을 수 있습니다.

이렇게 자동으로 스타일을 체크받다 보면, 변수나 함수 이름에 난 오타 등이 유발하는 버그를 미리 발견할 수 있어서 좋습니다. 아직 '코드 스타일’을 정하지 않았더라도 linter를 사용하면 버그를 예방할 수 있기 때문에 linter 사용을 권유 드립니다.

유명 linter:

  • JSLint – 역사가 오래된 linter
  • JSHint – JSLint보다 세팅이 좀 더 유연한 linter
  • ESLint – 가장 최근에 나온 linter

위 linter 모두 훌륭한 기능을 제공합니다. 글쓴이는 ESLint를 사용하고 있습니다.

대부분의 linter는 플러그인 형태로 유명 에디터와 통합해 사용할 수 있습니다. 원하는 스타일을 설정하는 것 역시 가능합니다.

ESLint를 사용한다고 가정했을 때 아래 절차를 따르면 에디터와 linter를 통합해 사용할 수 있습니다.

  1. Node.js를 설치합니다.
  2. npm(자바스크립트 패키지 매니저)을 사용해 다음 명령어로 ESLint를 설치합니다. npm install -g eslint
  3. 현재 작성 중인 자바스크립트 프로젝트의 루트 폴더(프로젝트 관련 파일이 담긴 폴더)에 .eslintrc라는 설정 파일을 생성합니다.
  4. 에디터에 ESLint 플러그인을 설치하거나 활성화합니다. 주요 에디터들은 모두 ESLint 플러그인을 지원합니다.

아래는 .eslintrc 파일의 예시입니다.

{
  "extends": "eslint:recommended",
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "rules": {
    "no-console": 0,
    "indent": ["warning", 2]
  }
}

위 예시에서 지시자 "extends"는 "eslint:recommended"를 기반으로 이를 확장해 스타일 가이드를 설정하겠다는 걸 의미합니다. 이렇게 세팅한 이후에 자신만의 스타일을 설정하면 됩니다.

스타일 규칙을 모아놓은 세트를 웹에서 다운로드해 이를 기반으로 스타일 가이드를 설정하는 것도 가능합니다. 설치 방법에 대한 자세한 내용은 http://eslint.org/docs/user-guide/getting-started에서 확인해 보시기 바랍니다.

몇몇 IDE에서는 자체 lint 도구가 있어 편리하긴 하지만 ESLint처럼 쉽게 설정을 변경하는 게 불가능하다는 단점이 있습니다.

요약

이 챕터에서 소개해 드린 문법 규칙과 스타일 가이드 관련 참고자료들은 코드 가독성을 높이기 위해 만들어졌습니다.

‘더 좋은’ 코드를 만들려면 "가독성이 좋고 이해하기 쉬운 코드를 만들려면 무엇을 해야 할까?"라는 질문과 "에러를 피하려면 어떤 일을 해야 할까?"라는 질문을 스스로에게 던져야 합니다. 어떤 코딩 스타일을 따를지 결정할 때와 이에 대한 논쟁을 할 땐 이런 질문을 기반으로 해야 하죠.

유명 스타일 가이드를 읽다 보면 코드 스타일에 관한 경향과 모범 사례에 대한 최신 정보를 유지할 수 있습니다.

과제

중요도: 4

아래 코드가 어떤 점에서 좋지 않은지 생각해보세요.

function pow(x,n)
{
  let result=1;
  for(let i=0;i<n;i++) {result*=x;}
  return result;
}

let x=prompt("x?",''), n=prompt("n?",'')
if (n<=0)
{
  alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
}
else
{
  alert(pow(x,n))
}

더 나은 코드로 고쳐봅시다.

반응형
반응형

nullish 병합 연산자

nullish 병합 연산자(nullish coalescing operator)

 

https://ko.javascript.info/nullish-coalescing-operator#ref-778

 

nullish 병합 연산자 '??'

 

ko.javascript.info

 

nullish 병합 연산자(nullish coalescing operator) ??를 사용하면 짧은 문법으로 여러 피연산자 중 그 값이 ‘확정되어있는’ 변수를 찾을 수 있습니다.

a ?? b의 평가 결과는 다음과 같습니다.

  • a가 null도 아니고 undefined도 아니면 a
  • 그 외의 경우는 b

nullish 병합 연산자 ??없이 x = a ?? b와 동일한 동작을 하는 코드를 작성하면 다음과 같습니다.

x = (a !== null && a !== undefined) ? a : b;

비교 연산자와 논리 연산자만으로 nullish 병합 연산자와 같은 기능을 하는 코드를 작성하니 코드 길이가 길어지네요.

또 다른 예시를 살펴봅시다. firstName, lastName, nickName이란 변수에 사용자 이름이나 별명을 저장하는데, 사용자가 아무런 정보도 입력하지 않는 케이스도 허용한다고 해보겠습니다.

화면엔 세 변수 중 실제 값이 있는 변수의 값을 출력하는데, 세 변수 모두 값이 없다면 '익명의 사용자’가 출력되도록 해보죠.

이럴 때 nullish 병합 연산자 ??를 사용하면 값이 정해진 변수를 간편하게 찾아낼 수 있습니다.

 
 
let firstName = null;
let lastName = null;
let nickName = "바이올렛";

// null이나 undefined가 아닌 첫 번째 피연산자
alert(firstName ?? lastName ?? nickName ?? "익명의 사용자"); // 바이올렛

'??'와 '||'의 차이

nullish 병합 연산자는 OR 연산자 ||와 상당히 유사해 보입니다. 실제로 위 예시에서 ??를 ||로 바꿔도 그 결과는 동일하기까지 하죠. 관련 내용은 이전 챕터에서 살펴본 바 있습니다.

그런데 두 연산자 사이에는 중요한 차이점이 있습니다.

  • ||는 첫 번째 truthy 값을 반환합니다.
  • ??는 첫 번째 정의된(defined) 값을 반환합니다.

null과 undefined, 숫자 0을 구분 지어 다뤄야 할 때 이 차이점은 매우 중요한 역할을 합니다.

예시를 살펴봅시다.

height = height ?? 100;

height에 값이 정의되지 않은경우 height엔 100이 할당됩니다.

이제 ??와 ||을 비교해봅시다.

 
 
let height = 0;

alert(height || 100); // 100
alert(height ?? 100); // 0

height || 100은 height에 0을 할당했지만 0을 falsy 한 값으로 취급했기 때문에 null이나 undefined를 할당한 것과 동일하게 처리합니다. 따라서 height || 100의 평가 결과는 100입니다.

반면 height ?? 100의 평가 결과는 height가 정확하게 null이나 undefined일 경우에만 100이 됩니다. 예시에선 height에 0이라는 값을 할당했기 때문에 얼럿창엔 0이 출력됩니다.

이런 특징 때문에 높이처럼 0이 할당될 수 있는 변수를 사용해 기능을 개발할 땐 ||보다 ??가 적합합니다.

연산자 우선순위

??의 연산자 우선순위 5로 꽤 낮습니다.

따라서 ??는 =와 ? 보다는 먼저, 대부분의 연산자보다는 나중에 평가됩니다.

그렇기 때문에 복잡한 표현식 안에서 ??를 사용해 값을 하나 선택할 땐 괄호를 추가하는 게 좋습니다.

 
 
let height = null;
let width = null;

// 괄호를 추가!
let area = (height ?? 100) * (width ?? 50);

alert(area); // 5000

그렇지 않으면 *가 ??보다 우선순위가 높기 때문에 *가 먼저 실행됩니다.

결국엔 아래 예시처럼 동작하겠죠.

// 원치 않는 결과
let area = height ?? (100 * width) ?? 50;

??엔 자바스크립트 언어에서 규정한 또 다른 제약사항이 있습니다.

안정성 관련 이슈 때문에 ??는 &&나 ||와 함께 사용하지 못합니다.

아래 예시를 실행하면 문법 에러가 발생합니다.

 
 
let x = 1 && 2 ?? 3; // SyntaxError: Unexpected token '??'

이 제약에 대해선 아직 논쟁이 많긴 하지만 사람들이 ||를 ??로 바꾸기 시작하면서 만드는 실수를 방지하고자 명세서에 제약이 추가된 상황입니다.

제약을 피하려면 괄호를 사용해주세요.

 
 
let x = (1 && 2) ?? 3; // 제대로 동작합니다.

alert(x); // 2

요약

  • nullish 병합 연산자 ??를 사용하면 피연산자 중 ‘값이 할당된’ 변수를 빠르게 찾을 수 있습니다.
    // height가 null이나 undefined인 경우, 100을 할당
    height = height ?? 100;
  • ??는 변수에 기본값을 할당하는 용도로 사용할 수 있습니다.
  • ??의 연산자 우선순위는 대다수의 연산자보다 낮고 ?와 = 보다는 높습니다.
  • 괄호 없이 ??를 ||나 &&와 함께 사용하는 것은 금지되어있습니다.
반응형

+ Recent posts