javascript高级编程

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<script type="text/javascript">

    var array=[1,2,3,4,5,6];
    var arr=array.map(function(item){
            return item*2;
        });
    alert(arr[0]);// 2
------------------------------------------------
    /////变量的作用域
    var variable="out";
    
    function func()
    {
        variable="in";
        alert(variable); 
    }
    func();              // 打印"in"
    alert(variable);   // 打印"in"
------------------------------------------------
    var object={
            field:"self",
            printInfo:function(){
                alert(this.field);    
            }
        }
    alert(object.field);  //"self"
    object.printInfo(); // "self"
    for(var key in object){
        alert(key+" : "+object[key]);
    }
------------------------------------------------
///JavaScript对象
    function Base(name) {
        this.name = name;
        this.getName = function () {
            return this.name;
        }
    }
    function Child(id) {
        this.id = id;
        this.getId = function () {
            return this.id;
        }
    }
    //将Child原型指向一个新的base对象
    Child.prototype = new Base("base");

    //实例化一个Child对象
    var c1 = new Child("child");
    //调用c1本身的getId方法
    alert(c1.getId()); //child
    //由于c1从原型链上“继承”到了getName方法,因此可以访问
    alert(c1.getName()); //base
    //////注解:由于遍历原型链时是由下而上的,所以最先遇到的属性值最先返回

    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.getName = function () {
            return this.name;
        }
        this.getAge = function () {
            return this.age;
        }
    }
    var tom = new Person("Tom", 30);
    var jerry = new Person("jerry", 40);
    ////注解:通过原型链,可以实现继承/重载等面向对象的js代码。当然这个机制并非基于类,而是基于原型
------------------------------------------------
    //定义个“类”,Address
    function Address(street, xno) {
        this.street = street || "黄泉路";
        this.xno = xno || 135;
        this.toString = function () {
            return "street:" + this.street + ",No:" + this.xno;
        }
    }
    //定义另外一个“类”,Person
    function Person(name,age,addr){
        this.name = name || "未知";
        this.age = age;
        this.addr = addr || new Address(null, null);
        this.getName = function () {
            return this.name;
        };
        this.getAge = function () {
            return this.age;
        };
        this.getAddr = function () {
            return this.addr.toString();
        };
    }
    //通过new 操作符来创建两个对象,注意,这个两个对象是相互独立的实体
    var jack = new Person("jack", 26, new Address("青海路", 123));
    var abruzzi = new Person("abruzzi", 26);
    //查看结果
    alert(jack.getName()); //jack
    alert(jack.getAge());  //26
    alert(jack.getAddr()); //street:青海路,No:123

    alert(abruzzi.getName()); //abruzzi
    alert(abruzzi.getAge());   //26
    alert(abruzzi.getAddr());  //street:黄泉路,No:135
------------------------------------------------
    ////函数作用域
    var str = "global";
    function scopeTest() {
        alert(str);
        var str = "local";
        alert(str);
    }
    scopeTest();
    //运行结果   undefined     local
    ///注解:因为在函数scopeTest的定义中,预先访问了未声明的变量str,然后才对str变量进行初始化,所以第一个alert会返回undefined错误。
    ///那为什么函数这个时候不会去访问外部的str变量呢?
    ///这是因为在词法分析结束后,构造作用域的时候会将函数内定义的var变量放入该链,因此str在整个函数内部是可见的(从函数体的第一行到最后一行),
    ///由于str变量本身是未定义的,程序顺序执行,到第一行就会返回为定义,第二行为str赋值
------------------------------------------------
    /////闭包
    ///由于在javaScript中,函数是对象,对象是属性集合,而属性的值有可以是对象,则在函数内定义函数成为理所当然,如果在函数func内部声明函数inner,然后在函数外调用inner,这个过程即产生闭包。
    var outter = [];
    function clouseTest() {
        var array = ["one", "two", "three", "four"];
        for (var i = 0; i < array.length; i++) {
            var x = {};
            x.no = i;
            x.text = array[i];
            x.invoke = function () {
                alert(i);
            }
            outter.push(x);
        }
    }
    //调用
    clouseTest();
    outter[0].invoke();
    outter[1].invoke();
    outter[2].invoke();
    outter[3].invoke();
    ///运行结果是  4   4   4   4   为什么不是0   1   2   3呢?
    //因为每次在迭代的时候,语句x.invoke=function(){alert(i);}并没有被执行,只是构建了一个函数体为“alert(i);”的函数对象而已。
    //如果每次迭代的时候语句x.invoke=function(){alert(i);}执行的话,则调用clouseTest()的时候则就会弹出对话框了,事实上却没有弹,证明没有执行
    //如何解决呢?
    var outter = [];
    function clouseTest2() {
        var array = ["one", "two", "three", "four"];
        for (var i = 0; i < array.length; i++) {
            var x = {};
            x.no = i;
            x.text = array[i];
            x.invoke = function (no) {
                alert(no);
            }(i);//调用
            outter.push(x);
        }
    }
    //调用
    clouseTest2();
------------------------------------------------
    ///封装
    var person = function () {
        //变量的作用域为函数内部,外部无法访问
        var name = "张飞";
        return {
            getName: function () { return name; },
            setName: function (newName) { name = newName; }
        }
    }();
    alert(person.name);//直接访问,结果为undefined
    alert(person.getName());  //张飞
    person.setName("关羽");
    alert(person.getName());  //关羽

    function Person() {
        var name = "张飞";
        return {
            getName: function () { return name; },
            setName: function (newName) { name = newName; }
        }
    };
    var john = new Person();
    alert(john.getName());  //张飞
    john.setName("john");
    alert(john.getName());  // john
    ////在不同的Javascript解释器实现中,由于解释器本身的缺陷,使用闭包可能造成内存泄露(严重影响用户体验)
    ///如:对象A引用B,B引用C,而C又引用A
