免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3495 | 回复: 2
打印 上一主题 下一主题

悟透JS [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-01 15:09 |只看该作者 |倒序浏览
本帖最后由 cu_Cbear 于 2011-12-01 15:10 编辑

悟透JS










1, 在js中 “123” == 123,“0123” == 0123,”123” === 123,”123” !== 123,”123” != 123 有什么不同?
“123” == 123的值为true,”0123” == 0123的值为false,因为js中将“0”开头的整数常量当八进制数处理。如undefined==null返回true。
“123” == 123的值为true,”123” === 123的值为false,因为js中“===”表示全等,也就是数据值与数据类型都必须相等才是true。
”123” !== 123的值为true,”123” != 123的值为false,因为“!==”表示不全等,“!=”表示值不等。不全等即值或类型不相等,不全等相当于 ”123” !== 123 || typeof(“123”) != typeof(123)。全不等即值和类型都不相等,全不等相当于”123” !== 123 && typeof(“123”) != typeof(123)。

2, Underfinedhe和null
Undefined:代表一切未知事物,啥都没有,无法想象,代码更无法去处理。
Null:有那么一个概念,但没有东西,无中似有,有中还无,虽不可想象,但代码可以去处理。
Typeof(undefined)返回也是undfined。
Typeof(null)返回object。
Undefined == null 返回true

3, Function 函数
Js中创建function函数类型。定义式和变量式。
  1. <script language="javascript" type="text/javascript">

  2. function myfun(){
  3. alert("hello");
  4. }

  5. myfun();//输出word

  6. function myfun(){
  7. alert("word");
  8. }

  9. myfun();//输出word

  10. </script>

  11. <script language="javascript" type="text/javascript">

  12. var myfun = function (){
  13. alert("hello");
  14. }

  15. myfun();//输出hello

  16. myfun = function (){
  17. alert("word");
  18. }

  19. myfun();//输出word

  20. </script>
复制代码
Js执行引擎并非一行一行地分析代码和执行程序的,而是一段一段地分析执行的。而且在同一段程序执行中,定义式的语句会被提取出来优先执行,函数定义完之后,才会顺序执行其他语句代码。
上面列子在定义式中,第一次定义的函数myfun被第二次定义的函数myfun覆盖,所以两次执行的是第二次的函数,而在变量式定义函数myfun中,函数看做变量改变过程来执行。

4, 作用域链
代码的时空:相对论告诉我们,时间和空间是不可分割的。我们只有把时间和空间结合起来才能确定一个事件发生的准确坐标。确定一个变量数据的执行时空,就是确定代码变量数据执行的上下文环境,即确定变量数据的作用域。
  1. <script type="text/javascript" language="javascript">

  2. var yourName = "you";
  3. myName = "me";

  4. function changeName(){
  5. alert(myName+"==="+yourName);//me===undefined
  6. var yourName = "your";
  7. myName = "my"
  8. alert(myName+"++++"+yourName);//my++++your
  9. }
  10. alert(myName+"---"+yourName);//me---you

  11. </script>
复制代码
在js中全局环境就是一个对象,这个对象就是js运行环境的根。对于浏览器中的js来说,这个根对象就是window对象对全局的js来说window对象就相当于当前作用域。
如:var yourName = "you"; //window作用域的一个变量yourName
myName = "me"; //window对象的一个属性myName
对于全局的js来说,加不加var都一样,不过在子作用域里就不一样了。
Var定义的是该作用域上的一个变量。而没有var标识的变量则需要在作用域链上查找变量,如果从子作用域到根定义中没有查找到该变量,则该变量为该作用域上的变量。反之既然。
在js中当代码运行进入一个函数时,js会创建一个新的作用域来作为当前作用域的子作用域。然后将当前作用域切换到这个新的子作用域,开始执行函数的逻辑。而js执行引擎会把此函数内的逻辑代码当做一个单元来分析执行。
Js执行步骤:
第一步:预编译分析,建立可调用的函数变量。将定义式函数直接创建为作用域上的函数变量,并将其值初始化为定义的函数代码逻辑;对于var标识的变量,将其初始化值为undefined。
第二步:解释执行代码,在预编译的环境中执行逻辑代码。当遇到函数名或变量名的使用时,js执行引擎会首先在当前作用域查找函数或变量,如果没有就到上层作用域查找,以此类推。对于子作用域和父作用域有相同的变量时,根据var来定义作用域。用var定义的变量只对本作用域有效,尽管父作用域中有同名变量都与本作用域变量无关,退出本函数(本作用域)后,var就失效了。
Js在执行函数时都会产生一个子作用域,退出函数后,这个子作用域就消失了,下次调用该函数是又会有另一个子作用域产生。而在该函数内在调用另外函数时,又会在该函数作用域的基础上产生一个子作用域,从而形成了一个作用域链。作用域链的根是js的根。
  1. 5, Caller

  2. function callerA(){
  3. alert("caller is "+callerA.caller);
  4. }

  5. function callerB(){callerA();}

  6. callerA();//caller is null
  7. alert(callerA.caller);//null

  8. callerB();//caller is callerB(){callerA();}
复制代码
caller是函数自身的一个属性,表示调用当前函数的父函数。如果caller值为null,表示函数没有被调用者或是被全局函数调用。函数的caller值是动态变化的,函数的caller的初始化值都是null。当调用一个函数数,代码已经运行在函数体内,被调用函数的caller属性就会设置为当前函数。在退出函数调用时,caller值又恢复为null。

6, 对象和函数的调用
  1. <script type="text/javascript" language="javascript">

  2. var obj = {};//var obj = function(){}
  3. obj.aproperty = "a property";
  4. obj.amethod = function(){alert("a method");}

  5. alert(obj["aproperty"]);
  6. obj["amethod"]();

  7. for(var i in obj){
  8. alert(i+"=="+typeof(obj[i]));
  9. }

  10. </script>

  11. Js中的函数和对象既有对象特性和数组特性。
  12. 7, This 自我
  13. <script language="javascript" type="text/javascript">

  14. function whoami(){
  15. alert("i am "+this.name+" of type: "+typeof(this));
  16. }

  17. var whoA = {name: "A"};
  18. whoA.whoami = whoami;

  19. var whoB = {name: "B"};
  20. whoB.whoami = whoami;

  21. whoA.whoami();//this作为whoA  i am A of type: object
  22. whoB.whoami();//this作为whoB  i am B of type: object

  23. whoami.call(whoA);//this作为whoA  i am A of type: object
  24. whoami.call(whoB);//this作为whoB  i am B of type: object

  25. whoB.whoami.call(whoA);//this作为whoA  i am A of type: object
  26. whoA.whoami.call(whoB);//this作为whoB  i am B of type: object

  27. whoami.whoami = whoami;
  28. whoami.name = "I"
  29. whoami.whoami();//this作为whoami  i am I of type: function

  30. </script>
复制代码
Js中把this看着当前要服务的这个对象。
8, Json对象
  1. <script language="javascript" type="text/javascript">
  2. var json = {
  3. name:"xiaohong",
  4. age:"20",
  5. say:function(){alert(this.name+" hello");}
  6. };

  7. json.say();
  8. </script>
复制代码
Json是js对象化的一种形式。如果要将一个json字符串转换成js对象,只需要使用eval函数就可以将json字符串转换为一个js对象。

9, js创建对象
js创建对象可以通过new操作符结合函数名来创建对象。
如:
  1. function obj(){};
  2. var o = new obj();//var o = {}; obj.call(o);
复制代码
在js中先用new操作符创建一个对象,紧接着就将这个对象作为this参数调用后面的函数。
  1. <script language="javascript" type="text/javascript">

  2. function person(name){
  3. this.name = name;
  4. this.say = function(){
  5. alert("I am "+this.name);
  6. }
  7. }

  8. function emp(name, salary){
  9. person.call(this,name);
  10. this.salary = salary;

  11. this.sal = function(){
  12. alert(this.anme+" "+this.salary+"$");
  13. }
  14. }

  15. var p = new person("xiaohong");
  16. var e = new emp("xiaofang",1234);

  17. p.say();//I am xiaohong
  18. e.say();//I am xiaofang

  19. e.sal();//xiaofang 1234$

  20. alert(p.say==e.say);//false

  21. </script>
复制代码
上面代码表明:emp构造函数将自己的this作为参数调用person的构造函数,就是相当于调用基类的构造函数。
同时通过alert(p.say==e.say);//false,我们也可以看到在emp和person对象中确实各自保存了一份say代码体。
  1. <script type="text/javascript" language="javascript">

  2. function person(name){
  3. this.name = name;
  4. this.say = function(){
  5. alert("I am "+this.name);
  6. }
  7. }

  8. var p1 = new person("xiaohong");
  9. var p2 = new person("xiaofang");

  10. alert(p1.say==p2.say);//false

  11. </script>
  12. 同一类的对象各自有一份代码是一种浪费,在js中我们可以同过this来指向同一份代码体。
  13. <script type="text/javascript" language="javascript">

  14. function say(){
  15. alert("I am "+this.name);
  16. }

  17. function person(name){
  18. this.name = name;
  19. this.say = say;
  20. }

  21. var p1 = new person("xiaohong");
  22. var p2 = new person("xiaofang");

  23. alert(p1.say==p2.say);//true

  24. </script>

  25. <script type="text/javascript" language="javascript">

  26. function person(name){
  27. this.name = name;
  28. }

  29. person.prototype.say = function(){
  30. alert("I am "+this.name);
  31. }

  32. var p1 = new person("xiaohong");
  33. var p2 = new person("xiaofang");

  34. alert(p1.say==p2.say);//true

  35. </script>
复制代码
10, prototype原型,原型链,继承,多态。
在js中所有function类型的对象都有一个prototype属性,prototype是对象的原型。它本身就是一个object类型的对象,以此我们可以给它添加任意类型的属性和方法。在构造函数的prototype上定义的所有属性和方法,都可以通过其构造的对象直接访问和调用。可以说prototype给一群同类的对象提供了共享属性和方法。
  1. <script language="javascript" type="text/javascript">

  2. function person(name){
  3. this.name = name;
  4. }

  5. person.prototype.say = function(){
  6. alert("I am "+this.name);
  7. }

  8. function emp(name, salary){
  9. person.call(this,name);//调用基类的构造函数
  10. this.salary = salary;
  11. }

  12. emp.prototype = new person();//建一个基类的对象作为子类原型的原型(原型继承)

  13. emp.prototype.sal = function(){
  14. alert(this.name+" "+this.salary+"$");
  15. }

  16. var p = new person("xiaohong");
  17. var e = new emp("xiaofang",1234);

  18. p.say();//I am xiaohong
  19. e.say();//I am xiaofang

  20. e.sal();//xiaofang 1234$

  21. alert(p.say==e.say);//true

  22. </script>
复制代码
在js中prototype有寻根问祖的天性,当一个对象那里读取属性或调用方法时,如果该对象自身不存在这样的属性或方法,该对象就会去关联的prototype对象那里寻找,如果自己关联的prototype那里没有,就会去prototype自己关联的前辈的prototype那里寻找,直到找到或者寻找到根为此。
对象的属性和方法追溯机制就是通过prototype链来实现的。当用new操作符来构造函数对象时,也会同时将构造函数的prototype对象指派给新创建的对象,成为该对象的内置的原型对象。内置的原型对象本身也是对象,也有自己关联的原型对象,这样就可以形成原型链。
原型链的最底端,就是Object构造函数prototype属性指向的那一个原型对象。Js中所有的构造函数都是继承于该原型对象。这被称作原型继承。
Js中子对象可以掩盖父对象的属性和方法,即重写了父对象的属性和方法,这种掩盖机制实现了js的多态。

11, 闭包
  1. function a(){
  2.    var i=0;
  3.    function b(){
  4.    alert(++i);
  5.    }
  6.    return b;
  7.   }
  8.   var c = a();
  9. c();
复制代码
这段代码有两个特点:
  1、函数b嵌套在函数a内部;
  2、函数a返回函数b。
  这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。
  在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。
那 么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收。
1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
  2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
以上两点是闭包最基本的应用场景,很多经典案例都源于此。

在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。

12, 网页运行原理
当打开一个网页时,浏览器会创建一个窗口,这个窗口就是一个window对象,也就是js运行所依附的全局环境对象。为了加载网页文档,当前窗口将为要打开的网页创建一个document对象,然后将网页加载到这个对象中,网页的内容加载就是在这个过程中一边加载一边呈现出来的。js代码也是伴随这个过程,一边加载一边执行的。对于外部js可能会分配多个线程去完成加载,但浏览器也会等待需要的js文件加载完成后,最终安正确的顺序来执行js代码。
进行加载和执行的目的,是为了建立文档对象模型(DOM)的主框架。这个主框架是有当前文档窗口的主线程来处理,并依照样顺序进行的。而网页中可以异步加载其他附属资源,如图片,声音,视频等多媒体数据,是被安排给其他线程去处理的。
浏览器中有多少个线程可以同时加载网页内容?web标准有一个限制,就是对同一个域名最多只允许使用两个连接来读取内容,大多数浏览器都遵循这一标准。就是说同一个域名的情况下,只有两个线程可以同时加载内容,其他的会处于等待状态。因此,浏览器使用多少个线程在同时加载网页,要看网页内容涉及多少域名。一个域名两个线程,多了就会堵塞。
当网页主框架加载和执行完毕,浏览器才开始触发window对象或body对象的onload事件。在极少的情况下,网页如果没有body对象,浏览器会在网页加载完后自动创建一个body对象,并将其设置为document的body属性。Window对象和body对象事件是相通的,就是说,要么设置window对象的onload事件,要么设置body对象的onload事件,只能有一个起到作用。甚至在ie中两个onload事件就是同一个东西,设置一个就意味着改变了另一个。
当网页主框架加载执行完成,由此引发的事件也处理完毕,js就暂停执行以等待下一次被触发的时机。如点击,定时刷新等功能被触发,js执行引擎将再次起到,执行相应的js代码。
可以认为js总是被动执行的,并且js绝对是单线程的,不管是窗口主线程加载的js代码,还是外部js代码,以及触发执行的js代码执行,都是在一个单一的线程中执行的。甚至在一个浏览器进程中,不同窗口对象的相对独立的js代码也是在同一个线程里执行的。也就是说,你打开一个浏览器之后。不管你在浏览器进程中开启了多少个页面,新打开多少个窗口,里面的所有js代码都是有同一个线程来执行的。即一个浏览器进程中所有的js代码是串行执行的。除非再打开一个浏览器,创建一个新的浏览器进程。
同时,在网页编写js脚本时,不能太自私编写大量耗时的js脚本。这样可能给在同浏览器其他页面脚本堵塞,从而导致用户体验不好。


13, 文档对象模型
DOM这个术语反映了三个意思:一是“文档”,它表示是一份文档,即网页。二是“对象”,它表示是由一个个可操控的对象构成的。三是“模型”,他表示一个树型结构,一个可编程的模型。
可以这样认为,dom就是一棵树,一棵会开花的树,长在js必经的路旁,为的就是要和js结一段尘缘。只要轻拂一下js,就能让dom翩翩起舞,让dom展现多彩的页面。
Dom对象本质并不是一个纯粹的js对象,他是紧凑的本机数据对象,这些对象大都是以本机二进制的接口模型出现。在ie中dom对象是一个个com接口对象。而在Firefox中也有自己的接口模型。在浏览器扩展开发的工作中,我们可以直接建立相关dom对象的接口,并通过访问接口的属性和方法来操作dom对象。
14, Js跨域
浏览器对于网络上的链接会有一些限制,这些限制包括XMLHttpRequest的限制,网络浏览器不会允许脚本去对它本身所在的server之外的server直接链接。
在网络中要实现跨域有两种方法:一是多个不同域名的服务器进行通信,服务器间不受域名的安全限制。二是客户端和多个服务器端进行请求通信,浏览器在这种跨域请求的时候,会受到浏览器的安全限制。
服务器间的跨域访问可以通过服务器代理,web service等来实现跨域访问,不受跨域限制。
客户端直接对服务器端的跨域访问,可以通过动态的js来实现。
一, 动态的script标签实现跨域访问。
本方案利用js脚本动态插入script标签,利用该标签的src属性向服务器端发出请求(可带参数),src属性可指向一个服务器端的处理程序或脚本。如jsp php action等。服务器段通常返回一段js代码,当js代码返回给客户端的时候,js代码就会被执行,从而导致异步跨域名通信的目的。
通常情况下,服务器端返回的是一个回调函数,该函数的参数已经在服务器端被填充,该回调函数(带着被填充的参数)就会被执行。
客户端:
  1. <script language="javascript">
  2. function callback(arg){
  3. alert("this is "+arg);
  4. }

  5. function getRequest(){
  6. var jsobj = document.createElement("script");
  7. jsobj.src = "http://172.16.23.53:8088/DMS1.0/login/test_test.action?name=aaaaa";
  8. document.body.appendChild(jsobj);
  9. }

  10. </script>
  11. <body>
  12. <input  type="button" value="click" onclick="getRequest();"/>
  13. </body>
复制代码
服务器端:
  1. <%
  2. PrintWriter out = response.getWriter();
  3. String name = request.getParameter("name");
  4. out.print("callback("+data+")");
  5. %>
复制代码
二, Iframe实现跨域

客户端:
  1. <script language="javascript">

  2. function client(name){
  3. alert("client method "+name);
  4. }

  5. function envoy(url, method, callback){
  6. var frame = document.createElement("iframe");
  7. frame.style.width = 0;
  8. frame.style.height = 0;
  9. frame.style.visibility = "hidden";

  10. var params = [];
  11. for(var i=3; i<arguments.length; i++){
  12. params.push( arguments[i]);
  13. }

  14. frame.contentWinddow.name = params;

  15. var url = "http://"+url+" #"+method+"/"+callback+"@"+location.host;
  16. frame.contentWindow.location= url;

  17. }

  18. envory(“url”,”service”,”client”,”testparam”);
  19. </script>
复制代码
服务器端:
  1. <body>
  2. <script language="javascript">

  3. function service(arg){
  4. alert("service method is "+arg);
  5. return “service”;
  6. }

  7. if(!parent || parent == this){
  8. alert(“parent”);
  9. }else{
  10. var command = location.hash.substring(1);
  11. var i = command.indexOf("/");
  12. if(i>0){
  13. var j = command.indexOf("@");
  14. var callback = command.substring(i+1, j);
  15. var domain = command.substring(j+1);
  16. var method = command.substring(0,i);

  17. command = method+"("+window.name+")";
  18. var result = eval(command);

  19. window.name = result;

  20. window.location = "http://"+domain+”#”+callback;
  21. }else{
  22. command = command+"("+window.name+")";
  23. parent.eval(command);
  24. }
  25. }

  26. </script>
  27. </body>
复制代码

论坛徽章:
0
2 [报告]
发表于 2011-12-24 21:33 |只看该作者
谢谢分享  希望于楼主多多交流

论坛徽章:
0
3 [报告]
发表于 2012-11-10 23:58 |只看该作者
好文章呀,教会了我好多误区
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP