《JavaScript应用程序设计》一一1.15 减少隐式副作用

简介:

本节书摘来华章计算机出版社《JavaScript应用程序设计》一书中的第1章,第1.15 节,作者:Eric Elliott 更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.15 减少隐式副作用

在JavaScript中有两类十分常见却可以轻易规避的错误。第一类是语法错误,第二类是无意识的隐式副作用。
隐式副作用是代码复用的大敌,因为它导致函数被其作用域外的状态所劫持。隐式副作用的产生是由于多个函数间共享变量或属性所致,举例来说,应用中有一个购物车功能,用户在会话期间可以对购物车的内容进行保存。
用户想要更改当前会话中购物车的内容顺序,只需:

test('Order WITH unintentional side effect.', function () {
      var cartProto = {
          items: [],

          addItem: function addItem(item) {
            this.items.push(item);
          }
        },

        createCart = function (items) {
          var cart = Object.create(cartProto);
          cart.items = items;
          return cart;
        },

        // Load cart with stored items.
        savedCart = createCart(["apple", "pear", "orange"]),

        session = {
          get: function get() {
            return this.cart;
          },

          // Grab the saved cart.
          cart: createCart(savedCart.items)
        };

      // addItem gets triggered by an event handler somewhere:
      session.cart.addItem('grapefruit');

      ok(session.cart.items.indexOf('grapefruit')
        !== -1, 'Passes: Session cart has grapefruit.');

      ok(savedCart.items.indexOf('grapefruit') === -1,
        'Fails: The stored cart is unchanged.');
    });

很不幸,当用户在当前会话中添加或删除购物车内容时,之后的购物车设置信息也被连带删除了,导致这个问题的代码片段是:

createCart = function (items) {
  var cart = Object.create(cartProto);
  cart.items = items;
  return cart;
},

请留意此处,cart.items是对原型对象上items属性的直接引用,现在对代码做略微修改。
cart.items = Object.create(items);
新的购物车拥有自己的内容副本,不会再对storedCart对象带来直接影响。
若想减少隐式副作用在程序中的出现概率,最好的方法就是在函数内部对它进行规避。所有外部变量传入函数之前,最好是先经过一轮复制,不要将原始值直接传入。
纯函数没有隐式副作用,因为它在调用时不会更改任何外部变量,决定它返回值的因素仅有一个,即它的入参。
尽可能地确保你的函数在执行过程中不会影响外界的状态,在执行结尾处返回修改后的变量副本而不是原始引用,请注意,在整个执行过程中你仍然有更改外部变量的机会。就像REST架构下客户端与服务器的数据传输一样:客户端首先从服务器获取一份数据资源的副本,修改其内容,再将处理过的副本发送回至服务器。建议归建议,大部分情况下开发者为了兼顾到应用的性能不会这么去做,不过使用纯函数或许可以起到一定效果。
在每个函数内部对隐式副作用做规避,一来可以减少代码冗余,二来可以帮助你提升程序分层设计的意识。举例来说,你有一个开工已达数月之久的项目,现在你需要对其新增数据校验功能,当项目中仅有一个函数能够对数据进行提交操作时,你只需把校验功能安插在此函数调用之前即可。但如果这样的函数在项目中有百来个,势必会影响校验功能的加入。
将不同的功能逻辑相互隔离,可以让你更好地管理应用状态。如果函数在执行过程中不会被外界的状态变更所干扰,它只需少量代码就可以完成手头的工作,因为眼前的任务只有一个。
同理,操作DOM的函数一定只专注于DOM树操作,比如视图的render()方法,又如一些DOM树插件。

相关文章
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
78 2
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的医院综合管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的医院综合管理系统附带文章源码部署视频讲解等
40 5
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
68 4
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物交易平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物交易平台附带文章源码部署视频讲解等
60 4
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的大学生入伍人员管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的大学生入伍人员管理系统附带文章源码部署视频讲解等
78 4
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
78 3
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp宿舍管理系统的附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp宿舍管理系统的附带文章源码部署视频讲解等
65 3
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的家政平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的家政平台附带文章源码部署视频讲解等
47 3
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物医院系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物医院系统附带文章源码部署视频讲解等
41 2
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的实验室安全考试系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的实验室安全考试系统附带文章源码部署视频讲解等
54 2