------------------------------------------------
    ///【面向对象的JavaScript】
    //原型继承:js中的继承可以通过原型链来实现,调用对象上的一个方法,由于方法在javascript对象中是对另一个函数对象的引用,因此解释器会在对象中查找该属性,
    //如果没有找到,则在其内部对象prototype对象上搜索。由于prototype对象与对象本身的结构是一样的,因此这个过程会一直回溯到发现该属性,否则,报错
    function Base() {
        this.baseFunc = function () { alert("基础行为");}
    }
    function Middle() {
        this.middleFunc = function () { alert("中间行为");}
    }
    
    Middle.prototype = new Base();

    function Final() {
        this.finalFunc = function () { alert("最终行为");}
    }
    Final.prototype = new Middle();

    function Test() {
        var obj = new Final();
        obj.baseFunc();
        obj.middleFunc();
        obj.finalFunc();
    }
    Test();/////  基础行为   中间行为   最终行为 
    // 原型链示意图 见图  P76 

    ///new 操作符
    function Shape(type) {
        this.type = type || "rect";
        this.calc = function () { return "calc," + this.type;}
    }
    var triangle = new Shape("triangle");
    alert(triangle.calc());

    var circle = new Shape("circle");
    alert(circle.calc());
    ////注解:Javascript和其他面向对象的new操作符不一样,triangle,circle可能在Java中是Shape对应的具体对象,但是在js中并非如此(new比较特殊)
    ////首先,创建一个空对象,然后用函数apply方法,将这个空对象传入作为apply的第一个参数以及上下文参数,这样的函数内部的this将会被这个空的对象所替代。
    var triangle = new Shape("triangle");
    ///相当于下面的代码
    var triangle = {};
    Shape.apply(triangle, ["triangle"]);
------------------------------------------------
    ///柯里化
    //柯里化就是余下将函数的某些参数传入,得到一个简单的函数,但是预先传入的参数被保存在闭包中,因此会有一些奇特的特性
    var addr = function (num) {
        return function (y) { return num + y;}
    }
    var inc = addr(1);
    var dec = addr(-1);

    alert(inc(99));  //100
    alert(dec(101));  // 100

    alert(addr(100)(2)); // 102
    alert(addr(2)(100)); // 102
------------------------------------------------
    //开发智力(坑爹)
    //函数的不动点
    function fixedPoint(Func, first) {
        var tolerance = 0.00001;
        function closeEnough(x, y) {
            return Math.abs(x - y) < tolerance;
        };
        function Try(guess) {
            var next = Func(guess);
            //alert(next+" "+ guess);
            if (closeEnough(guess, next)) {
                return next;//返回小的
            }
            else {
                return Try(first);//递归调用
            }
        };
        return Try(first);
    }
    //数层嵌套函数
    function sqrt(x) {
        var Func = function (y) {
            var div = function (a, b) { return (a + b) / 2; }
            return div(y, x / y);
        }
        return fixedPoint(Func, 1.0);
    }
    alert(sqrt(100));
------------------------------------------------///原型链:由于原型对象本身也是对象,它也有自己的原型,而他自己的原型对象又可以有自己的原型,这样就组成了一条链,这个链就是原型链
    ///Javascript引擎在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回undefined。原型链一般是实现为一个链表,这样就可以按照一定的顺序来查找
    var base = {
        name: "base",
        getInfo: function () {
            return this.name;
        }
    }
    var ext1 = {
        id: 0,
        __proto__:base
    }
    var ext2 = {
        id: 9,
        __proto__:base
    }
    alert(ext1.id);      //0
    alert(ext1.getInfo()); //base
    alert(ext2.id);    //9
    alert(ext2.getInfo()); // base
    //原型链图 见P105
    var base = {     ///(原型对象)
        name: "base",
        getInfo: function () { return this.id + " : " + this.name;}
    };
    var ext1 = {   ///(原始对象)
        id: 0,
        __proto__:base
    };
    alert(ext1.getInfo()); // 0 : base
    ///注解:getInfo函数中的this表示原始的对象,并非原型对象,上例中的id属性来自于ext1对象,而name来自base对象
    ///如果没有显示的声明自己的”__proto__“属性,这个值默认的设置为Object.prototype,而Object.prototype的“__proto__”属性值为“null”,标志着原型链的终结
------------------------------------------------
    ///执行期上下文:按照ECMAScript的规范,一共有三种类型的代码,全局代码、函数代码、以及eval代码
    ///this上下文:ECMAScript的规范中对this的定义为:this是一个特殊的对象,与执行期上下文相关,因此可以称为上下文对象。
    ///this是执行期上下文对象的一个属性(执行期上下文对象包括变量对象、作用域链以及this)。执行期上下文对象有三类,当进入不同的上下文时,this的值会确定下来,并且this的值不能更改。
    ///在执行全局代码时,控制流会进入全局执行期上下文,而在执行函数时,又会有函数执行期上下文
    var global = this;
    var tom = {
        name: "Tom",
        home: "desine",
        getInfo: function () {
            alert(this.name + ", from " + this.home);
        }
    };
    tom.getInfo();   // Tom,from desine

    var jerry = {
        name: "Jerry",
        getInfo:tom.getInfo
    };
    jerry.getInfo();   // Jerry,from undefined
    
    global.getInfo = tom.getInfo;
    global.getInfo();   // ,from undefined
</script>
</head>

<body>
</body>
</html>

 

posted on 2014-08-27 17:58  小兵程序  阅读(359)  评论(0编辑  收藏  举报