- 几个基础知识点
- 数据代理
- 数据劫持
- 完整demo
一、几个基础知识点
1.普通函数和箭头函数的区别
如上图所示,a函数定义在全局,其作用域链,只有GO对象,当其执行的时候会临时产生一个aAO对象,所以b函数的作用域链就是 aAO -> GO
函数每次执行都会产生一个新的AO对象挂在作用域链头部,函数被解释执行的时候,其内部标识符的检索都是在作用域链上检索的。
根据以上理论,我们来执行b函数。
控制台输出如下:
为什么b函数中看到的this是window呢?是因为其顺着作用域链找,bBO -> aAO -> GO,只有GO上有this,就是window。
当然对于普通函数,我们可以改变其this指向:
控制台输出如下:
于是我们得到一个结论:
函数执行生成的临时AO对象中,包含了arguments隐式变量来保存实参列表。
函数执行看到的this变量,可以修改,通过对象调用,call,apply来修改。
但是,但是,但是。。。。
箭头函数,它就不是这样的。。。
控制台输出:
箭头函数,没有arguments隐式变量了。而且,this它居然修改不了。。
那么说白了,this只能在其作用域链上找了,生成的临时AO对象上没有this,没有this。
是否有arguments隐式变量 | 是否能改变this指向 | |
普通函数 | 是 | 是 |
箭头函数 | 否 | 否 |
2.闭包
由于plus,minus,showCount三个函数的作用域链中有aaa的AO对象,所以当他们被返回后,形成了闭包。
3.defineProperty函数的使用
但是其实除了这样给对象加属性外,我们也可以通过defineProperty来给对象加属性。
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
title>demo01-defineProperty的使用title>
head>
body>
script type="application/javascript">
// defineProperty()
let obj = {
name: 'zhangsan',
age: 33,
showInfo() {
console.log(this.name + "--" + this.age)
}
}
obj.showInfo();
Object.defineProperty(obj, 'ccc', {
value: 10,
enumerable: true, // 是否能枚举
configurable: true, // 是否能删除
writable: true // 是否能写入
})
// 枚举
var keys = Object.keys(obj);
console.log(keys);
// 写入
obj.ccc = 100;
console.log(obj);
// 删除
delete obj.ccc;
console.log(obj);
script>
body>
html>
上述代码控制台输入如下:
其实这样的话,定义属性和我们直接写属性没什么太大区别,关键是下面这样的写法:
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
title>demo01-defineProperty的使用title>
head>
body>
script type="application/javascript">
// defineProperty()
let obj = {
name: 'zhangsan',
age: 33,
showInfo() {
console.log(this.name + "--" + this.age)
}
}
let ccc 服务器托管网= 10;
Object.defineProperty(obj, 'ccc', {
// value: 10,
enumerable: true, // 是否能枚举
configurable: true, // 是否能删除
// writable: true, // 是否能写入
get: function proxyGet() {
return ccc;
},
set: function proxySet(value) {
ccc = value;
}
})
console.log(obj.ccc);
obj.ccc = 100;
console.log(obj.ccc);
console.log(obj);
script>
body>
html>
注意,如果我们要定义属性的get/set,那么就不能定义value和writable了,否则会报错。
此时我们对属性ccc的写入和读取将走get/set方法了。
控制台输出如下:
这个ccc属性的三个点,是不是特别想我们使用vue的时候点开的组件对象里面的一些属性。
在这里我插一句,我点开set/get给大家看看,其实能看见[[scopes]]作用域链了。
如下图:
当然,这里我们看见了,set/get函数定义的时候的作用域链[[scopes]],其实是SO -> GO,这个SO其实就是外层包裹的script标签。
可以理解成,script标签执行流程就像一个函数执行一样,也会产生作用域对象挂在[[scopes]]上。
二、数据代理
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
title>demo01-vue简单使用title>
script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js">script>
head>
body>
div id="app">
h3>姓名:{{name}}h3>
h3>年龄:{{age}}h3>
button @click="agePlusOne">年龄+1button>
div>
script type="application/javascript">
let vm = new Vue({
el: '#app',
data(){
return {
name: '张三',
age: 33
}
},
methods: {
agePlusOne(){
this.age ++;
console.log(this)
}
}
});
script>
body>
html>
点击按钮,我把Vue对象打印出来:
可以清晰的看到,我们配置的data对象中的属性都被定义在了Vue组件对象中。
起码,这里看到了,vue做了数据代理,我们在组件对象中对data中同名属性的set和get都走了其对应的代理方法。
三、数据劫持
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
title>demo01-数据劫持title>
head>
body>
div id="app">
div>
script type="application/javascript">
function setAppInnerText (value) {
document.querySelector("#app").innerText = value;
}
let obj = {
name: '张三',
age: 100,
showInfo() {
return this.name + "---" + this.age;
}
};
setAppInnerText(obj.showInfo())
// 数据劫持
Object.keys(obj).forEach(key => {
let value = obj[key];
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
set(newValue) {
if(newValue === value) {
return ;
} else {
value = newValue;
setAppInnerText(obj.showInfo());
}
},
get() {
return value;
}
})
})
obj.age = 1000;
script>
body>
html>
上面的代码,就是数据劫持,每次属性设置的时候,都触发了setAppInnerText函数的调用。
上述代码执行完之后,只要我们对obj对象的属性进行修改,都会触发页面的变化。
四、完整demo
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
meta http-equiv="X-UA-Compatible" content="IE=edge">
meta name="viewport" content="width=device-width, initial-scale=1.0">
title>data_observertitle>
head>
body>
div id="root">
a = {{a}}
br>
b = {{b}}
div>
script>
function Vue(config) {
this._data = config.data;
// 数据代理 方便程序员操作
for (let key in config.data) {
Object.defineProperty(this, key, {
enumerable: true,
get: function proxyGet() {
return this._data[key];
},
set: function proxySet(value) {
this._data[key] = value;
}
})
}
this.mounted = false;
if (config.el) {
this.$mount(config.el);
}
}
Vue.prototype.$mount = function (id) {
if (!this.mounted) {
this.originInnerHtml = document.getElementById(id).innerHTML;
// 编译模板生成render
let _self = this;
function render() {
let innerHtml = _self.originInnerHtml;
for (let key in _self._data) {
innerHtml = innerHtml.replaceAll('{{' + key + '}}', _self._data[key]);
}
document.getElementById(id).innerHTML = innerHtml;
}
// 数据劫持
for (let key in this._data) {
let value = this._data[key];
Object.defineProperty(this._data, key, {
enumerable: true,
configurable: true,
get: function getObserver() {
return value;
},
set: function setObserver(newValue) {
if (value !== newValue) {
value = newValue;
render();
}
}
})
}
// 执行render
render();
this.mounted = true;
服务器托管网 }
}
let config = {
el: 'root',
data: {
a: '牛逼的消息',
b: '学习vue2底层实现'
}
};
let vm = new Vue(config);
script>
body>
html>
控制台打印如下:
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
引言 现在全社会都在搞数字化转型,从政府到企业,那么为什么要进行数字化转型呢?本质上还是社会治理和企业经营难度变得更大了。 以企业来说,转型的目标是为了实现有质量的活着,比如能赚更多的钱或者持续保持稳健运营,转型的核心是期望借助数字化技术构建一个管理体系,以应…