1.MVVM
最近公司网页开始使用VUE框架了,由于本人才疏学浅,于是问了句,vue好上手么?我们的大哥大手一挥,好上手的很!跟小程序差不多!但是由于当时我连小程序也没有开发过,所以并不能有所体会,不过现在我多少明白了些其中的奥妙。
不论是小程序,还是VUE,其实都采用了MVVM的开发模式,那么什么是MVVM呢?
MVVM,即Model-View-ViewModel的缩写,Model即数据模型,用于存储数据,View即展示视图界面和进行UI交互操作,ViewModel即Model和View之间的一段桥梁
在网页开发时,浏览器在接收到返回的HTML界面后,会先生成相应的DOM树,然后在此基础上渲染成我们直观能看得见的网页。DOM,即document object model,是一个跨平台的应用程序接口,而js的核心其实就是在操纵DOM节点来达到网页的动态效果。但是随着项目工程的规模日益增大,人们发现代码写起来过于繁琐,于是就想到把数据(Model)用纯javascript对象表示,而View负责展示,两者做到最大程度的分离
而ViewMode起到的作用就是把Model的数据同步到View显现出来,再将View的修改同步回Model
如此以来,通过ViewModel,我们编写网页交互时的关注点从如何操作DOM到了如何更行js对象的状态,这使得工作量大大减少了!
这就是MVVM的设计思想:关注Model的变化,让MVVM框架去自动更新DOM的状态,从而把开发者从操作DOM的繁琐步骤中解脱出来!
将model的某一个变量绑定到视图层上,借助MVVM的帮助,我们使用双花括号{{}}即可!这实在是很棒棒!
2.回调函数
在翻阅小程序的官方文档的过程中,我发现了“回调函数”这个词十分常见,那么到底什么是回调函数呢?我在B乎的两个高赞回答中找到了答案!
首先是用户no.body的回答,他指出编分为两类,系统编程和应用编程。所谓系统编程,就是编写库;而应用编程就是利用写好的各种库来编写应用,系统程序员会在库中留下一些接口,即API,以供应用程序员使用。当程序跑起来时,应用程序一般会调用库中预先写好的函数。而有些库函数要求应用先传递给它一个函数,好在合适的时候调用,以便完成目标任务,这个先通过应用程序员手动编写传入的,后又通过库中预先编好的函数所调用的函数,就称之为回调函数
使用python作为例子来讲的话是这样的:
#回调函数1,使一个数字翻倍
def double(x):
return x*2
#回调函数2,使一个数字翻成原先的四倍
def quadruple(x):
return x*4
#中间函数,接受一个生成偶数的函数作为参数,返回一个奇数
def getOddNumber(k,getEvenNumber):
return 1+getEvenNumber(k)
#起始函数,这里即位main函数
def main():
k=1
i=getOddNumber(k,double)
print(i)
i=getOddNumber(k,quadruple
print(i)
#输出结果为3和5
常溪玲的回答则巧妙地对回调函数的概念进行了其它方面的补充,原回答如下:
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。回答完毕。
下面我们回到小程序中康康回调函数的功力!
在小程序的官方文档中的响应的数据绑定模块中,举了下面这样一个例子
<view>Hello {{name}}!</view>
<button bindtap="changeName">Click me!</button>
const helloData = {
name: 'WeChat'
}
// Register a Page.
Page({
data: helloData,
changeName(e) {
// sent data change to view
this.setData({
name: 'MINA'
})
}
})
单击按钮后,页面的显示内容会变成”MIna",这个结果估计没有任何编程基础的人也能看得出来,不过这其中的内涵却包括了目前为止提到的两大内容,MVVM和回调函数。
在视图层中,{{name}}绑定了位于Page对象中的data对象中的name属性,这就是MVVM的作用
接下来,changeName是用户定义的回调函数,使用bindtap绑定了changeName这个函数,即注册回调函数,而中间函数并没有显现出来,其实就是单击事件触发的函数,当用户单击按钮后,回调函数条件被触发,这时系统会调用changeName,这一过程即是响应回调函数。
顺便一提,changeName中的参数e是event的缩写,包含了事件触发时的一些信息,其信息都保存在window.event之中,在本例中并没有用到它。
3.箭头函数
不知道为什么,小程序代码中this的出现频率生TM高,而this的绑定问题一直是javascript的一大难题。
关于this的绑定问题,可以参考我写的js进阶开发指南,在ES5之前,为了防止函数回调时产生this绑定对象丢失的问题,程序员们不得不用that=this这种很微妙的办法来解决该问题,不过在ES6出现的箭头函数解决了这一大问题。
MDN对于箭头函数的this问题是这样描述的:箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。即箭头函数的this是基于词法作用域的,它会继承父级中this所指向的对象。
下面是一个典型的例子!
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| 正确地指向 p 实例
}, 1000);
}
var p = new Person();
在延时函数中setInterval,第一个参数是一个箭头函数,其内部的this继承了词法作用域中的父级元素的this,即setInterval的this,而setInterval的调用对象是person对象,所以其this指向person对象,因此箭头函数中的this就指向了person对象,且该绑定不会更改!(即使使用call()也没用!!)。如果不用箭头函数,this会泄露到全局对象!
下面再贴一波箭头函数的基础语法~
(参数1, 参数2, …, 参数N) => { 函数声明 }
//相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }
(参数1, 参数2, …, 参数N) => 表达式(单一)
// 当只有一个参数时,圆括号是可选的:
(单一参数) => {函数声明}
单一参数 => {函数声明}
// 没有参数的函数应该写成一对圆括号。
() => {函数声明}