在JavaScript编程中,对象和数组是构建复杂应用的基础。本文将通过多个实用案例,从原始实现出发,逐步优化代码,带你掌握对象创建、数组操作、数据遍历等核心技能。每个案例都包含原始代码解析、优化方案及关键知识点说明,帮助你写出更规范、高效的JavaScript代码。

案例1:创建人类对象及方法实现

需求说明

创建一个包含编号、名称、年龄、性别属性的人类对象,添加"吃饭"功能,并在页面展示该对象信息。

原始代码实现

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>人类对象示例</title>
<script>
var person={
  'bianhao':007,
  'name':'诗书画唱',
  'age':20,
  'sex':'男',
  'chifan' :function(){
    alert(this.name+"正在吃饭");
  }
};

for(var i in person){
  document.write(person[i]+"&nbsp;&nbsp;");
}
document.write("<hr>");
document.write(person.bianhao+"&nbsp;&nbsp;"+person.name + "&nbsp;&nbsp;"+person.age+" &nbsp; &nbsp;"+person.sex);
person.chifan();
</script>
</head>
<body>
</body>
</html>

原始代码解析

  1. 使用对象字面量创建了person对象,包含属性和方法
  2. 通过for...in循环遍历对象属性并输出
  3. 直接通过点语法访问属性并输出
  4. 调用chifan方法弹出提示框

存在的问题

  1. 使用var声明变量,缺乏块级作用域
  2. 编号007作为数字会被解析为7,丢失前导零
  3. 使用document.write()输出内容,不利于页面布局控制
  4. 弹窗提示用户体验不佳
  5. 代码结构混乱,展示逻辑与数据混合

优化方案

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>优化后的人类对象示例</title>
  <style>
    .person-card {
      border: 1px solid #ccc;
      padding: 15px;
      max-width: 300px;
      margin: 20px;
      border-radius: 5px;
      box-shadow: 0 2px 3px rgba(0,0,0,0.1);
    }
    .person-info {
      margin: 8px 0;
    }
    .action-btn {
      margin-top: 10px;
      padding: 6px 12px;
      background-color: #4CAF50;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    .action-btn:hover {
      background-color: #45a049;
    }
    .status {
      margin-top: 10px;
      color: #666;
      font-style: italic;
    }
  </style>
</head>
<body>
  <div class="person-card" id="personCard"></div>

  <script>
    // 使用const声明常量对象,属性使用更规范的命名
    const person = {
      id: '007',          // 改为字符串保留前导零
      name: '诗书画唱',
      age: 20,
      gender: '男',       // 使用更规范的属性名
      
      // 吃饭方法,改为更新页面状态而非弹窗
      eat: function() {
        const statusElement = document.getElementById('status');
        statusElement.textContent = `${this.name}正在吃饭`;
      }
    };

    // 渲染人员信息到页面
    function renderPersonInfo(person) {
      const card = document.getElementById('personCard');
      
      // 创建信息展示区域
      card.innerHTML = `
        <h3>人员信息</h3>
        <div class="person-info"><strong>编号:</strong>${person.id}</div>
        <div class="person-info"><strong>姓名:</strong>${person.name}</div>
        <div class="person-info"><strong>年龄:</strong>${person.age}</div>
        <div class="person-info"><strong>性别:</strong>${person.gender}</div>
        <button class="action-btn" onclick="person.eat()">执行吃饭动作</button>
        <div class="status" id="status"></div>
      `;
    }

    // 页面加载完成后渲染信息
    window.onload = function() {
      renderPersonInfo(person);
    };
  </script>
</body>
</html>

