- const box = document.querySelector('.box')
- const obj = {
- name: 'QF666',
- age: 18
- }
- box.innerHTML = `名字: ${obj.name}; 年龄: ${obj.age}`;
-
- obj.age = 99;
- box.innerHTML = `名字: ${obj.name}; 年龄: ${obj.age}`;
-
-
- obj.name = 'QF999';
- box.innerHTML = `名字: ${obj.name}; 年龄: ${obj.age}`;
- console.log(obj);

- 将原始数据,劫持出一份一摸一样, 听起来有点像浅拷贝
- 劫持出来的数据, 默认是不可以修改的
- 语法: Object.defineProperty(那个对象, '对象的key', {配置项})
- 配置项:
- 1. value 访问这个值 之后, 得到结果
- 2. writable 决定当前这个属性能否被修改, 默认是 false
- 3. enumerable 决定当前这个属性能否被枚举, 决定当前这个属性能否被遍历到
- 4. getter 是一个函数, 是一个获取器, 当访问这个属性时, 会执行这个函数
- getter不能和value、writable一起使用
-
- 5. setter 是一个函数, 是一个设置器, 当设置这个属性是, 会执行这个函数
- const obj = {}
- obj.name = 'QF666'
- console.log(obj)
-
- // Object.defineProperty(obj, str, {配置项})
- Object.defineProperty(obj, 'age', {
- // value: 'QF999',
- // writable: true,
- enumerable: true,
- get() {
- // console.log('你当前访问了这个age属性, 触发了get函数')
- return 'qwerty'
- },
- set(val) {
- console.log('你当前想要修改这个age属性, 修改的值是: ', val)
- }
- })
- obj.age = 999
- console.log(obj.age)

- "box">
- <script>
- // 实现数据劫持
- const box = document.querySelector('#box')
- const obj = {
- name: 'QF666',
- age: 18
- }
- console.log('原始对象obj:', obj)
- const res = {}
-
- Object.defineProperty(res, 'name', {
- get() {
- return obj.name
- },
- set(val) {
- // console.log('你想要修改这个属性的值, 新值为: ', val)
- obj.name = val
- box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
- }
- })
-
- Object.defineProperty(res, 'age', {
- get() {
- return obj.age
- },
- set(val) {
- // console.log('你想要修改这个属性的值, 新值为: ', val)
- obj.age = val
- box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
- }
- })
- box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
- res.age = 100;
- script>

