1、获取对象在浏览器窗口中的绝对位置
function getObjPosition(Obj){
try{
var sumTop=0;
var sumLeft=0;
while(Obj!=window.document.body){
sumTop+=Obj.offsetTop;
sumLeft+=Obj.offsetLeft;
Obj=Obj.offsetParent;
}
return {left:sumLeft,top:sumTop};
}catch(e){alert(e);}
}
获取对象的宽度和宽度 obj.offsetWidth,obj.offsetHeight,不同浏览器间这两个值有的包括border和padding有的不包括.
2、浏览器窗口中对象的各种宽度和高度
注:这里有比较详细的解释:http://www.cnblogs.com/trlanfeng/archive/2012/11/04/2753280.html
3、关于this对象
this对象是在运行时基于函数的执行环境邦定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象.然而,匿名函数的执行环境具有全局性,所以匿名函数内部的this指向window对象. 如果匿名函数被赋值给一个对象的属性,则this对象指向该对象.
var name = 'the window';
var obj = {
name = 'the object',
getName:function(){
return function(){//匿名函数
return this.name;
}
}
}
obj.getName();//获取匿名函数
obj.getName()();//执行匿名函数,返回'the window';
var myObj = new Object();
myObj.name = '张山';
myObj.getMyName = obj.getName();
myObj.getMyName();//输出为张山
在几种特殊的情况下,this的值可能意外地改变,如:
var name = "the window";
var object = {
name:"my object",
getName:function(){
return this.name;
}
}
以下是几种调用object.getName()的方法以及各自的结果.
1.var fn = object.getName;
fn();//the window
2.object.getName();//my object
3.(object.getName)();//my object
4.(object.getName=object.getName)();//the window,这里比较难理解,结合第四和第五种情况说下我的暴力般的理解:这里进行了两步操作,第一步是赋值操作;第二步是执行函数,此时被执行的函数是在全局环境下执行object.getName变量指向的函数.
object.getName();//前面执行了赋值操作,现在再来执行返回 my object
5. var anotherObject = {name:"another Object"}
(anotherObject.getName=object.getName)();//the window
anotherObject.getName();//another object
4.正则表达式
特殊符号
( [ { \ ^ $ | ) ? * + . ] } ,要匹配特殊字符必须使用 \ 进行转义.
模糊匹配
* 匹配0次或1次
+ 匹配1次或多次
? 匹配0次或依次
匹配模式标志
g 全局模式,即正则表达式将用于匹配整个字符串,而不是第一匹配到时即停止,下一次匹配从上一次匹配的末尾开始直到字符串结束又从头开始. 重复使用同一个正则表达式时应注意.
i 匹配的过程中忽略大小写.
m 表示多行模式,即在到达一行的结尾时会继续在下一行中查找匹配的字符串.
正则表达式字面量和RegExp
在某些低版本的浏览器中(ECMAScript3)正则表达式字面量(形如:/^\d/g 的字符串常量)始终会共享同一个RegExp实例,实例属性不会被重置,而使用RegExp构造函数创建的每一个都是一个新实例.
RegExp实例属性
index 匹配项在字符串中的位置
input 应用模式的字符串
exec 方法 返回Array, 如果没有匹配到则返回null. 数组中第一项为与整个正则表达式匹配的字符串, 其他项是与模式中的捕获组匹配的字符串.
即使模式中设置了全局标志g,它每次都只返回一个匹配项. 在不设置全局标志的情况下,在同一个字符串上都次调用exec将始终返回第一个匹配项, 否则它会从上次匹配的结尾开始继续查找新的匹配项.
test 方法 如果匹配返回true,否则返回false.
5.Function类型
函数是对象,每个函数都是Function类型的实例. 由于是对象,函数可以有属性和方法.
函数没有重载, 函数名称相同的两个函数, 下面的会覆盖上面的,不管参数列表长成啥样. 实际上函数的参数是保存在arguments属性当中的. 可以把函数名称想像成指针或者变量, 他们同一时刻只能引用一个对象.
函数声明和函数表达式
js解析器率先读取函数声明,并使其在执行任何代码之前可用;函数表达式只有解析器执行到它所在的行时才会真正被解释执行。看下面的例子:
function sum(){...}//函数声明
var sum = function(){...}//函数表达式
函数内部属性arguments/this/caller
arguments 的主要作用是保存入参,但这个对象还有一个叫callee的属性(在严格模式下不能使用该属性),该属性是一个指针,指向拥有这个arguments对象的方法. 这个属性典型的用处是在编写第归函数的时候实现函数的执行和函数名字的解耦. 举例说明如下:
function factorial(num){
if(num <= 1){
return 1;
}else{
return num*factorial(num-1);
}
}
考虑如下代码
var factorial01 = factorial;
factorial = function(){
return 0;
}
factorial01(5);//得到的值为0,而不是120
将return num*factorial(num-1)改为return num*arguments.callee(num-1)则能够返回正确的120.
this this指针指向函数赖以执行的环境对象,当在网页的全局作用域调用函数时,函数内的this指针指向window对象.
除了arguments和this之外,ECMAScript还定义了caller(function_name.caller或者arguments.callee.caller)属性, 这个属性保存着调用当前函数的函数的引用,如果在全局作用域内调用当前函数则为null.
函数的属性和方法
每个函数都包含两个属性length和prototype.
length
表示参数列表的长度.
prototype
prototype是一个指针,指向一个对象实例,而这个对象实例的属性和方法可以被每个函数实例访问和共享.
function Person(){
this.name = 'zhangsan';
this.sayName = function(){alert(this.name);}
}
通过Person.prototype获取到Person对象的原型,如果给原型对象增加属性Person.prototype.avgHeight = 172,则height属性可以被Person的每一个实例共享.
var p = new Person();
alert(p.avgHeight);//172
每个函数都包含两个非继承而来的方法apply()和call(),这两个方法的用途都是在特定的作用域中调用函数,区别在于接收参数的方式不一样.
apply()方法接收两个参数,第一个参数指定运行当前函数的作用域,第二个参数指定参数,第二个参数可以是数组也可以是arguments对象.
function sum(num1,num2){
return num1+num2;
}
function callsum1(num1,num2){
return sum.apply(this,[num1,num2]);//这里的this指向callsum1运行时的环境,参数传递形式为数组
}
function callsum2(num1,num2){
return sum.apply(this,arguments);//这里的this指向callsum2运行时的环境,参数传递形式为arguments
}
callsum1(10,20);//30,运行时环境为window对象
callsum2(10,20);//30,运行时环境为window对象
call() 方法必需明确传递每一个参数
function callsum3(num1,num2){
sum.call(this,num1,num2);//参数必须一个个传递
}
callsum3(10,20);//30,运行时对象为window
apply()和call()方法真正强大的地方在于可以通过第一参数指定方法运行的作用域.
ECMAScript还提供了一个方法func.bind(obj), 该方法创建一个函数并返回,返回的函数的运行作用域为obj. IE9+,FireFox 4+, Safari 5.1+,Opera 12+和Chrome支持该方法.
6.Global对象
Global对象是全局对象,不属于任何对象的属性和方法都属于Global对象.
URI编码方法
encodeURI() 对URI进行编码,有效的URI不能包含某些字符. encodeURI()方法就是把URI中无效的字符(比如中文,空格等)用特殊的UTF-8编码替换,对于URI里面有效地字符(比如/,?等)不做转换.
与encodeURI()对应的方法是decodeURI().
encodeURIComponent() 方法用UTF-8编码对所有非字母数字字符进行编码. 只能对附加在URI后面的字符串使用encodeURIComponent方法.
与encodeURIComponent方法对应的方法是decodeURIComponent方法。如果ajax返回中文的话,可以考虑在服务器端使用java的encodeURI,然后在浏览器端使用decodeURIComponent方法。
eval()方法
eval()方法把字符串参数解析为javascript运行,并把运行结果替换eval()原来的位置。效果就像是先用eval() 的参数替换eval(),然后再解析执行整个js脚本或片断。
7.Ajax
创建跨浏览器的XMLHttpRequest对象
function createXHR(){
//IE7+,FireFox,Opera,Chrome和Safari均支持原生的XMLHttpRequest
if(XMLHttpRequest){//<span style="font-family: Arial, Helvetica, sans-serif;">typeof XMLHttpRequest != undefined在chrome、FireFox下报错</span>
return new XMLHttpRequest();
}else if(typeof ActiveXObject != undefined){//typeof ActiveXObject != undefined 在chrome\firefox下报错
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
var i,len;
for(i=0,len=versions.length;i<len;i++){
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
}catch(ex){
}
}
}
return new new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error("No XHR Object available");
}
}
使用XHR
最简单的ajax调用流程如下:
<pre class="javascript" name="code"><pre class="javascript" name="code">var xhr = createXHR();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
alert(xhr.responseText);
}
}
}
//为了保持浏览器的兼容性,先设置好监听器,再调用open方法
xhr.open(method,url,false);
xhr.send('parameter string or null');
open()方法接收三个参数:第一是请求的类型,get、post等;第二个参数是请求的URL,如果是get请求,url后面接参数列表;第三个参数表示是否异步发送请求;
onreadystatechange函数监听xhr对象属性readyState的变化,readyState可能的值如下:
0:未初始化。尚未调用open方法
1:启动。已经调用open方法,尚未调用send方法
2:发送。已经调用send方法,但尚未接收到反应。
3:接收。已经接收到部分响应数据。
4:完成。已经接收到全部的响应数据,而且已经可以在客户端使用了。
xhr.status属性存储的是请求返回的状态码,类似于http请求返回的状态码,仅仅因为浏览器对XHR对象的实现上有细微的差别。与之对应的是状态信息xhr.statusText.
responseText 存储的是响应的内容,如果响应内容是xml,则还会存储在responseXML属性中,否则responseXML属性为null。
send方法发送请求,send方法带一个参数,即传送给服务器的参数,对于get方法而言,参数被添加到url的末尾,因此传null即可,不传null也会被无视;对于post方法,则发给服务器的参数应该做为send方法的参数,如果参数的形式和get方法参数格式一致则必须在open方法之后send方法之前设置请求头Content-Type如下所示:
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
否则参数无法正确被解析。无论get还是post,如果参数列表中包含特殊的字符,则需用encodeURIComponent编码之;
8.in操作符
在for-in中使用.for-in语句是一种精准的迭代语句,可以用来枚举对象的属性和方法(对象实例属性和对象原型中定义的属性),当然前提是该属性可以被枚举.
for(var p in window){
alert(p);
}
单独使用in. 单独使用时,in操作符会在通过对象能够访问给定属性时返回true,而不管属性存在实例中还是原型中. 这里有必要提一下object.hasOwnerProperty()方法.hasOwnerProperty方法只会针对对象实例的属性或者方法名返回true. 因此可以结合使用in操作符和hasOwnerProperty方法判断属性或方法定义在对象实例上还是定义在原型上.
alert("document" in window);//true
9.块级作用域
javascript中没有块级作用域,如下面的例子:
if(true){
var color = 'blue';
}
alert(color);//blue
color变量是在if语句块里定义的,在java语言中,当if语句块执行完毕,color变量就会被销毁,但javascript因为没有块级作用域,所以color属性还在.
特别值得注意的是这一特性在for循环中体现.
for(var i=0;i<10;i++){
//do something;
}
alert(i);//10
尽管javascript里面没有块级作用域,但我们可以通过其他方式模仿块级作用域
(function(){
//这里就是块级作用域了,在这里定义的变量会在执行结束时销毁
})();
使用这种方式可以避免定义的变量在无意中被添加到window全局作用域。
10.JSON
如下是一个json对象字面量:
{
"name":"lisi",
"age":27
}
细细看来上面这个json对象字面量与javascript中的对象字面量有如下区别:
1. 没有声明变量。json里面没有变量的概念。
2. 属性用双引号括起来了。json里面属性名称必须用双引号括起来。
ECMAScript 5 对解析json的行为进行了规范,定义了全局对象JSON。IE8+,FireFox3.5+,Safari4+,Chrome和Opera10.5+.
JSON对象有两个方法:stringify()和parse().
stringify()将javascript对象序列化为json字符串。
var obj = {
name:'lisi',
age:27,
sayName:function(){
alert(this.name);
}
}
JSON.stringify(obj)输出为 {"name":"lisi","age":27}
stringify方法在序列化javascript对象时,所有函数和原型成员都会被有意忽略,不体现在结果中,另外值为undefined的属性将会被跳过。
实际上stringify()方法可以带三个参数,第一是被序列化的javascript对象。第二个参数是过滤选项,可以是数组或者函数,如果是数组,则返回的json字符串中只包含数组中列出的属性;如果是函数,则该函数必需带两个参数:属性名称和属性值,经过函数处理最后返回属性值,如果返回的属性值为undefined,则json字符串中该属性被忽略。第三个参数在格式化输出的json字符串时用到,是一个数字,最大有效值为10,表示json字符串层级之间的缩进。
parse()将json字符串反序列化为javascript对象。
如果stringify()方法不能满足对某些对象自定义序列化的要求,可以为对象定义toJSON方法返回javascript对象,stringify()会先调用toJSON方法取得目标对象,然后再在目标对象的基础上进行序列化,具体的执行步骤如下:
1.如果存在toJSON方法而且能通过它取得有效的值,则调用该方法。否则返回对象本身。
2.如果提供了第二个参数,应用这个函数过滤器,传入函数过滤器的值是第(1)步中返回的值。
3.对第(2)步返回的每个值进行相应的序列化。
4.如果提供了第三个参数,执行相应的格式化。
11.事件
事件流
事件流描述的是从页面中接收事件的顺序. 事件流有两种,一种是由MS提出的事件冒泡,另外一种是由网景公司提出的事件捕获.
事件冒泡是指事件由触发者一层一层往上传播;事件捕获是指事件首先由最高层接收,然后再一层一层往下传播,直到事件的触发对象.
<! DOCTYPE html>
<html>
<head>
<title>Event Stream</title>
</head>
<body>
<div>Click Me</div>
</body>
</html>
如果你点击了<div>元素,在冒泡机制里面,事件会这样传播div -> body -> html -> document;而在事件捕获机制中,事件则是这样传播document -> html -> body -> div.
主流浏览器都实现了事件冒泡,因此在日常的开发中,可以放心的使用冒泡机制.
DOM2级事件流
"DOM2级事件"规定的事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段.首先发生的是事件捕获,为截获事件提供了机会.然后是实际的目标接收到事件,最后一阶段是冒泡阶段.
各浏览器厂商及浏览器版本之间对DOM2级事件流的实现参差不齐.
12.js判断上传文件大小
function fileChange(target) {
var fileSize = 0;
if (window.ActiveXObject) {
var filePath = target.value;
var fileSystem = new ActiveXObject("Scripting.FileSystemObject");
if(!fileSystem.FileExists(filePath)){
alert("附件不存在,请重新输入!");
return;
}
var file = fileSystem.GetFile (filePath);
fileSize = file.Size;
} else if(target.files){
fileSize = target.files[0].size;
}
var size = fileSize / 1024;
if(size>1){
alert("附件大小不能大于1KB!");
}
if(size<=0){
alert("附件大小不能为0!");
}
}
<input type="file" name="contractFileName" style="width: 500px;" onchange="fileChange(this);"/>
13.基本包装类型String,Number,Boolean
js有5种基本的数据类型(Undefined, Null, Boolean, Number, String)和一种复杂数据类型Object
我们知道基本类型值(使用typeof操作符返回不是object)不是对象,是没有方法和属性的,但我们经常看到类似如下的用法:
var s1 = 'abcde';//基本类型值
var s2 = s1.substring(1);//调用基本类型的方法
原来每当读取一个基本类型值时,后台就会创建一个对应的基本包装类型,从而让我们能够调用一些方法来操作这些数据.当第二行代码访问s1的时候,访问过程处于一种读取模式,也就是要从内存中读取这个字符串的值,而在读取模式中访问字符串时,后台都会自动完成下列处理:
(1) 创建String类型的一个实例
(2) 在实例上调用指定方法
(3) 销毁这个实例
创建的实例只存在于一行代码执行的瞬间,然后立即被销毁.
14.执行环境和作用域链
执行环境是js中最重要的一个概念.执行环境定义了变量和函数有权访问的其他数据,决定了他们各自的行为.每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中.
每个函数都有自己的执行环境.当执行流进入一个函数时,函数的环境就会被推入一个环境栈中.而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境.
当代码在一个环境中运行时,会创建一个作用域链,这个作用域链是由变量对象组成的.作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问.作用域链的前端始终是当前执行代码所在的环境的变量对象,如果这个环境是函数,则将其活动对象作为变量对象.活动对象在最开始时只包含一个变量,即arguments对象,作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境.这样一直延伸到全局执行环境.
标志符的解析是从作用域链的最前端开始,沿着作用域链一级一级搜索标志符的过程.
15.闭包
闭包是指有权访问另一个函数作用域中的变量的函数.创建闭包的常见方式,就是在一个函数内部创建另一个函数并返回.
如:
function createBiBao(showMe){
return function(){
alert(showMe);
}
}
之所以外部函数返回了还能访问外部函数中的变量,是因为内部函数的作用域链中包含了外部函数的作用域链.
在匿名函数从createBiBao中被返回后,他的作用域链被初始化为包含createBiBao函数活动对象(即变量对象)和全局变量对象.这样匿名函数就可以访问在createBiBao中定义的所有变量.更为重要的是createBiBao函数在执行完毕之后,其活动对象不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象.
闭包与变量
闭包只能取得包含函数中任何变量的最终值.因为闭包保存的是整个变量对象,而不是某一变量在某一时刻的值.如,
function createFunctions(){
var result = new Array();
for(var i=0;i<10;i++){//此处的局部变量i的作用域,不仅仅局限于for循环,因为js中没有块级作用域
result[i] = function(){
return i;
};
}
return result;
}
这个函数会返回一个函数数组.表面上看似乎每个函数都应该返回自己的索引值,但实际上,每个函数都返回10.因为每个函数的作用域链中都保存着createFunctions()的活动对象,所以他们引用的都是同一个变量i.当createFunctions()返回后,变量i的值为10,所以每个函数内部i的值都为10.
我们可以通过创建另一个匿名函数强制让闭包的行为符合预期,如下所示:
function createFunctions(){
var result = new Array();
for(var i=0;i<10;i++){//此处的局部变量i的作用域,不仅仅局限于for循环,因为js中没有块级作用域
result[i] = function(num){
return function(){
return num;
}
}(i);
}
return result;
}
在这个版本中,没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋值给数组.这里的匿名函数有一个参数num,也就是最终的函数要返回的值.在调用每个匿名函数时,传入了变量i.由于函数参数是按照值传递的,所以会将变量i的当前值复制给参数num,而在这个匿名函数的内部,又创建并返回了一个访问num的闭包.这样一来,result数组中的每个函数都有自己num变量的一个副本,因此可以返回不同的值了.
闭包和this对象
每个函数在被调用时都会自动获取两个特殊变量:this和arguments.内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量.不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了.
var name = "the window";
var object = {
name:"My Object",
getNameFunc:function(){
var that = this;
return function(){
return that.name;//这里如果用this,则会返回the window
}
}
};
object.getNameFunc()();//My Object