优化点说明

  1. 变量声明:使用const替代var,明确变量不可变
  2. 属性命名:使用更规范的英文命名(如id替代bianhaogender替代sex
  3. 数据类型:编号改为字符串类型,保留前导零
  4. 输出方式:使用DOM操作替代document.write(),通过模板字符串构建页面结构
  5. 用户体验:将弹窗提示改为页面内状态更新,添加交互按钮
  6. 代码组织:将渲染逻辑封装为函数,提高可维护性
  7. 样式美化:添加CSS样式,使展示更美观

案例2:人类对象数组创建与遍历

需求说明

创建包含3名人员信息的对象数组,并遍历展示所有人员信息。

原始代码实现

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>人员对象数组</title>
<script>
var persons=[
  {'bianhao':007,'name':'诗书画唱1','age':20},
  {'bianhao':666,'name':'诗书画唱2','age':21},
  {'bianhao':233,'name':'诗书画唱3','age':22},
];

for(var i of persons){
  for(var j in i){
    document.write(i[j]+"&nbsp;");
  }
  document.write("<br>");
}
</script>
</head>
<body>
</body>
</html>

原始代码解析

  1. 创建了包含3个人员对象的数组
  2. 使用for...of遍历数组中的每个对象
  3. 使用for...in遍历每个对象的属性
  4. 通过document.write()输出属性值,使用&nbsp;分隔

存在的问题

  1. 缺乏表头信息,用户无法直观理解各数值含义
  2. 输出格式简陋,数据排列不整齐
  3. 同样存在编号前导零丢失问题
  4. 直接使用document.write()不利于样式控制

优化方案

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>优化后的人员对象数组</title>
  <style>
    .persons-table {
      border-collapse: collapse;
      width: 80%;
      max-width: 600px;
      margin: 20px;
      border: 1px solid #ddd;
    }
    .persons-table th, .persons-table td {
      padding: 12px;
      text-align: left;
      border-bottom: 1px solid #ddd;
    }
    .persons-table th {
      background-color: #f2f2f2;
      font-weight: bold;
    }
    .persons-table tr:hover {
      background-color: #f5f5f5;
    }
  </style>
</head>
<body>
  <table class="persons-table" id="personsTable">
    <!-- 表格内容将通过JS动态生成 -->
  </table>

  <script>
    // 人员数据数组,使用规范命名和字符串编号
    const persons = [
      { id: '007', name: '诗书画唱1', age: 20 },
      { id: '666', name: '诗书画唱2', age: 21 },
      { id: '233', name: '诗书画唱3', age: 22 }
    ];

    // 渲染人员表格
    function renderPersonsTable(persons) {
      const table = document.getElementById('personsTable');
      
      // 创建表头
      const thead = document.createElement('thead');
      thead.innerHTML = `
        <tr>
          <th>编号</th>
          <th>姓名</th>
          <th>年龄</th>
        </tr>
      `;
      table.appendChild(thead);
      
      // 创建表体并添加数据行
      const tbody = document.createElement('tbody');
      
      // 使用forEach方法遍历数组,更现代的写法
      persons.forEach(person => {
        const row = document.createElement('tr');
        row.innerHTML = `
          <td>${person.id}</td>
          <td>${person.name}</td>
          <td>${person.age}</td>
        `;
        tbody.appendChild(row);
      });
      
      table.appendChild(tbody);
    }

    // 页面加载完成后渲染表格
    window.onload = function() {
      renderPersonsTable(persons);
    };
  </script>
</body>
</html>

优化点说明

  1. 数据结构:统一使用规范的属性命名,编号改为字符串
  2. 遍历方式:使用forEach方法遍历数组,代码更简洁清晰
  3. 展示方式:使用表格展示数据,添加表头,提高可读性
  4. 样式美化:添加CSS样式,包括hover效果,提升用户体验
  5. 代码组织:将渲染逻辑封装为函数,便于维护和复用
  6. DOM操作:通过创建DOM元素构建表格,而非直接写入文档

案例3:商品构造函数与总价计算

需求说明

创建商品构造函数,实例化3件商品并放入数组,计算并展示商品总价格。

原始代码实现

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>商品总价计算</title>
<script>
var shangPin = function(bianhao, name, price, num) {
  this.bianhao = bianhao;
  this.name = name;
  this.price = price;
  this.num = num;
}

var shangPinShuZu = [
  new shangPin(1,'苹果', 2, 5),
  new shangPin(2,'香蕉', 5, 2),
  new shangPin(3, 'CD', 10, 1)
];

alert("计算总价格为:"+jiSuanZongJiaGe(shangPinShuZu));

function jiSuanZongJiaGe(shangPinShuZu) {
  var zongJiaGe = 0; 
  for(var i of shangPinShuZu) {
    var meiGeShangPinJiaGe = (i.price * i.num);
    zongJiaGe += meiGeShangPinJiaGe;
  }
  return zongJiaGe;
}
</script>
</head>
<body>
</body>
</html>

原始代码解析

  1. 使用构造函数创建shangPin对象类型
  2. 实例化3个商品对象并存储在数组中
  3. 定义jiSuanZongJiaGe函数计算总价
  4. 通过弹窗展示计算结果

存在的问题

  1. 构造函数命名不规范(应使用 PascalCase 命名法)
  2. 仅通过弹窗展示结果,用户体验不佳
  3. 未展示商品列表信息,用户无法核对
  4. 变量命名使用拼音,不符合规范
  5. 缺乏必要的格式处理(如价格保留两位小数)

优化方案

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>商品总价计算</title>
  <style>
    .product-container {
      margin: 20px;
      max-width: 800px;
    }
    .product-table {
      border-collapse: collapse;
      width: 100%;
      margin-bottom: 20px;
    }
    .product-table th, .product-table td {
      border: 1px solid #ddd;
      padding: 12px;
      text-align: left;
    }
    .product-table th {
      background-color: #f2f2f2;
    }
    .total-price {
      font-size: 18px;
      font-weight: bold;
      color: #e74c3c;
      padding: 10px;
      border: 1px solid #eee;
      display: inline-block;
    }
  </style>
</head>
<body>
  <div class="product-container">
    <h2>商品列表</h2>
    <table class="product-table" id="productTable"></table>
    <div id="totalPriceContainer"></div>
  </div>

  <script>
    // 使用ES6 class语法,更清晰的构造函数
    class Product {
      constructor(id, name, price, quantity) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.quantity = quantity;
      }
      
      // 计算单个商品总价的方法
      getTotalPrice() {
        return this.price * this.quantity;
      }
    }

    // 创建商品数组
    const products = [
      new Product(1, '苹果', 2, 5),
      new Product(2, '香蕉', 5, 2),
      new Product(3, 'CD', 10, 1)
    ];

    // 计算所有商品的总价
    function calculateTotalPrice(products) {
      // 使用reduce方法计算总价,更函数式的写法
      return products.reduce((total, product) => {
        return total + product.getTotalPrice();
      }, 0);
    }

    // 渲染商品列表和总价
    function renderProducts() {
      const table = document.getElementById('productTable');
      const totalContainer = document.getElementById('totalPriceContainer');
      
      // 创建表头
      table.innerHTML = `
        <tr>
          <th>编号</th>
          <th>商品名称</th>
          <th>单价(元)</th>
          <th>数量</th>
          <th>小计(元)</th>
        </tr>
      `;
      
      // 添加商品行
      products.forEach(product => {
        const row = document.createElement('tr');
        const subtotal = product.getTotalPrice();
        row.innerHTML = `
          <td>${product.id}</td>
          <td>${product.name}</td>
          <td>${product.price.toFixed(2)}</td>
          <td>${product.quantity}</td>
          <td>${subtotal.toFixed(2)}</td>
        `;
        table.appendChild(row);
      });
      
      // 展示总价
      const totalPrice = calculateTotalPrice(products);
      totalContainer.innerHTML = `
        <div class="total-price">
          商品总价:${totalPrice.toFixed(2)}元
        </div>
      `;
    }

    // 页面加载完成后渲染
    window.onload = function() {
      renderProducts();
    };
  </script>
