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>
我是一名小兵,总有一天我会成为将军