悟透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函数类型。定义式和变量式。
<script language="javascript" type="text/javascript">

function myfun(){
alert("hello");
}

myfun();//输出word

function myfun(){
alert("word");
}

myfun();//输出word

</script>

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

var myfun = function (){
alert("hello");
}

myfun();//输出hello

myfun = function (){
alert("word");
}

myfun();//输出word

</script>

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

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

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

var yourName = "you";
myName = "me";

function changeName(){
alert(myName+"==="+yourName);//me===undefined
var yourName = "your";
myName = "my"
alert(myName+"++++"+yourName);//my++++your
}
alert(myName+"---"+yourName);//me---you

</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的根。

5, Caller

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

function callerB(){callerA();}

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

callerB();//caller is callerB(){callerA();}

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

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

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

alert(obj["aproperty"]);
obj["amethod"]();

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

</script>

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

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

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

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

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

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

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

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

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

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

9, js创建对象
js创建对象可以通过new操作符结合函数名来创建对象。
如:
function obj(){};
var o = new obj();//var o = {}; obj.call(o);

在js中先用new操作符创建一个对象,紧接着就将这个对象作为this参数调用后面的函数。

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

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

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

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

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

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

e.sal();//xiaofang 1234$

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

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

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

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

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

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

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

function person(name){
this.name = name;
this.say = say;
}

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

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

</script>

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

function person(name){
this.name = name;
}

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

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

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

</script>

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

function person(name){
this.name = name;
}

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

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

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

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

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

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

e.sal();//xiaofang 1234$

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

</script>

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

11, 闭包
function a(){
   var i=0;
   function b(){
   alert(++i);
   }
   return b;
  }
  var c = a();
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代码就会被执行,从而导致异步跨域名通信的目的。
通常情况下,服务器端返回的是一个回调函数,该函数的参数已经在服务器端被填充,该回调函数(带着被填充的参数)就会被执行。
客户端:
<script language="javascript">
function callback(arg){
alert("this is "+arg);
}

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

</script>
<body>
<input  type="button" value="click" οnclick="getRequest();"/>
</body>

服务器端:
<%
PrintWriter out = response.getWriter();
String name = request.getParameter("name");
out.print("callback("+data+")");
%>
二, Iframe实现跨域

客户端:

<script language="javascript">

function client(name){
alert("client method "+name);
}

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

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

frame.contentWinddow.name = params;

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

}

envory(“url”,”service”,”client”,”testparam”);
</script>


服务器端:

<body>
<script language="javascript">

function service(arg){
alert("service method is "+arg);
return “service”;
}

if(!parent || parent == this){
alert(“parent”);
}else{
var command = location.hash.substring(1);
var i = command.indexOf("/");
if(i>0){
var j = command.indexOf("@");
var callback = command.substring(i+1, j);
var domain = command.substring(j+1);
var method = command.substring(0,i);

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

window.name = result;

window.location = "http://"+domain+”#”+callback;
}else{
command = command+"("+window.name+")";
parent.eval(command);
}
}

</script>
</body>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值