Back to Blog
By AriesZhou · · 6 min read

JavaScript Fundamentals

js

Have you ever seen code like this? Inside a setTimeout callback, you want to access the outer this, only to find it has become undefined. Or when working with arrays, you write a pile of for loops and later realize it could be done with one line of map. These problems all point to the most basic and core concepts of JavaScript.

This article records the concepts I find important while using and learning JavaScript: arrow functions, higher-order functions, prototype chains, code splitting, and templates. These concepts matter for both beginners and developers who want to strengthen their foundations.


1. Arrow functions: behind the concise syntax

The arrow functions introduced in ES6 are not just syntactic sugar. They resolve the long-standing confusion around this binding in JavaScript.

1.1 Basic syntax

const add = (a, b) => {
  return a + b;
};

// 隐式返回 - 省略花括号和 return
const multiply = (a, b) => a * b;

// 单参数 - 省略括号
const double = x => x * 2;

ps: When the function body is a single expression, omitting the curly braces makes the code more concise.

1.2 Core feature: lexical this binding

The most important feature of arrow functions: they do not bind their own this.

// 箭头函数:this 指向定义时的上下文
function Counter() {
  this.count = 0;
  setInterval(() => {
    this.count++; // 这里的 this 指向 Counter 实例
    console.log(this.count);
  }, 1000);
}

const counter = new Counter();
// 输出: 1, 2, 3, ...

Compared with regular functions:

// 普通函数:this 指向调用时的上下文
function Counter() {
  this.count = 0;
  setInterval(function() {
    this.count++; // 这里的 this 指向 global 或 undefined
    console.log(this.count);
  }, 1000);
}

1.3 Usage limitations

Arrow functions are not a cure-all. They are not suitable in these cases:

  • Object methods: this cannot be dynamically bound
  • Constructors: cannot be called with new
  • Prototype methods: prototype property does not exist
// ❌ 错误用法
const obj = {
  name: 'test',
  getName: () => this.name  // this 指向外层作用域,不是 obj
};

// ✅ 正确用法
const obj = {
  name: 'test',
  getName() { return this.name; }  // 普通方法
};

2. Higher-order functions: the cornerstone of functional programming

Since we’re on the topic of functions, we have to talk about higher-order functions, the core of functional programming in JavaScript.

A higher-order function is one that either takes a function as an argument or returns a function.

2.1 The three essential array methods

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

// map: 转换每个元素
const doubled = numbers.map(x => x * 2);
// [2, 4, 6, 8, 10]

// filter: 筛选符合条件的元素
const evens = numbers.filter(x => x % 2 === 0);
// [2, 4]

// reduce: 汇总为单个值
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
// 15
graph LR
    A["原始数组 1,2,3,4,5"] --> B["map"]
    B --> C["新数组 2,4,6,8,10"]
    A --> D["filter"]
    D --> E["筛选结果 2,4"]
    A --> F["reduce"]
    F --> G["单一值 15"]

2.2 Combining them

The real power of higher-order functions lies in composition:

const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 17 },
  { name: 'Charlie', age: 30 }
];

// 获取成年用户名字
const adultNames = users
  .filter(user => user.age >= 18)
  .map(user => user.name);

// ['Alice', 'Charlie']

Performance tip: avoid creating unnecessary intermediate arrays in map/filter/reduce. Chained calls are concise, but with large datasets you may need to optimize manually.

2.3 More higher-order functions

// find: 查找第一个匹配元素
const firstEven = numbers.find(x => x % 2 === 0);

// some: 是否有任意匹配
const hasNegative = numbers.some(x => x < 0);

// every: 是否全部匹配
const allPositive = numbers.every(x => x > 0);

// bind: 绑定 this 和参数
const log = console.log.bind(console);

3. Prototype chain: inheritance in JavaScript

When it comes to inheritance, Java and C++ developers might think of “classes.” But JavaScript has no classes. It uses prototypes.

3.1 How the prototype chain works

Every JavaScript object has a __proto__ property that points to its prototype. When accessing a property on an object, if the object itself doesn’t have that property, JavaScript looks up the prototype chain.

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return `Hello, I'm ${this.name}`;
};

const alice = new Person('Alice');
console.log(alice.greet()); // "Hello, I'm Alice"

// 原型链: alice → Person.prototype → Object.prototype → null
graph TD
    A["alice 实例"] -->|"__proto__"| B["Person.prototype"]
    B -->|"__proto__"| C["Object.prototype"]
    C -->|"__proto__"| D["null"]

3.2 Prototypal inheritance

