JavaScript面向对象系列连接
JavaScript巧用Object的get和set方法实现js变量的动态监听
Javascript面向对象编程之工厂模式、构造函数和ES6的class类
写在前面
Object 是什么?
- typeof {} // “object”
- typeof [] // “object”
- var m = new Map(); typeof m; // “object”
- var s = new Set(); typeof s; // “object”
- function fn () {}; var instantFn = new fn(); typeof instantFn; // “object”
- class Cat{}; var garfield = new Cat(); typeof garfield; // “object”
- typeof null // “object”
- typeof undefined // “undefined”
- 以上,可以看出所有的引用数据类型实例化后都是“object”
- 分个类吧:数组和对象是普通对象,分别拥有Array、Object数据类型的所有基本特征;Map和Set是特殊定制的Object对象,拥有大多数基本的Object基本特征和若干自身特有的属性方法;function和class在实例化之前是“function”类型,实例化之后为Object类型,具有所有Object的基本特征,类似的还有Date对象等;null就是空Object,空的当然什么属性方法都没有啦,区别undefined只是数据类型不同,undefined是基本数据类型。
-
数组是最基本的引用数据类型,属性和方法很多,但扩展性不强,暂时不讨论数组的getter和setter
-
对象的getter和setter(创建对象时设置的setter和getter):
-
未设置getter和setter方法的属性相当于对象的静态属性,例如下面的count
-
设置了getter和setter方法的属性相当于对象的动态属性,例如下面的plus
-
静态属性的值可以在触发setter方法时被改变
-
动态属性的value是getter的return返回值
let obj = { count: 1, get plus() { console.log('get plus') return this.count }, set plus(val) { console.log('set plus') this.count += val } } // 控制台: obj.count // 1 obj.plus // 1 obj.plus = 2 // 3 obj.count // 3
-
-
对象初始化完成后,给对象某个属性添加getter和setter,Object.defineProperty(obj, key, {})
-
defineProperty静态描述
varo1 = new Object() o1.a = 'o1a' o1.b = 'b' // 给对象当前属性添加defineProperty Object.defineProperty(o1, 'a', { enumerable: false, // 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中 configurable: false, // 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除 // writable: false, // 当且仅当该属性的writable为true时,value才能被赋值运算符改变 value: "static o1a" // 属性的值 }) console.log(o1.a) // static o1a // 题外,上面的三个属性作用测试: o1.a = 12121 console.log(o1.a) // static o1a writable: false 时可以进行赋值操作,但是改变不了该属性的值
-
defineProperty动态态描述(getter和setter方法)
var o1 =new Object() o1.a = 'o1a' o1.b = 'b' // 给对象的当前属性添加getter和setter Object.defineProperty(o1, 'b', { enumerable: true, configurable: true, // writable: true, // 添加getter和setter时不能设置writable和value // value: 'chang1 oa.b', get() { console.log('触发了getter') return o1.b }, set(val) { console.log('触发了setter') o1.b = val } }) console.log(o1.b) // 啊哦,出现很多次重复调用getter,我的浏览器卡死了-_-!
-
改进方法:效避免被触发多次,将getter和setter需要修改的值赋值给外部变量
var o1 = new Object() o1.a = 'o1a' o1.b = 'b' var bVal = '' Object.defineProperty(o1, 'b', { enumerable: true, configurable: true, get() { console.log('触发了getter') return bVal }, set(val) { console.log('触发了setter') bVal = val } }) o1.b = 322 // 触发了setter console.log(o1.b) // 触发了getter 322
- 使用场景,在构造函数中:使创建的构造对象对内部属性的值存取产生响应事件
function Cat () { var color = null Object.defineProperty(this, 'color', { get() { console.log('get color!') return color }, set(val) { console.log(`set color: ${val}!`) color = val } }) } // 实例化cat var blueCat = new Cat() blueCat.color = 'blue' // set color: blue! console.log(blueCat.color) // get color! "blue"
-
-
函数和class的实例化对象的getter和setter
- 上面示例已经提到了构造函数的实例化对象的getter和setter
- 不过这个写法需要在创建这个构造函数时就写好,有的场景就不太适用了
- 更高级的写法就是把getter和setter写到构造函数或class的原型链上:
functionCat () {} var redCat = new Cat() Object.defineProperty(Cat.prototype, 'age', { get() { console.log('get Cat.age!') return Cat.age }, set(val) { console.log(`set Cat.age: ${val} !`) Cat.age = val } }) redCat.age = "121" // set Cat.age: mimi ! console.log(redCat.age) // get Cat.age! "121"
- ps: 将上面的Cat.age属性换成Cat.name属性试试 ←_← 这是一个小小的坑哦,不想在项目中踩坑的小伙伴们动手手哦,至于原因嘛,能自己找到最好了,小编在这里小小剧透下:问题就出现在命名空间冲突上
-
应用:实现js变量的动态变化监听,你想想,只要你修改了一个变量的值,自动触发一个同步修改DOM的方法,你是不是不用再去手动操作DOM,岂不省心!反过来DOM节点上的一个变量的值发生改变,同步修改你内存空间上的的某变量,也不用你再去手动获取DOM节点的值,岂不美哉!有兴趣的小伙伴快去动手实现一个mini Vue吧!!!