About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Jul

    24

    让 JS 安全的运行在 AS 里

    • 1 Comments
    • Flash Platform

    什么时候都要记得真机调试,否则会死的很惨。先上一段代码:

    package
    {
        import flash.display.Sprite;
        import flash.events.LocationChangeEvent;
        import flash.media.StageWebView;
        //一个 AIR for iOS 的主类
        public class MainTest extends Sprite
        {
            private const view:StageWebView = new StageWebView(true);
            
            public function MainTest()
            {
                super();
                test();
            }

            private function test():void
            {
                view.addEventListener(LocationChangeEvent.LOCATION_CHANGING, locationChaningHandler);

                var xml1:XML = 
                    <script type="text/javascript">
                        var name = prompt("写点什么?","")//当运行的时候我们点击取消   
                        if(name)
                            alert("1:" + name);
                        else
                            alert("2:" + name);
                    </script>;

                view.loadString(xml1.toXMLString());
            }

            private function locationChaningHandler(e:LocationChangeEvent):void
            {
                //我们并不是为了跳转网页,所以这里中止跳转
                e.preventDefault();
            }
        }
    }

    在桌面 AIR 环境中测试,点击取消,输出"2:null",看起来一切良好。可是当连接上手机后,在真机测试环境中测试发现同样的操作结果输出了“1:null”。这和 JS 的自动转型规则完全不一样了,也就是这种 JS 代码运行在 AS 里面它显的那么的不安全。

    将上面的 XML 改为如下这个样子,让 JS 代码运行在一个函数里:

    var xml1:XML = 
        <script type="text/javascript">
            function run()
            &#x7B;
            var name = prompt("写点什么?","");                            
            if(name)
                alert("1:" + name);
            else
                alert("2:" + name);
            &#x7D;
            run();
        </script>;

    现在无论是在桌面上测试,还是在真机环境下,它们都保持输出一致了,都是“2:null”。其中 &#x7B; 与 &#x7D; 两个字符是在 E4X 里 XML 代表的左右大括号转字义符的实体字符。

    也可以将 JS 代码完全剥离 AS,使用一个纯文本文件,然后使用 Embed 标签嵌入。但这个方法对于纯 Flash IDE 开发人员并不适用,因为 Embed 标签需要 FLEX SDK 支持。

    JS 文件(因为是在纯文本文件中,所以左右大括号就不需要转义了;而且仍然要在函数中运行,否则它依然是不安全的,会和桌面测试环境不一致):

    <script type="text/javascript">
        function run()
        {
            var name = prompt("写点什么?","");                            
            if(name)
                alert("1:" + name);
            else
                alert("2:" + name);
        }
        run();
    </script>;

    然后 AS 代码也稍作修改:

    //这里必须写上 mimeType="application/octet-stream"
    [Embed(source="/assets/js/run.js", mimeType="application/octet-stream")]
    static private const JS:Class;

    static public const js:String = new JS();

    private var view:StageWebView = new StageWebView(true);

    private function test():void
    {
        view.addEventListener(LocationChangeEvent.LOCATION_CHANGING, locationChaningHandler);
        view.loadString(js);
    }

    备注:使用静态嵌入的 JS 文件会有两个缺点:1、不能动态的生成 JS 代码了。2、不能使用 AS 的特性了,比如 XML 的绑定语法之类的都不能用了。

    May

    25

    <script>
    var f = function fact(x){
        if(<=1)
            return 1;
        else 
            return x * fact(x-1);    
    }
    alert(f(2));
    alert(fact(2));
    </script>

    这是一个看起来像是有命名的函数直接量。为什么说它看起来像是有命名呢?因为要分情况。

    在 IE 8 中测试结果发现它真的就像命名函数一样,甚至可以将 alert(fact(2)); 提前到函数直接量表达式的前面;

    但在 Google Chrome 35 中上面的代码最后一行会产生一个运行时错误(因为访问了一个不存在的定义)。如果将上面代码中的最后两种交换位置,在 Chrome 35 中不会输出任何内容,因为当 alert(fact(2)); 运行产生错误时会静默失败,然后后续代码会全部中止运行。

    而事实上这种看起来好像有命名的函数直接量只允许 JS 1.5 后的版本中使用,并且是只允许的在函数体内用这个名字来引用自身(比如类似上面的嵌套函数)。

    所以,如果不是想要展现自己在特定平台开发的编程技巧,就算有脚本标准,最好也不要使用奇葩的写法(因为不同浏览器厂商未必都遵循标准),除非那个脚本语言是被垄断性的只能运行在特定的平台,比如 ActionScript。

    May

    25

    使用 with 语句虽然能使用代码变简洁,减少代码的输入量,但它并不被开发者们推荐(甚至在 ECMAScript 5 的严格模式中遭到了禁用)。因为在使用 with 语句时,代码的运行速度会比不使用时更慢。并且在 with 语句内定义的变量作用域情况比较复杂,也会让初学者迷惑。看以下样例代码:

    <script>
    function fun(){
        var x = 9;
        var y = 10
        with(Math){
            var larger = max(x,y);//显示声明,这个变量是定义在函数内的,作用域是在函数层级,与x、y相同。
        }
        alert(larger);//10
        alert(Math.larger);//undefined;虽然在with内声明,但并不属于with的目标对象。
    }
    fun();
    alert(larger);//访问不存在的变量,这里就会产生一个异常,因为在函数外没有定义。
    </script>

    然后再试一下隐式声明:

    <script>
    function fun(){
        var x = 9;
        var y = 10
        with(Math){
            larger = max(x,y);//隐式声明一个变量时它的作用域是全局的
        }
        alert(larger);//10
        alert(Math.larger);//undefined;
    }
    fun();
    alert(larger);//10,访问全局的变量。
    </script>

    备注:由于 AS 与 JS 遵循相同的 ECMA-262 标准,尤其是熟悉和精通 AS1、AS1.1、AS2 的人可能会对这种 JS 的作用域更熟悉(AS1.1 与 JS 之间完全可以轻松的共享代码)。