function Employee(name, jobTitle) {
  Person.call(this, name);  // 调用父构造函数
  this.jobTitle = jobTitle;
}

// 原型继承
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

Employee.prototype.work = function() {
  return `${this.name} is working as ${this.jobTitle}`;
};

const bob = new Employee('Bob', 'Developer');
console.log(bob.greet()); // "Hello, I'm Bob"  (继承自 Person)
console.log(bob.work()); // "Bob is working as Developer"

3.3 The nature of ES6 classes

Many people think ES6’s class is a new inheritance mechanism in JavaScript. In fact, it’s just syntactic sugar over prototypal inheritance.

// ES6 Class 写法
class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `Hello, I'm ${this.name}`;
  }
}

// 等价于原型写法
function Person(name) {
  this.name = name;
}
Person.prototype.greet = function() {
  return `Hello, I'm ${this.name}`;
};

3.4 Common Pitfalls

// ❌ 错误:修改原型影响所有实例
Person.prototype.sayHi = () => console.log('Hi');
// 所有 Person 实例都受影响

// ✅ 正确:只在实例上添加
alice.sayHi = () => console.log('Hi');
// 只有 alice 实例有这个方法

4. Code Splitting: The Key to Performance Optimization

First paint loading too slow? User churn is severe. What you may need here is code splitting.

4.1 Dynamic Import

ES6’s import() allows loading modules dynamically:

// 静态导入 - 立即加载
import { utils } from './utils.js';

// 动态导入 - 按需加载
button.addEventListener('click', () => {
  import('./heavyModule.js')
    .then(module => {
      module.doSomething();
    });
});
sequenceDiagram
    participant User
    participant Page
    participant Network
    participant Server

    User->>Page: 点击按钮
    Page->>Network: import('./heavyModule.js')
    Network->>Server: 请求模块
    Server-->>Network: 返回模块代码
    Network-->>Page: 加载完成
    Page->>Page: 执行模块代码

4.2 Webpack Splitting Strategies

// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',      // 分割所有类型的 chunk
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
};

4.3 Comparison of Splitting Strategies

StrategyUse CaseProsCons
Route-level splittingSPA applicationsSimple to implementCoarse granularity
Component-level splittingLarge componentsOn-demand loadingComplex configuration
Library-level splittingStable dependenciesLong-term cachingMore initial requests

Practical advice: bundle node_modules separately. Leverage the browser’s long-term caching to reduce repeated downloads.


5. Templates: The Art of Dynamic Rendering

How do you safely splice dynamic data into HTML? Template techniques are the key.

5.1 Template Strings

ES6 template strings greatly alleviate the torment of constantly typing quotes when concatenating strings:

const user = { name: 'Alice', age: 25 };

// 模板字符串
const html = `
  <div class="user-card">
    <h2>${user.name}</h2>
    <p>Age: ${user.age}</p>
  </div>
`;

// 对比旧写法
const htmlOld = '<div class="user-card">' +
  '<h2>' + user.name + '</h2>' +
  '<p>Age: ' + user.age + '</p>' +
  '</div>';

5.2 Template Engines

In complex scenarios, use a template engine:

<!-- Handlebars 模板 -->
<script id="user-template" type="text/x-handlebars-template">
  <div class="user">
    <h2>{{name}}</h2>
    {{#if age}}
      <p>Age: {{age}}</p>
    {{/if}}
    <ul>
      {{#each hobbies}}
        <li>{{this}}</li>
      {{/each}}
    </ul>
  </div>
</script>
// 编译并渲染
const template = Handlebars.compile(
  document.getElementById('user-template').innerHTML
);

const html = template({
  name: 'Alice',
  age: 25,
  hobbies: ['Reading', 'Coding', 'Gaming']
});

5.3 Security Notes

XSS protection: never insert user input directly into templates. Use the template engine’s auto-escaping feature.

// ❌ 危险
const html = `<div>${userInput}</div>`;

// ✅ 安全 - 自动转义
const html = template({ userInput });

6. Summary

Core ConceptUse Case
Arrow functionsLexical this bindingCallbacks, array methods
Higher-order functionsFunctions as arguments/return valuesData processing, function composition
Prototype chainPrototype-based inheritanceObject creation, inheritance patterns
Code splittingOn-demand loadingPerformance optimization
TemplatesData-driven renderingDynamic UI updates
  • Deep dive: MDN Prototype Documentation
  • Advanced topics:
    • Asynchronous programming (Promise, async/await)
    • Module systems (CommonJS, ES Modules)
    • Decorators and proxies

Learning is a continuous process. Foundational concepts are the prerequisite for advanced topics. They reward revisiting. Keep going.