</body>
</html>

优化点说明

  1. 构造函数:使用ES6的class语法,更清晰的面向对象结构
  2. 命名规范:使用英文命名且遵循规范(PascalCase 用于类,camelCase 用于方法和属性)
  3. 方法封装:在类中添加getTotalPrice方法计算单个商品总价
  4. 计算方式:使用reduce方法计算总价,更符合函数式编程风格
  5. 展示方式:通过表格展示完整商品信息,包括单价、数量和小计
  6. 格式处理:使用toFixed(2)确保价格保留两位小数
  7. 用户体验:在页面中展示结果而非弹窗,提供完整的视觉信息

扩展题:对象操作进阶技巧

扩展1:对象控制台输出与方法优化

原始代码实现
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>对象控制台输出</title>
<script>
// 第一种创建对象方法:直接创建
var duiXiang1={'bianhao':1,'name':'诗书画唱' , 'age':19,'sex':'男'};

// 第二种创建对象方法:使用new创建
var duiXiang2=new Object();
duiXiang2.bianhao=2;
duiXiang2.name='诗书画唱SSHC';
duiXiang2.age=19;
duiXiang2.sex='男';

duiXiang2.gongneng=function(){
  alert(this.name+"的功能是吃饭");
  document.write(this.name+"的功能是吃饭");
}

console.log(duiXiang1);
console.log(duiXiang2);

window.onload=function() {
  duiXiang2.gongneng();
}
</script>
</head>
<body>
</body>
</html>
优化方案
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>对象控制台输出优化</title>
  <style>
    .info-box {
      margin: 20px;
      padding: 15px;
      border: 1px solid #ccc;
      border-radius: 5px;
    }
    .hint {
      color: #666;
      font-style: italic;
    }
  </style>
