对象基础属性的属性设置

52 阅读1分钟

通过Object.defineProperty来认识/设置

	   for (let key in obj){
			Object.defineProperty(target,key,{
				value: obj[key], // 值
				writable:true, // 是否可写
				enumerable: false,// 是否可遍历
				configurable: false, // 是否可删除
        get(){ // 注意,定义了这个方法的时候,就不能加value和writable属性
        	return obj[key]
        },
        set(val){ // 注意,定义了这个方法的时候,就不能加value和writable属性
          console.log(val)
        }
			})
		}
		delete target.count;//删除count属性
		console.log(target); // 删不掉

所有有时候,我们打印一个对象,里面是没有x属性的,但是你打印obj.x却是有值的,这是因为给这个x属性设置了get方法。 下面是一个使用上的例子,来自vue2源码,巧妙应用了闭包和属性的特性

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
  <div id='app'>
    <div>1</div>
    <div>
      <h3>姓名</h3>
      <p>{{name}}</p>
      <h3>年龄</h3>
      <p>{{age}}</p>
    </div>
  </div>
</body>

</html>
<script>
  document.addEventListener('DOMContentLoaded', function () {
    let obj = { el: '#app', data: { name: '检索中', age: 30 } }
    let vm = new Vue(obj)
    setTimeout(() => {
      obj.data.name = '王永峰'
    }, 200);
  }, false)
  class Vue {
    constructor(obj) {
      this.obj = obj
      this.observe(obj.data)
      let root = document.querySelector(obj.el)
      this.compile(root)
    }
    // 为响应式对象 data 里的每一个 key 绑定一个观察者对象
    observe(data) {
      Object.keys(data).forEach(key => {
        let obv = new Observer() // 注意,是每一个属性都注册了一个观察者
        data["_" + key] = data[key]
        // 通过 getter setter 暴露 for 循环中作用域下的 obv,闭包产生
        Object.defineProperty(data, key, {
          get() {
            console.log('getgetget', data['_' + key], Observer.target)
            Observer.target && obv.addSubNode(Observer.target);
            return data['_' + key]
          },
          set(newVal) {
            console.log('setsetset', newVal)
            obv.update(newVal)
            data['_' + key] = newVal
          }
        })
      })
    }
    // 初始化页面,遍历 DOM,收集每一个key变化时,随之调整的位置,以观察者方法存放起来
    compile(node) {
      [].forEach.call(node.childNodes, child => {
        if (!child.firstElementChild && /\{\{(.*)\}\}/.test(child.innerHTML)) {
          // 这个正则匹配的是{{}}括号
          let key = RegExp.$1.trim()
          console.log('child1', child, key)
          child.innerHTML = child.innerHTML.replace(new RegExp('\\{\\{\\s*' + key + '\\s*\\}\\}', 'gm'), this.obj.data[`_${key}`]) // 这样我觉得更合适,不调用get方法
          Observer.target = child
          this.obj.data[key] // 这里是触发get方法
          Observer.target = null
        }
        else if (child.firstElementChild) {
          console.log('child2', child)
          this.compile(child)
        }
      })
    }
  }
  // 常规观察者类
  class Observer {
    constructor() {
      this.subNode = [] // 这个subNode就是订阅了属性的节点们
    }
    addSubNode(node) {
      this.subNode.push(node)
      console.log('addnode', this.subNode)
    }
    update(newVal) {
      console.log('this.subNode', this.subNode)
      this.subNode.forEach(node => {
        node.innerHTML = newVal
      })
    }
  }
</script>

内容来自blog.csdn.net/qq_43465434…