- <input type="text" name="" id="inp">
- <div id="box">div>
函数的封装 :
- const box = document.querySelector('#box')
- const obj = {
- name: 'QF666',
- age: 18
- }
- function observer(origin, callback) {
- const target = {}
-
- for (let k in origin) {
- Object.defineProperty(target, k, {
- get() {
- return origin[k]
- },
- set(val) {
- // console.log('你现在想要修改的key是' , k, '修改的值为', val)
- origin[k] = val
- callback(target)
- }
- })
- }
- callback(target)
- return target
- }
调用的
- function fn(res) {
- box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
- }
-
- const app = observer(obj, fn)
-
-
- document.querySelector('#inp').oninput = function (e) {
- app.age = e.target.value
- }
- 模拟一个其他人写的代码, 框架的源码
- 把需要渲染的代码, 都放到HTML 中, 然后由我这段代码帮助我们去渲染
- "app">
- <h1> {{msg}} h1>
- <h1> {{ name }} h1>
- <h1> {{ age }} h1>
- <h1> {{ abc }} h1>
-
封装的
-
- function observer(options) {
- // 1. 验证root有没有传递
- if (options.root === undefined) {
- // console.log('您没有传递root属性, 请重新传递')
- // 手动返回一个错误
- throw new Error('您没有传递root属性, 请重新传递')
- }
-
- // 2. 验证root能否正确获取到节点
- const rootHtml = document.querySelector(options.root)
- if (rootHtml == null) {
- // 手动返回一个错误
- throw new Error('您传递 root 的属性, 有问题, 请检查后重新传递')
- }
-
- // 3. 验证是否传递data
- if (options.data == undefined) {
- throw new Error('您没有传递 data 属性, 请重新传递')
- }
-
- // 4. 验证data是否为一个对象
- if (options.data.constructor !== Object) {
- throw new Error('您传递的 data 不是一个对象, 请重新传递')
- }
-
- // 5. 数据劫持
- // 存储一份最初的html文本
- const rootHtmlStr = rootHtml.innerHTML
- // 这里存储最开始的具有{{}}的HTML文本,
- // 如果不写, 第一次渲染完毕, HTML中就没有花括号, 第二次渲染正则没有办法正确匹配
- const _data = {}
- for (let k in options.data) {
- Object.defineProperty(_data, k, {
- get() {
- return options.data[k]
- },
- set(val) {
- options.data[k] = val
- // 5.2 数据更新后, 重新渲染页面
- randers(rootHtml, _data, rootHtmlStr)
- }
- })
- }
-
- // 5.1 首次执行, 渲染页面
- randers(rootHtml, _data, rootHtmlStr)
-
- // 6. 返回一个劫持后的数据
- return _data
- }
-
- function randers(root, _data, str) {
- // 准备一个正则
- const reg = /{{ *(\w+) *}}/g
-
- // 匹配到节点中所有的花括号, 存放在一个数组中
- const res = str.match(reg)
-
- // 遍历数组, 拿到每一个花括号
- res.forEach(item => {
-
- // 拿到花括号内的文本, 因为这是对象中的 key
- const key = reg.exec(str)[1]
-
- // 将原本花括号与内部文本, 全部替换为对象中实际的值
- str = str.replace(/{{ *(\w+) *}}/, _data[key])
- })
-
- // 重新将修改完毕的字符串, 渲染到页面
- root.innerHTML = str
- }
-
调用的
-
- // 我们后续使用, 就在这里
- const app = observer({
- root: '#app',
- data: {
- msg: '你好',
- name: 'QF001',
- age: 18,
- abc: '醒醒, 别睡了, 说你呢, 还睡'
- }
- })
-
<div id="root">div>
- const obj = {
- name: 'QF001',
- age: 18
- }
- const res = {}
- Object.defineProperty(res, 'name', {
- get() {
- return obj.name;
- },
- set(val) {
- obj.name = val;
- }
- })
-
- obj.newName = 'QF999';
- console.log(obj);
-
- document.querySelector('#root').innerHTML = `name: ${obj.name}`;

语法: Object.defineProperties(到那个对象, {
属性1: 配置项,
属性2: 配置项
})
- const obj = {
- name: 'QF001',
- age: 18
- }
- const res = {}
- Object.defineProperties(res, {
- name: {
- get() {
- return obj.name
- },
- set(val) {
- obj.name = val
- }
- },
- age: {
- get() {
- return obj.age
- },
- set(val) {
- obj.age = val
- }
- }
- })
-
- obj.newName = 'QF999';
- console.log(obj);
- document.querySelector('#root').innerHTML = `name: ${obj.name}`;

- const obj = {
- name: 'QF001',
- age: 18
- }
- const res = {};
- // 升级版(plus)
- for (let k in obj) {
- // k === 'name' 2. k === age
- console.log(k);
- Object.defineProperties(res, {
- // 对象内部直接写 k 会帮当成字符串, 所以可以写成 [k], 将他识别为变量
- [k]: {
- get() {
- return obj[k];
- },
- set(val) {
- obj[k] = val;
- }
- },
- })
- }
-
- obj.newName = 'QF999';
- console.log(obj);
- document.querySelector('#root').innerHTML = `name: ${obj.name}`;

- const obj = {
- name: 'QF001',
- age: 18
- }
-
- for (let k in obj) {
- Object.defineProperties(obj, {
- ['_' + k]: {
- // 我在我这个对象内把所有属性复制一份, 放在自己这个对象内部
- value: obj[k],
- writable: true
- },
- [k]: {
- get () {
- return obj['_' + k]
- },
- set(val) {
- obj['_' + k] = val
-
- document.querySelector('#root').innerHTML = `name: ${obj.name}`
- }
- }
- })
- }
- obj.newName = 'QF999'
- console.log(obj)
-
- document.querySelector('#root').innerHTML = `name: ${obj.name}`
