JavaScript必知必会(一)

1.原生js实现路由

前端路由,是指随着浏览器地址栏的变化,展示给用户的页面也不相同。

传统的网页根据用户访问的不同地址,浏览器从服务器获取对应页面内容展示给用户。这样造成服务器压力比较大,而且用户访问速度也会比较慢。在这种场景下,单页面应用出现了。

单页面应用,就是只有一个页面,用户访问一个网址,服务器返回的页面也只有一个。地址栏内容改变显示不同页面由前端路由来实现。

法一:hash+hashchange

我们通过读取location.hash和监听hashchange事件来实现路由。

首先定义一个Router对象:

function Router() {
    this.currentUrl = '';
    this.routes = {};
}

Router.prototype.route = function (path, callback) {
    this.routes[path] = callback || function () {};
}

Router.prototype.refresh = function () {
    this.currentUrl = location.hash.slice(1) || '/';
    this.routes[this.currentUrl]();
}

Router.prototype.init = function () {
    window.addEventListener('load', this.refresh.bind(this), false);
    window.addEventListener('hashchange', this.refresh.bind(this), false);
}

然后创建一个实例:

对应的html为:

上面就实现了不同路由展示不同的内容。支持浏览器的前进和后退,很好地解决了前后端分离的问题。

法二:history.pushState()+popstate

跟之前的方法一样,pushState()修改url的地址,popstate监听地址的改变,不同的是,手动的进行pushState()并不会触发popstate事件。

2.原生js实现对象属性监听器

可以使用defineProperty来实现对象属性的监听。defineProperty是ES5属性,大部分的使用场景都没有问题。现在首先来看看它的用法:

各参数的作用分别是:

obj是需要定义属性的那个对象。

prop是需要被定义或者修改的属性名。

descriptor是定义属性prop的描述。

下面来详细看看descriptor的各属性可以做什么。

value 设置属性的值

在代码中,我们定义了bob的一个属性name,value为bob。然后试着给name属性赋值Bob,却发现属性没有发生变化。这是为什么?原来只有把writable修饰符设置为true时,这个属性才能被修改。

writable 当该属性为true时,该属性的才会被赋值运算符改变。默认为false。

依然是上面的例子,这次成功修改了bob的name属性。

enumerable 设置该属性是否是可枚举类型。默认为false。

只有enumerable属性设置为true时,这个属性才可以用for(prop in obj)Object.keys()枚举出来。

上面的代码为bob添加了两个属性,一个是可枚举属性age,一个是不可枚举属性math。

configurable 该属性决定了对象的属性是否可以被删除,以及除writable外的其他特性能不能被修改;并且修改writable时只能修改为false。

get 给属性提供的getter方法,如果没有getter则返回undefined,该方法返回值被用作属性值。

set 给属性提供的setter方法,该方法接受唯一参数,并将该参数的新值分配给该属性。

getset属性不能和valuewritable属性一起出现,否则会报错。

在上面的代码中,我们为bob的weight属性添加了setget方法,现在读取和修改属性时都会打印出提示文字。注意,为什么需要一个中间变量weight来保存weight属性值。因为如果我们直接在getset方法里访问bob.weight,则又会触发wegihtget方法,会导致程序陷入死循环中。

介绍完defineProperty的用法,属性对象监听器的写法就呼之欲出啦。我们只需要重写对象属性的set方法,就可以在对象的属性发生变化时调用我们设置的回调函数了。我们来完成一个函数,实现对对象属性的监听。

我们的监听器已经实现好了,其实,defineProperty非常强大,vuejs的数据绑定也是基于该方法实现的。

3、参考文献

原生js实现前端路由arrow-up-right

理解JavaScript的Object.defineProperty()函数arrow-up-right

Last updated