」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > JavaScript 駭客會讓你說「我這輩子你去哪了?

JavaScript 駭客會讓你說「我這輩子你去哪了?

發佈於2024-08-15
瀏覽:621

JavaScript Hacks That Will Make You Say “Where Have You Been All My Life?

Let’s face it: as developers, we’re always on the lookout for ways to streamline our workflow and shave precious minutes off our coding time.

Who wants to spend hours wrestling with clunky code when there’s a sleek and efficient solution just around the corner?

Today, I’m sharing 10 JavaScript tricks — some built-in, some custom — that will have you wondering how you ever lived without them.

Great! Let’s move on to the first section. We’ll start with a simple, yet incredibly useful JavaScript feature.


1. Optional Chaining: Kiss Those TypeErrors Goodbye!

Problem: You’re trying to access a property deep within an object, but you’re not sure if all the properties in the chain exist. This can lead to those dreaded “Cannot read properties of undefined” errors.

const user = {
   // address: { street: "123 Main St" } 
};

let street = user.address.street; 

console.log(street); // Uncaught TypeError: Cannot read properties of undefined (reading 'street')

Old Painful Solution: You’d have to write a bunch of nested if statements to check if each property exists before trying to access it.

const user = {
    // address: { street: "123 Main St" }
};

// The old, painful way:
let street = user && user.address && user.address.street;

console.log(street); // undefined

New Modern Solution: Optional chaining to the rescue! With ?., the expression short-circuits to undefined if a property is missing, preventing errors.

const user = {
    // address: { street: "123 Main St" }
};

// The elegant, modern way:
let street = user?.address?.street; 

console.log(street); // undefined:

With optional chaining (?.), if any property in the chain is null or undefined, the expression short-circuits and simply returns undefined instead of throwing a dreaded TypeError. No more clunky if statements cluttering up your code!

Real-World Example:

Imagine you’re fetching data from an API, and the response structure might vary. Instead of writing multiple nested checks, optional chaining provides a clean and concise way to access data that may or may not be present.


2. Nullish Coalescing Operator: Default Values Just Got Smarter

Problem: You want to assign a default value to a variable if it’s null or undefined, but you don't want to accidentally override falsy values that might be valid in your code, like 0 or an empty string.

Old Painful Solution: Using the logical OR operator (||) to set defaults could lead to these unintended consequences.

const user = { name: 0 };

// The old way (potentially problematic):
let postCount = user.name || "No posts yet!"; 

console.log(postCount); // Outputs "No posts yet!", even though 0 might be a valid post count.

New Modern Solution: The nullish coalescing operator (??) saves the day! It only provides the default if the left-hand operand is strictly null or undefined.

const user = { name: 0 };

// The new, improved way:
let postCount = user.name ?? "No posts yet!"; 

console.log(postCount); // Outputs 0, respecting the actual value of user.name

Our trusty ?? only steps in if the left-hand operand is null or undefined, ensuring the default is used only when intended.

Real-World Example:

Imagine a user profile where 0 is a valid input for "number of posts." Using || to set a default would incorrectly replace 0 with the default. The ?? operator avoids this pitfall, respecting the true meaning of 0 in this context.


3. Object.freeze(): Make It Immutable!

Problem: You have an object, and you want to make sure that none of its properties can be accidentally changed after it’s created. This is especially important for configuration objects or data that should remain constant.

const colors = {
    primary: "blue",
    secondary: "green"
};

colors.primary = "red"; // Accidental modification is too easy!

console.log(colors.primary); // Outputs "red" - the object was modified

Solution: Object.freeze() makes your object rock-solid! It prevents any further modifications to its properties.

const colors = {
    primary: "blue",
    secondary: "green"
};

Object.freeze(colors);

colors.primary = "red"; // This will silently fail
console.log(colors.primary); // Still outputs "blue"

Object.freeze() takes an object and makes it immutable. Any attempt to change its properties will be silently ignored. It's like putting your object in a display case – you can look, but you can't touch!

Real-World Example:

