js动态加载脚本之实用小技巧

  最近我们公司的iClient产品需要改动,由于我们的包大概有1M了,用户在使用的过程中如果网速不是很好的话,加载的就比较慢,用户体验就不好,上面要求用户初始化的时候只有基础包,比较小,当用户用到哪一块功能就加载哪块的功能,这样体验上要好得多,但是我们的用户已经有很多了,那么我们就不能让用户改变以前的代码,只能让用户把包替换一下,这里研究了几天研究了一种办法和大家分享一下。对于做产品的朋友可能会有帮助吧!

  对于产品包来说,无非就是N多的类。用户一般使用的时候都是new一个对象,然后开始使用它!比如我们有一个Person类,这里就会涉及到当浏览器运行到var person = new Person()这里时,其实内存里面还没有这个类,我们并没有在一开始就导进来,但是如果没有的话浏览器肯定会报错,那我们在new之前加一句代码来导包,这样不就是需要更改用户的源代码了吗?肯定不可取。我们需要在浏览器new对象的时候把对应的类导进来,而又不改变任何源代码,如何做到?

  我们可以在基础包里面对每一个类写一个假的类,但是命名空间、类名必须都是一样的,但类里面除了构造函数什么都没有,这样假类就很小,基本不会使基础包的大小改变多少,这样在浏览器运行到如var person = new Person()这一句的时候至少不会报告错误,但是生成的对象person是假的,不可用的,我们得想办法让它变成真的,怎么才能让new出的对象不是自己而是其他的对象呢?

  我尝试了很多种办法,比如在构造函数里面改变过this.__proto__.constructor、this.__proto__、this等手段,希望最后new出来的对象不是自身,而和new Person(真的)一样,但是你可以调试发现没法做到一模一样,最后无意间发现在构造函数里面使用return就可以改变new出来的对象,如下面new Person()出一个对象。

        function Person()
        {
            return new Date();
        }

  你会发现new出来的不是Person的对象,而是一个Date对象,而且和new Date()出来的对象一模一样,这是js这门语言故意这样设计吧!也不知道最开始的目的是啥!如果使用return;或者return null;最后new出来的对象还是本身。这样第一个问题就解决了,可以new出一个非自身的对象。

  继续讨论,现在我们new出来的对象需要时真的那个类,而不是那个假的类,但是两个类的命名空间和类名都是一样的,这可怎么办,其实大家都知道所有的类无非就是window的属性而已,其实都是指针,我把指向的部分改变后不久实现了吗?

  我们先需要写一个真的类,创建一个Person.js文件,打开后写入如下代码:

function Person(name,age){
    this.name =  name;
    this.age = age;
    this.getName = function(){
        return this.name;
    }
    this.getAge = function(){
        return this.age;
    }
}

  这是一个真的类,有name和age两个属性以及getName()和getAge()两个方法。在在同样的文件夹下创建一个html文件,代码如下:

<html>
<head>
    <title></title>
    <script type="text/javascript" src="loadJS.js"></script>
    <script type="text/javascript">
        function init()
        {
            var person = new Person("Bill",23);
            var name = person.getName();
            var age = person.getAge();
            alert(name + "_" + age);
        }
        function Person(name,age)
        {
            loadJS("idPerson","Person.js");
            return  new Person(name,age);
        }
    </script>
</head>
<body>
    <button onclick="init()">测试</button>
</body>
</html>

  这里有一个loadJS.js文件,这是一个动态同步加载js文件的一个包,我自己写的,很简单,里面的内容详见《js动态加载脚本》里面的第六种方法里有源代码,其实就一个方法loadJS(id,url)。上面代码已经有一个假的Person存在了,里面有两句代码,第一句是加载真的Person,第二句是返回一个Person对象,当我们调试的时候你会惊奇的发现,当真的Person加载进来后Person这个类就变成了真的类,而假的类在new以后就没有了,因为没有指针指向它了,它接下来就会被回收机制给回收掉,new玩后发现person就成为了真的那个Person的对象,当你再次new Person()的时候发现直接就是真的Person对象了,因为已经加载过一次了。

  我们仔细思考一下,如果Person这个类用到了我们其他没加载的类,浏览器也会先寻找到假的那个类,再次去加载需要的类,这就形成了一个循环,需要什么类的时候再加载什么,不会多加载任何一个多余的类。前提是你得每一个类对应一个js文件。你也可以分成多少个模块,每个模块里面有多个类,那么每一次去加载就会加载一个模块,一个模块加载进来后会替换掉其中一部分假类。无论怎么设计都很方便。

  好了,所有问题都解决了,我们需要把假的类封装进我们的产品包,然后让用户把这个包替换掉,用户不需要改变任何以前项目的源代码,就可以做到动态加载需要的脚本。这个办法是不是很好用?好用就帮我顶一下!

posted on 2013-03-08 14:26  追梦的远远  阅读(2737)  评论(8编辑  收藏  举报

导航