</head>
<body>
  <div class="info-box">
    <h3>对象调试演示</h3>
    <p>请打开浏览器控制台(F12)查看对象信息</p>
    <p class="hint">提示:在控制台中可以展开对象,查看其属性和方法</p>
    <div id="actionResult"></div>
  </div>

  <script>
    // 使用对象字面量创建(推荐方式)
    const person1 = {
      id: 1,
      name: '诗书画唱',
      age: 19,
      gender: '男',
      
      // 重写toString方法,便于日志输出
      toString() {
        return `${this.name} (${this.id}): ${this.age}岁, ${this.gender}`;
      }
    };

    // 使用Object.create创建对象(适合需要原型继承的场景)
    const person2 = Object.create(null, {
      id: { value: 2, writable: true },
      name: { value: '诗书画唱SSHC', writable: true },
      age: { value: 19, writable: true },
      gender: { value: '男', writable: true },
      // 吃饭方法
      eat: { 
        value: function() {
          const resultElement = document.getElementById('actionResult');
          resultElement.textContent = `${this.name}正在吃饭`;
          // 在控制台输出详细信息
          console.log(`${new Date().toLocaleTimeString()}: ${this.name}执行了吃饭动作`);
        }
      }
    });

    // 控制台输出优化
    console.group('人员对象信息');
    console.log('person1 对象:', person1);
    console.log('person1 字符串表示:', person1.toString());
    console.log('person2 对象:', person2);
    console.dir(person2); // 更详细的对象结构展示
    console.groupEnd();

    // 页面加载后执行方法
    window.onload = function() {
      // 添加按钮触发动作,而非自动执行
      const button = document.createElement('button');
      button.textContent = '执行吃饭动作';
      button.onclick = () => person2.eat();
      document.body.appendChild(button);
    };
  </script>
</body>
</html>

扩展1.1:对象属性的添加与删除