Imagine you have configuration settings stored in an object. Using Object.freeze() ensures these settings remain constant throughout your application, preventing accidental modifications that could lead to unexpected behavior.


4. Array Destructuring: Unpacking Made Easy

Problem: You need to extract specific values from an array and assign them to individual variables. Traditional array access using indices can feel a bit clunky, especially for longer arrays.

Old Painful Solution: You’d end up accessing elements by their index, which can be less readable and more error-prone, especially as arrays grow larger.

const rgb = [255, 128, 0];

const red = rgb[0];
const green = rgb[1];
const blue = rgb[2]; 

console.log(red, green, blue); // 255 128 0

New Modern Solution: Array destructuring provides an elegant and readable way to “unpack” array elements into distinct variables.

const rgb = [255, 128, 0];

const [red, green, blue] = rgb;

console.log(red, green, blue); // 255 128 0

By using square brackets [] on the left-hand side of an assignment, we create a pattern that mirrors the structure of the array. JavaScript then neatly assigns the corresponding values from the array to the variables.

Real-World Example:

Imagine you have an array representing a user’s information: [name, age, city]. With destructuring, you can easily extract these values into separate variables for more readable and maintainable code.


5. Default Parameters: No More Undefined Headaches

Problem: You’re writing a function, and you want to provide default values for parameters in case the caller doesn’t supply them.

Old Painful Solution: You’d have to check if the arguments were undefined within the function body and assign default values manually.

function greet(name, message) {
    const userName = name || "Stranger"; 
    const greeting = message || "Hello there!";

    console.log(`${greeting}, ${userName}!`);
}

greet(); // Hello there!, Stranger!
greet("Alice"); // Hello there!, Alice!
greet("Bob", "Good morning"); // Good morning, Bob!

New Modern Solution: Default parameters let you specify default values for function parameters directly within the function definition.

By assigning values to parameters in the function signature (name = "Stranger"), we tell JavaScript to use those values if the corresponding arguments are not provided when the function is called.

Real-World Example:

Consider a function that calculates the area of a rectangle. You could set default values for width and height to 1, so if the function is called without arguments, it returns the area of a unit square.


6. Tagged Template Literals: Supercharge Your Strings

Problem: You want to create more powerful and flexible string formatting capabilities beyond what’s offered by basic template literals. You might need custom parsing, escaping, or data transformations within your string construction.

Old Painful Solution: You’d rely on a combination of string concatenation, helper functions, and potentially complex logic to achieve the desired results.

function highlight(text, name) {
    // Find the index of the placeholder within the text
    const placeholderIndex = text.indexOf("%name%"); 

    if (placeholderIndex !== -1) {
        // Replace the placeholder with the actual name
        return text.substring(0, placeholderIndex)   name   text.substring(placeholderIndex   6);
      } else {
        return text;
    }
}

const name = "Alice";
const message = highlight("Welcome, %name%!", name);

console.log(message); // "Welcome, Alice!"

New Modern Solution: Tagged template literals allow you to define custom functions (called “tag functions”) that can process template literal strings before they’re interpolated.

