李子默

Bugslayer

JavaScript中的getter和setter

2018-11-24 Azrieljavascript

在 C++, C#, Java 等面向对象语言中,对象由两部分组成:属性和方法。通常属性是私有成员或保护成员,不能从对象外部直接访问;方法是公有成员,供外界间接访问对象的内部属性,以此来实现数据隔离。利用伪代码来简单演示如下:

构造一个只有一个私有成员而没有任何共有方法的对象 obj

var obj = {
  private int attr1 = 1024,
}

不能直接访问和修改attr1

print(obj.attr1) // Error: can't access attr1 of obj
obj.attr1 = 4201 // Error: can't access attr1 of obj

而 Javascript 中则没有这样的数据隔离机制(不过 ES6 中可以通过Symbol来实现相似的定义私有成员的方法) , 你可以定义一个对象,然后随意修改它的属性:

var obj = {
  attr1: 1024
};

console.log(obj.attr1); // 1024
obj.attr1 = 1000;
console.log(obj.attr1); // 1000

虽然 Javascript 没有提供硬性的对象成员隔离机制,但通过定义方法来间接访问数据成员的场景还是存在的,这就是 getter 和 setter 存在的意义。你可能以为我接下来会讲讲 JavaScript 的 setter 和 getter 是怎么运作的, You’re wrong. 自己去 MDN 看吧!这里有必要讲的是 Vuex 的 getter 和 setter 是怎么工作的,因为身边很多朋友都踩过坑。看下边的例子:

// 先在Vuex store里定义一个cat
const zoo = {
  state: {
    cat: {
      name: 'tom'
    }
  },
  mutations: {
    changeCatColor(color) {
      state.cat.color = color
    }
  }
}

// 然后在系统中某个地方修改下上面的cat的color
store.commit('changeCatColor', 'red')

// 在某个叫foo-bar的component中获取store中的cat的color,将其渲染在视图上
{
  computed: {
    catColor() {
      return this.$store.state.cat.color
    }
  }
}

// 猜猜结果是什么?

// 正确答案:
// zoo.state变成了

{
  cat: {
    name: 'tom',
    color: 'red'
  }
}

// foo-bar中
console.log(this.catColor) // undefined

为什么会这样?因为 Vuex 之所以能将 state 中数据的变化传递到组件中,是因为 Vuex 在初始化 state 时会通过字段的 setter 来设置监听器, 当字段值改变时,就可以把新值传递给 getter。示例中的 cat.color 没有在 state 初始化时声明,所以没有监听器,就导致虽然 state.cat.color 改变了, 但没有传递到组件中。所以,最重要的一句话:在使用 Vuex 的 state 之前,一定要初始化所有属性!