实现代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>对象属性操作</title>
  <style>
    .container {
      margin: 20px;
    }
    .object-display {
      padding: 15px;
      background-color: #f8f9fa;
      border-radius: 5px;
      margin: 10px 0;
      white-space: pre-wrap;
    }
    button {
      margin: 5px;
      padding: 6px 12px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h3>对象属性添加与删除演示</h3>
    <div>
      <button onclick="addProperty()">添加属性</button>
      <button onclick="deleteProperty()">删除属性</button>
      <button onclick="modifyProperty()">修改属性</button>
      <button onclick="checkProperty()">检查属性是否存在</button>
    </div>
    <h4>当前对象:</h4>
    <div class="object-display" id="objectDisplay"></div>
    <div id="message"></div>
  </div>

  <script>
    // 初始对象
    let person = {
      id: 1,
      name: '诗书画唱',
      age: 19,
      gender: '男'
    };

    // 显示对象当前状态
    function displayObject() {
      const displayElement = document.getElementById('objectDisplay');
      // 格式化输出,便于阅读
      displayElement.textContent = JSON.stringify(person, null, 2);
    }

    // 添加属性
    function addProperty() {
      // 检查属性是否已存在
      if (!person.address) {
        person.address = '北京市';
        showMessage('已添加address属性');
      } else if (!person.hobby) {
        person.hobby = '阅读';
        showMessage('已添加hobby属性');
      } else {
        showMessage('所有可选属性已添加');
      }
      displayObject();
    }

    // 删除属性
    function deleteProperty() {
      // 删除属性的两种方式
      if (person.age) {
        delete person.age;
        showMessage('已删除age属性');
      } else if (person.gender) {
        delete person['gender'];
        showMessage('已删除gender属性');
      } else {
        showMessage('没有可删除的属性');
      }
      displayObject();
    }

    // 修改属性
    function modifyProperty() {
      person.age = person.age ? person.age + 1 : 20;
      showMessage(`已更新age属性为: ${person.age}`);
      displayObject();
    }

    // 检查属性是否存在
    function checkProperty() {
      const hasId = 'id' in person;
      const hasAddress = 'address' in person;
      showMessage(`id属性存在: ${hasId}, address属性存在: ${hasAddress}`);
    }

    // 显示操作消息
    function showMessage(text) {
      const messageElement = document.getElementById('message');
      messageElement.textContent = text;
    }

    // 初始化显示
    window.onload = function() {
      displayObject();
    };
  </script>
</body>
</html>

扩展1.2:JavaScript数组遍历方法详解

实现代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>数组遍历方法详解</title>
  <style>
    .container {
      margin: 20px;
      max-width: 800px;
    }
    .method-section {
      margin-bottom: 30px;
      padding: 15px;
      border: 1px solid #eee;
      border-radius: 5px;
    }
    .result {
      background-color: #f8f9fa;
      padding: 10px;
      margin-top: 10px;
      border-radius: 4px;
      white-space: pre-wrap;
    }
    button {
      padding: 6px 12px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>JavaScript数组遍历方法对比</h2>
    
    <div class="method-section">
      <h3>1. for循环遍历</h3>
      <button onclick="traverseWithFor()">执行for循环遍历</button>
      <div class="result" id="forResult"></div>
    </div>
    
    <div class="method-section">
      <h3>2. for...of遍历</h3>
      <button onclick="traverseWithForOf()">执行for...of遍历</button>
      <div class="result" id="forOfResult"></div>
    </div>
    
    <div class="method-section">
      <h3>3. forEach遍历</h3>
      <button onclick="traverseWithForEach()">执行forEach遍历</button>
      <div class="result" id="forEachResult"></div>
    </div>
    
    <div class="method-section">
      <h3>4. map遍历(返回新数组)</h3>
      <button onclick="traverseWithMap()">执行map遍历</button>
      <div class="result" id="mapResult"></div>
    </div>
    
    <div class="method-section">
      <h3>5. filter遍历(筛选元素)</h3>
      <button onclick="traverseWithFilter()">执行filter遍历</button>
      <div class="result" id="filterResult"></div>
    </div>
  </div>

  <script>
    // 人员数据数组
    const persons = [
      { id: 1, name: '诗书画唱1', age: 19 },
      { id: 2, name: '诗书画唱2', age: 22 },
      { id: 3, name: '诗书画唱3', age: 25 }
    ];

    // 1. for循环遍历
    function traverseWithFor() {
      const result = [];
      for (let i = 0; i < persons.length; i++) {
        result.push(`[${i}] ${persons[i].name}, ${persons[i].age}`);
      }
      document.getElementById('forResult').textContent = result.join('\n');
    }

    // 2. for...of遍历
    function traverseWithForOf() {
      const result = [];
      for (const person of persons) {
        result.push(`${person.name}, ${person.age}`);
      }
      document.getElementById('forOfResult').textContent = result.join('\n');
    }

    // 3. forEach遍历
    function traverseWithForEach() {
      const result = [];
      persons.forEach((person, index) => {
        result.push(`[${index}] ${person.name}, ${person.age}`);
      });
      document.getElementById('forEachResult').textContent = result.join('\n');
    }

    // 4. map遍历(返回新数组)
    function traverseWithMap() {
      // map返回一个新数组,包含转换后的值
      const mapped = persons.map(person => {
        return {
          fullInfo: `${person.name} (ID: ${person.id})`,
          ageGroup: person.age < 20 ? '青年' : '成年'
        };
      });
      document.getElementById('mapResult').textContent = JSON.stringify(mapped, null, 2);
    }

    // 5. filter遍历(筛选元素)
    function traverseWithFilter() {
      // filter返回符合条件的元素组成的新数组
      const adults = persons.filter(person => person.age >= 20);
      document.getElementById('filterResult').textContent = JSON.stringify(adults, null, 2);
    }
  </script>
</body>
</html>

总结与进阶建议

通过对以上案例的解析与优化,我们可以总结出JavaScript对象与数组操作的最佳实践:

  1. 命名规范:使用有意义的英文名称,遵循PascalCase(类)和camelCase(方法、属性)命名法
  2. 变量声明:优先使用constlet,避免使用var,明确变量的可变性
  3. 对象创建
    • 简单对象推荐使用对象字面量{}
    • 复杂对象或需要多次实例化时使用class
    • 避免使用new Object()创建对象
  4. 数组遍历
    • 简单遍历推荐使用forEach
    • 需要返回新数组时使用map
    • 需要筛选元素时使用filter
    • 需要计算累加结果时使用reduce
  5. DOM操作:避免使用document.write(),通过createElementtextContent等方法操作DOM
  6. 代码组织:将功能封装为函数,提高复用性和可维护性

进阶学习建议

  1. 学习ES6+更多特性:箭头函数、解构赋值、展开运算符等
  2. 掌握数组高级方法:find(), some(), every(), sort()
  3. 学习对象的原型与继承机制
  4. 了解Immutable数据处理理念,避免直接修改对象
  5. 学习TypeScript,为对象和数组添加类型定义,提高代码健壮性

通过不断实践这些技巧,你将能够写出更规范、高效、可维护的JavaScript代码,为构建复杂前端应用打下坚实基础。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