function highlight(strings, ...values) {
    let result = '';
    for (let i = 0; i ${values[i]}`;
        }
    }
    return result;
}

const name = "Alice";
const message = highlight`Welcome, ${name}!`;

console.log(message); // "Welcome, Alice!"
  • Old Solution: We relied on a separate function (highlight) that took the text and the value to be inserted as separate arguments. We manually searched for a placeholder (%name%) and replaced it. This approach is less flexible, more error-prone (what if the placeholder is wrong?), and doesn't scale well for more complex formatting.

  • New Solution: With tagged template literals, the highlight function receives the string parts and the interpolated values as separate arguments. This allows for much cleaner manipulation and transformation of the string based on its structure and the provided values.

Real-World Example:

  • Creating Domain-Specific Languages (DSLs): Build custom templating engines, query builders, or even mini-languages within your JavaScript code.

  • Internationalization (i18n): Handle translations and localized string formatting based on user preferences.

  • Security: Implement robust sanitization and escaping mechanisms for user-generated content within strings.


7. Proxy Objects: Intercept and Control

Problem: You need fine-grained control over object operations, such as property access, assignment, function calls, or even object construction. You might want to implement custom validation, logging, or even modify the behavior of existing objects without directly changing their code.

Old Painful Solution: You’d often resort to:

  • Wrapper Functions: Creating functions that encapsulate object interactions, adding overhead and potentially obscuring the underlying object’s interface.

  • Overriding Methods: Modifying object prototypes, which can lead to unexpected side effects and conflicts, especially in larger codebases.

const user = {
    name: "Alice",
    age: 30,
};

function validateAge(age) {
    if (age  120) {
        throw new Error("Invalid age value!");
    }
      return age;
}

// Using a wrapper function to enforce validation
function setUserAge(user, newAge) {
    user.age = validateAge(newAge);
}

setUserAge(user, 35); // Works
setUserAge(user, -5); // Throws an error

New Modern Solution: Proxy objects act as intermediaries, intercepting fundamental operations on an object and giving you the power to customize how those operations are handled.

const user = {
    name: "Alice",
    age: 30,
};

const userProxy = new Proxy(user, {
    set: function (target, property, value) {
        if (property === "age") {
          if (value  120) {
            throw new Error("Invalid age value!");
          }
        }
        // Update the original object's property
        target[property] = value;
        return true; // Indicate success
    },
});

userProxy.age = 35; // Works
userProxy.age = -5; // Throws an error
  • We create a Proxy object, passing in the target object (user) and a handler object.

  • The handler object defines “traps” for various operations. In this case, we use the set trap to intercept property assignments.

  • Inside the set trap, we perform custom validation for the age property.

  • If the validation passes, we update the original object’s property using target[property] = value.

Real-World Example:

  • Data Validation and Sanitization: Enforce data integrity rules before saving objects to a database or sending them over a network.

  • Change Tracking: Log or react to changes made to an object’s properties.

  • Lazy Loading: Defer loading expensive object properties until they are actually accessed.


8. The Power of reduce(): Beyond Simple Array Summation

Problem: You need to perform sophisticated transformations or calculations on arrays, going beyond simple aggregation like finding the sum or maximum value.

Old Painful Solution: You might resort to:

  • Imperative Loops: Writing verbose for or while loops, often with nested logic and temporary variables, making the code harder to read and maintain.

  • Specialized Functions: Creating separate functions for each specific array transformation, leading to code duplication.

const orders = [
    { product: "Shirt", quantity: 2, price: 15 },
    { product: "Shoes", quantity: 1, price: 50 },
    { product: "Hat", quantity: 3, price: 10 },
];

// Calculate the total value of all orders (imperative approach)
let totalValue = 0;
for (let i = 0; i 



New Modern Solution: The reduce() method provides a versatile way to iterate over an array and "reduce" it to a single value, applying a callback function to each element and accumulating a result.

const orders = [
    { product: "Shirt", quantity: 2, price: 15 },
    { product: "Shoes", quantity: 1, price: 50 },
    { product: "Hat", quantity: 3, price: 10 },
];

// Calculate the total value of all orders using reduce
const totalValue = orders.reduce((accumulator, order) => {
    return accumulator   order.quantity * order.price;
}, 0); // Initial value of the accumulator

console.log(totalValue); // Output: 110
  • reduce() takes two arguments: a callback function and an optional initial value for the accumulator.

  • The callback function receives the accumulator (which starts with the initial value or the first element) and the current element.

  • In each iteration, the callback returns the updated accumulator, which is then passed to the next iteration.

  • The final value returned by reduce() is the accumulated result.

Real-World Example:

  • Data Grouping: Transform an array of objects into a grouped object based on a specific property.
const products = [
    { name: "Apple", category: "Fruit" },
    { name: "Banana", category: "Fruit" },
    { name: "Carrot", category: "Vegetable" },
];

const groupedProducts = products.reduce((groups, product) => {
    const category = product.category;
    if (!groups[category]) {
        groups[category] = [];
    }
    groups[category].push(product);
    return groups;
}, {});

console.log(groupedProducts); 
// Output: { Fruit: [{...}, {...}], Vegetable: [{...}] }
  • Flattening Arrays: Merge nested arrays into a single flat array.
const nestedArray = [1, [2, 3], [4, [5, 6]]];

const flatArray = nestedArray.reduce(
     (acc, current) => acc.concat(Array.isArray(current) ? current.flat() : current),[]);

console.log(flatArray); // Output: [1, 2, 3, 4, 5, 6]
  • Creating Unique Lists: Extract unique values from an array.
const numbers = [1, 2, 2, 3, 4, 4, 5];

const uniqueNumbers = numbers.reduce((unique, number) => {
      return unique.includes(number) ? unique : [...unique, number];
}, []);

console.log(uniqueNumbers); // Output: [1, 2, 3, 4, 5]

Mastering reduce() unlocks a higher level of array manipulation, allowing you to express complex transformations concisely and elegantly.


9. Spread Syntax for Easy Array and Object Manipulation

Problem: You need to copy arrays, combine them, or insert elements at specific positions. Similarly, you might want to create copies of objects with modified properties. Doing this manually can be tedious and involve loops or multiple lines of code.

Old Painful Solution: You’d use combinations of slice(), concat(), or Object.assign() for these tasks:

Arrays:

const numbers1 = [1, 2, 3];
const numbers2 = [4, 5, 6];

// Concatenating arrays
const combinedArray = numbers1.concat(numbers2); 

// Inserting the number 0 at index 2 (the old way)
const newArray = numbers1.slice(0, 2).concat([0], numbers1.slice(2));

Objects:

const product = {
    name: "Phone",
    price: 499,
};

// Creating a modified copy
const updatedProduct = Object.assign({}, product, { price: 599 });

New Modern Solution: The spread syntax (...) provides a more concise and flexible way to work with arrays and objects:

Arrays:

const numbers1 = [1, 2, 3];
const numbers2 = [4, 5, 6];

// Concatenating arrays
const combinedArray = [...numbers1, ...numbers2];

// Inserting an element
const newArray = [...numbers1.slice(0, 2), 0, ...numbers1.slice(2)];

Objects:

const product = {
     name: "Phone",
     price: 499,
};

// Creating a modified copy
const updatedProduct = { ...product, price: 599 };
  • Spread Syntax with Arrays: When used with arrays, ... expands the elements of an array in place.

  • Spread Syntax with Objects: When used with objects, ... expands the key-value pairs of an object.

Why It’s Easier:

  • Conciseness: Spread syntax significantly reduces the code required for common array and object operations.

  • Readability: The code becomes more declarative and easier to understand.

Real-World Example:

  • Modifying State in React: Spread syntax is widely used in React and other UI libraries to create updated copies of state objects without mutating the original state:
// Example in a React component
this.setState(prevState => ({
    ...prevState,
    cartItems: [...prevState.cartItems, newItem], 
}));

Spread syntax is a versatile tool that simplifies array and object manipulation, making your code more concise, readable, and maintainable.


10. Arrow Functions: A Concise Syntax for Functions

Problem: You often need to write short, anonymous functions for event handlers, callbacks, or array methods, but the traditional function syntax can feel a bit verbose in these cases.

Old Painful Solution: You’d use the function keyword to define anonymous functions:

// Example with an array method
const numbers = [1, 2, 3, 4, 5];

const doubledNumbers = numbers.map(function(number) {
    return number * 2;
});

console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]

New Modern Solution: Arrow functions (=>) provide a more compact syntax for writing functions, especially for short function bodies:

const numbers = [1, 2, 3, 4, 5];

const doubledNumbers = numbers.map((number) => number * 2);

console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]
  • Syntax: An arrow function is defined with parentheses for parameters (or a single parameter without parentheses), followed by the arrow (=>), and then the function body.

  • Implicit Return: If the function body contains a single expression, the result of that expression is implicitly returned without needing the return keyword.

  • Lexical this Binding: Arrow functions don't have their own this binding. They inherit this from the surrounding scope, which can be very useful in certain situations (we'll explore this in a later example).

Why It’s Easier:

  • Shorter Syntax: Arrow functions significantly reduce the code required to define simple functions.

  • Improved Readability: The code becomes more concise and easier to follow, especially when used with array methods.

Real-World Example:

  • Event Handlers: Arrow functions are very common when attaching event listeners:
const button = document.getElementById("myButton");

button.addEventListener("click", () => {
    console.log("Button clicked!"); 
});

Ready for More? ?

  • This is just the beginning! The world of JavaScript is vast. ?

  • Keep experimenting, keep learning, and never be afraid to break things (in a safe coding environment, of course! ?).

  • Want to stay connected? Follow me on Instagram @codingwithjd for more coding tips, tricks, and even some bad programming jokes. ?

版本聲明 本文轉載於:https://dev.to/jaimaldullat/10-javascript-hacks-that-will-make-you-say-where-have-you-been-all-my-life-22bn?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 為什麼填入在 Safari 和 IE 選擇清單中不起作用?
    為什麼填入在 Safari 和 IE 選擇清單中不起作用?
    在Safari 和IE 的選擇清單中不顯示填充儘管W3 規範中沒有限制,但WebKit 瀏覽器不支援選擇框中的填充,包括Safari和Chrome。因此,這些瀏覽器中不應用填充。 要解決此問題,請考慮使用 text-indent 而不是 padding-left。透過相應增加選擇框的寬度來保持相同的...
    程式設計 發佈於2024-11-05
  • 在 Spring Boot 中建立自訂註解的終極指南
    在 Spring Boot 中建立自訂註解的終極指南
    Such annotations fill the entire project in Spring Boot. But do you know what problems these annotations solve? Why were custom annotations introduce...
    程式設計 發佈於2024-11-05
  • 為什麼 Elixir 在非同步處理方面比 Node.js 更好?
    為什麼 Elixir 在非同步處理方面比 Node.js 更好?
    简单回答:Node.js 是单线程的,并拆分该单线程来模拟并发,而 Elixir 利用了 Erlang 虚拟机 BEAM 原生的并发和并行性,同时执行进程。 下面,我们将更深入地了解这种差异,探索两个关键概念:Node.js 事件循环和 Elixir 的 BEAM VM 和 OTP。这些元素对于理解...
    程式設計 發佈於2024-11-05
  • AngularJS $watch 如何取代動態導航高度調整中的計時器?
    AngularJS $watch 如何取代動態導航高度調整中的計時器?
    避免 AngularJS 的高度監視計時器當導航高度是動態時,AngularJS 程式設計師經常面臨響應式導航的挑戰。這就導致需要調整內容的 margin-top 值以回應導航高度的變化。 以前,使用計時器來偵測導航高度的變化,但這種方法有缺點:使用計時器和調整內容的 margin-top 出現延遲...
    程式設計 發佈於2024-11-05
  • 從零到 Web 開發人員:掌握 PHP 基礎知識
    從零到 Web 開發人員:掌握 PHP 基礎知識
    掌握PHP基礎至關重要:安裝PHP建立PHP檔案運行程式碼理解變數和資料類型使用表達式和運算子建立實際專案以提高技能 PHP開發入門:掌握PHP基礎PHP是一種用途廣泛、功能強大的腳本語言,用於創建動態且互動式Web應用程式。對於初學者來說,掌握PHP的基本知識至關重要。 一、安裝PHP在本地開發機...
    程式設計 發佈於2024-11-05
  • 緩衝區:Node.js
    緩衝區:Node.js
    Node.js 中緩衝區的簡單指南 Node.js 中的 Buffer 用於處理原始二進位數據,這在處理流、文件或網路數據時非常有用。 如何建立緩衝區 來自字串: const buf = Buffer.from('Hello'); 分配特定大小的Buffer...
    程式設計 發佈於2024-11-05
  • 掌握 Node.js 中的版本管理
    掌握 Node.js 中的版本管理
    作為開發者,我們經常遇到需要不同 Node.js 版本的專案。對於可能不經常參與 Node.js 專案的新手和經驗豐富的開發人員來說,這種情況都是一個陷阱:確保每個專案使用正確的 Node.js 版本。 在安裝依賴項並執行專案之前,驗證您的 Node.js 版本是否符合或至少相容專案的要求至關重要...
    程式設計 發佈於2024-11-05
  • 如何在 Go 二進位檔案中嵌入 Git 修訂資訊以進行故障排除?
    如何在 Go 二進位檔案中嵌入 Git 修訂資訊以進行故障排除?
    確定Go 二進位檔案中的Git 修訂版部署程式碼時,將二進位檔案與建置它們的git 修訂版關聯起來會很有幫助排除故障的目的。然而,直接使用修訂號更新原始程式碼是不可行的,因為它會改變原始程式碼。 解決方案:利用建造標誌解決此挑戰的方法包括利用建造標誌。透過使用建置標誌在主套件中設定當前 git 修訂...
    程式設計 發佈於2024-11-05
  • 常見 HTML 標籤:視角
    常見 HTML 標籤:視角
    HTML(超文本標記語言)構成了 Web 開發的基礎,是互聯網上每個網頁的結構。透過了解最常見的 HTML 標籤及其高級用途,到 2024 年,開發人員可以創建更有效率、更易於存取且更具視覺吸引力的網頁。在這篇文章中,我們將探討這些 HTML 標籤及其最高級的用例,以協助您提升 Web 開發技能。 ...
    程式設計 發佈於2024-11-05
  • CSS 媒體查詢
    CSS 媒體查詢
    確保網站在各種裝置上無縫運作比以往任何時候都更加重要。隨著用戶透過桌上型電腦、筆記型電腦、平板電腦和智慧型手機造訪網站,響應式設計已成為必要。響應式設計的核心在於媒體查詢,這是一項強大的 CSS 功能,可讓開發人員根據使用者裝置的特徵應用不同的樣式。在本文中,我們將探討什麼是媒體查詢、它們如何運作以...
    程式設計 發佈於2024-11-05
  • 了解 JavaScript 中的提升:綜合指南
    了解 JavaScript 中的提升:綜合指南
    JavaScript 中的提升 提升是一種行為,其中變數和函數聲明在先前被移動(或「提升」)到其包含範圍(全域範圍或函數範圍)的頂部程式碼被執行。這意味著您可以在程式碼中實際聲明變數和函數之前使用它們。 變數提升 變數 用 var 宣告的變數被提升...
    程式設計 發佈於2024-11-05
  • 將 Stripe 整合到單一產品 Django Python 商店中
    將 Stripe 整合到單一產品 Django Python 商店中
    In the first part of this series, we created a Django online shop with htmx. In this second part, we'll handle orders using Stripe. What We'll...
    程式設計 發佈於2024-11-05
  • 在 Laravel 測試排隊作業的技巧
    在 Laravel 測試排隊作業的技巧
    使用 Laravel 應用程式時,經常會遇到命令需要執行昂貴任務的情況。為了避免阻塞主進程,您可能決定將任務卸載到可以由佇列處理的作業。 讓我們來看一個例子。想像一下指令 app:import-users 需要讀取一個大的 CSV 檔案並為每個條目建立一個使用者。該命令可能如下所示: /* Imp...
    程式設計 發佈於2024-11-05
  • 如何創建人類層級的自然語言理解 (NLU) 系統
    如何創建人類層級的自然語言理解 (NLU) 系統
    Scope: Creating an NLU system that fully understands and processes human languages in a wide range of contexts, from conversations to literature. ...
    程式設計 發佈於2024-11-05
  • 如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    使用JSTL 迭代HashMap 中的ArrayList在Web 開發中,JSTL(JavaServer Pages 標準標記庫)提供了一組標記來簡化JSP 中的常見任務( Java 伺服器頁面)。其中一項任務是迭代資料結構。 要迭代 HashMap 及其中包含的 ArrayList,可以使用 JS...
    程式設計 發佈於2024-11-05

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3