javascript权威指南学习笔记

时间:2022-08-27 08:09:43

一.数据类型:
js中,所有的数字都是浮点型的。
isNaN()/isFinite() //检测数据类型
Infinity //无穷大
Number.MAX_VALUE //可表示的最大数字
Number.MIN_VALUE //可表示的最小数字

数字转字符串
n+""
String(N)
n.toString() //可以加参数 2-2进制 8-8进制 16-16进制
n.toFixed() //显示小数点后的指定位数
n.toExponential() //指数表示
n.toPrecision() //指定有意思的位数

字符串转数字
+字符串
parseInt(string,16) //截取整数,支持另一个参数指定解析的数字基数(2-36)
parseFloat() //截取整数和浮点数

布尔类型转换
1.布尔转其他
true-1 true-"true"
false-0 false-"false"
2.其他转布尔
数字 0/NaN-false 其他-true
字符串 空字符串-false 其他-true
对象 空值/未定义的值-false 非空对象、数组、函数-true
3.显示转换
Boolean(x)/!!x

null的转换
布尔 null-false
数字 null-0
字符串 null-"null"

undefined的转换
布尔 undefined-false
数字 undefined-NaN
字符串 undefined-"undefined"

date类型转换/格式化
date -- string
date.toGMTString()
date.toLocaleString()
string -- date
new Date(s)
string -- string
var date = new Date(s)
date.toLocaleString()

===等同
数值和string只要值相等就完全相等。
两个值同为null或undefined就完全相等。
只要有一个为NaN就不完全相等。
引用同一个对象、数组或函数就完全相等。

==相等
同类型数据比较,相等就相等。
不同类型数据比较,先转换成同类型数据再比较。
null和undefined相等。


二.变量
未用var声明的变量会被创建为全局变量。
js中没有块级作用域,函数中声明的所有变量在函数内都有定义。
----------------------------------------------
function test(){
for(var k=0;k<10;k++){
alert(k);
}
alert(k); //10
}
----------------------------------------------
js解释器运行时先创建一个全局对象,对象的属性就是js程序的全局变量。
js函数都运行在自己独有的执行环境。具有自己的调用对象。调用的对象的属性就是该函数的局部变量。


三.运算符
in
要求左边是字符串或可以被转换成字符串,右边是数组或函数。

delete
var声明的变量不能删除,当delete操作的不是属性、数组元素或变量时返回true
------------------------------------------
delete 1; //true
delete x; //true
------------------------------------------

void
舍弃运算数的值,返回undefined,常用在客户端的javascript:URl中,计算表达式的值,而浏览器不会显示这个值。
另一个用途是专门生成undefined值。undefined是在javascript1.5中实现,考虑向后兼容,用void 0比undefined更有用。
<a href="javascript:void window.open();">Open New Window</a>
a href="javascript:void(0)"

如果是个# ,就会出现跳到顶部的情况,:个人收藏的几种方法:
1:<a href="####"></a>
2:<a href="javascript:void(0)"></a>
3:<a href="javascript:void(null)"></a>
4:<a href="#" onclick="return false"></a>
5:<span style="cursor:hand"></span>(在FF中不能显示)
方法2和3有可能导致页面中的GIF动画停止播放,推荐使用方法4

,运算符
先计算左边的参数,再计算右边的参数,然后返回右边参数的值

undefined不是保留字,为了确保其值不被改变,可以声明一个未赋值的变量
--------------------------------------------
var undefined; //undefined为undefined
--------------------------------------------

未声明的变量alert会报error错,typeof会返回undefined
null与undefined关系
undefined实际是null派生的,两者相等

var t1 = 56;
var t2 = 070;
var t3 = 0x38;
alert(t1==t2); //output:true
alert(t2==t3); //output:true
这说明无论是8进制、16进制,其变量都保存的是10进制的值。

数值运算优先调用valueOf,字符串或输出运算优先调用toString.


四.语句
switch语句
匹配case表达式是用===等同运算符判断的,所以表达式必须在没有类型转换的情况下进行。

for/in语句
for(variable in object)
statement

with语句(代码很难优化,运行速度慢,不建议使用)
with语句用于暂时修改作用域链
with(object)
statement
这条语句将object添加到作用域链的头部,然后执行statement,在把作用域链恢复到原始状态。

五.对象和数组
对象创建:
----------------------------------------------------
var obj = {};
var obj = new Object();
----------------------------------------------------

遍历对象:
----------------------------------------------------
for(var name in o) statement
----------------------------------------------------

检测属性的存在:
----------------------------------------------------
if("x" in o)
if(o.x !==undefined)
//区别当一个属性定义为o.x=undefined时,上一个有操作,后一个不做任何操作。
----------------------------------------------------

删除属性:
----------------------------------------------------
delete o.xxx
----------------------------------------------------
删除操作将属性从对象中移除,for/in不会枚举该属性。

Object的constructor属性
每个对象都有一个constructor属性,他引用初始化之个对象的构造函数。
----------------------------------------------------------------------------------------------------
if((type o == "object")&&(o.constructor == Date)) //确定一个位置值的类型。
if((type o == "object")&&(o instanceof Date)) //instanceof检查constructor属性的值。
----------------------------------------------------------------------------------------------------

检测对象的一个属性是不是非继承属性
----------------------------------------------------
o.hasOwnProperty("a");
----------------------------------------------------

检测一个对象的类型强烈建议使用Object.property.toString方法。
typeof只使用在检测一个变量是否已经定义。
----------------------------------------------------
Object.prototype.toString.call([]) //"[object Array]"
typeof foo !== 'undefined'
----------------------------------------------------

instanceof 操作符用来比较两个操作数的构造函数。只有在比较自定义的对象时才有意义。
如果用来比较内置类型,将会和 typeof 操作符 一样用处不大。应该仅仅用来比较来自同一个 JavaScript 上下文的自定义对象

数组:
Array对象的创建
1.new Array(10)
2.new Array("1","2")
3.["1","2"]
js中数组是稀疏的,所以数组的下标不必落在一个连续的数字范围
-------------------------------------------
a[0] = 1;
a[10000] = 10000;
//js解释器只给下标为0和10000的元素分配内存
-------------------------------------------

遍历数组:
js中数组是对象,用for in循环会枚举原型链上所有属性,过滤属性的方式是用hasOwnProperty函数,会比普通的for慢。
推荐使用经典的for循环,通过l=list.length来缓存数组的长度。
---------------------------------------
var list = [1,2,3,4,......10000000000];
for(var i=0;l=list.length;i<l;i++){
alert(i);
}
---------------------------------------

delete操作和对对象的操作不同,对数组操作元素设置为undefined ,元素本身还存在

数组方法:
join()
把数组中所有元素转换成字符串
----------------------------------------
var array = [1,2,3];
alert(array.join("|")); //1|2|3
----------------------------------------
reverse()
颠倒数组元素的顺序。 --改变原数组
sort()
排序 默认是按字母顺序。
a.sort(function(a,b){
return a-b;
}); --改变原数组
concat()
数组连接。如果参数是数组将被展开连接,但不支持递归的展开。 --不改变原数组
---------------------------------------------------------------
var a = [1,2,3];
alert(a.concat(4,[5,[6,7]])); //[1,2,3,4,5,[6,7]]
---------------------------------------------------------------
slice()
截数组。第一个参数是起始位置,第二个参数是结束位置。参数为负则相对于数组最后一个元素。 --不改变原数组
---------------------------------------------------------------
var a = [1,2,3,4,5];
alert(a.slice(1,-1)); //[2,3,4]
---------------------------------------------------------------
splice()
插入或删除数组元素。第一个参数是插入或删除元素的位置,第二个参数是删除的个数,后面元素是插入的元素。 --改变原数组
---------------------------------------------------------------
var a = [1,2,3,4,5]; //Returns [3,4]
alert(a.splice(2,2,[1,2],3)); //a=[1,2,[1,2],3,5]
---------------------------------------------------------------
push()/pop()
从数组的尾部添加或删除元素。返回数组新长度。
unshift()/shift()
从数组的头部添加或删除元素。返回数组新长度。
toStirng()/valueOf
每个数组元素调用toString()然后用","连接.

六.函数
函数定义
function square(x){ return x*x;}
var square = function(x) { return x*x;}
var square = new Functioin("x","return x*x;");

函数参数
js函数可以以任意数目的参数来调用,而不管函数定义中的参数个数

函数中判断一个参数是否传进来
---------------------------------------------
if(!a) a=[];
a=a||[];
---------------------------------------------

arguments对象;
实际传的参数列表,类似数组功能,有数组下标属性和length属性
arguments对象为其内部属性以及函数形式参数创建getter和setter方法。
改变形参的值会影响到arguments对象的值,反之亦然。
-------------------------------------------
function foo(a,b,c){
arguments[0] = 2;
a; //2
b=4;
arguments[1]; //4
var d = c;
d = 9;
c; //3
}
foo(1,2,3);
-------------------------------------------
arguments是java标识符避免同名变量
callee属性:
引用当前正在执行的函数,可以用作对未命名函数递归调用
--------------------------------------------
function(x){
if(x<=1) return 1;
return x*arguments.callee(x-1);
}
--------------------------------------------

length属性:
定义函数的实际参数数

prototype属性:
每个函数都有一个prototype属性,它引用的是预定义的原型对象。

call和apply方法:
第一个参数是要调用函数的对象,后面参数是函数的参数。
apply传递给函数的参数是由数组指定。

Function构造函数:
最后一个参数是函数体,如果前面有参数是函数参数

闭包:
定义在函数内部的函数:
用于读取函数的局部变量,
函数返回局部变量
让这些变量的值始终保持在内存中
调用闭包的变量声明为全局变量。
当一个函数作为函数而不是方法来调用的时候,this指向的是全局对象
--------------------------------------------------------------
var name = "ferry_passion";
var obj = {
"name":"ferry",
getName:function(){
alert(this.name); //ferry
return function(){
return this.name;
}
}
};
alert(obj.learn()()); //ferry_passion
--------------------------------------------------------------


七.类、构造函数、原型

Math类
方法:
random 前开后开,取0-1之间伪随机数
ceil 前开后闭,对一个数进行上舍入
floor 前闭后开,对一个数进行下舍入
round 就近取整
max 最大值
min 最小值

String类
对象创建:
new String("Hi")
Stinrg("Hi")
"Hi"
方法:
indexOf 检索字符串
lastIndexOf 从后向前检索字符串
1、字符位置是从0开始索引
2、即使是从后往前查找,返回位置时也还是位置0开始计算
3、当在字符串中索引不到该子串时,返回-1值。
charAt 返回在指定位置的字符
charCodeAt 返回在指定位置的字符的Unicode编码
slice(a[,b]) 截取字符串
substring(a[,b]) 取子串
substr(a[,length]) 取子串
slice和substr,当a为负数从字符串尾部开始计算
substring为负数从0开始计算
match 在字符串中检索指定的值,返回匹配结果的数组
search 检索指定的子字符串,返回相匹配的子串起始位置,没有匹配返回-1
toLowerCase 转小写
toUpperCase 转大写

实例化obj对象三步:
------------------------------------------
function A(x){
this.x = x;
}
var obj = new A(1);
------------------------------------------
1.创建obj对象:obj = new Object();
2.将obj的内部_proto_指向构造他的函数A的prototype,同时obj.constructor===A.prototype.constructor
3.将obj作为this去调用构造函数A,初始化

区分继承属性和常规属性的方法:
Object.hasOwnProperty()
在原型对像中定义方法,对象中都可以用,原型对象的endsWith方法是唯一的副本共享,每个对象不创建单独副本。
String.prototype.endsWith = function(c){}
绝对不能在Object.prototype添加属性,因为添加的属性可以用for/in循环枚举,而{}对象没有可枚举属性,在对象用作关联数组代码会出错。

要在js中定义一个类方法只要让相应的函数成为构造函数的一个属性。
--------------------------------------------
function Circle(radius){
this.r = radius;
}
Circle.max = function(a,b){};
Circle.max(c,d);
--------------------------------------------

一个类的属性声明为私有的可以使用闭包。
--------------------------------------------
function f(a,b){
this.a = function(){return a;}
this.b = function(){return b;}
}
--------------------------------------------

typeof null -- object
typeof undefined -- undefined
typeof 数组 -- object
typeof 函数 -- function


原型eg1:
------------------------------------------------
1 function A(x){
2   this.x = x;
3 }
4 A.prototype.a = "a";
5 function B(x,y){
6   this.y = y;
7   A.call(this,x);
8 }
9 B.prototype.b1 = function(){
10   alert("b1");
11 }
12 B.prototype = new A();
13 B.prototype.b2 = function(){
14   alert("b2");
15 }
16 B.prototype.constructor = B;
17 var obj = new B(1,3);
------------------------------------------------
这个例子讲的就是B继承A。第7行类继承:A.call(this.x);。实现原型继承的是第12行:B.prototype = new A();
  就是说把B的原型指向了A的1个实例对象,这个实例对象具有x属性,为undefined,还具有a属性,值为"a"。所以B原型也具有了这2个属性(或者说,B和A建立了原型链,
B是A的下级)。而因为方才的类继承,B的实例对象也具有了x属性,也就是说obj对象有2个同名的x属性,此时原型属性x要让位于实例对象属性x,所以obj.x是1,
而非undefined。第13行又定义了原型方法b2,所以B原型也具有了b2。虽然第9~11行设置了原型方法b1,但是你会发现第12行执行后,B原型不再具有b1方法,
也就是obj.b1是undefined。因为第12行使得B原型指向改变,原来具有b1的原型对象被抛弃,自然就没有b1了。

  第12行执行完后,B原型(B.prototype)指向了A的实例对象,而A的实例对象的构造器是构造函数A,
所以B.prototype.constructor就是构造对象A了(换句话说,A构造了B的原型)。
alert(B.prototype.constructor)出来后就是"function A(x){...}" 。同样地,obj.constructor也是A构造对象,alert(obj.constructor)出来后就是"function A(x){...}" ,
也就是说B.prototype.constructor===obj.constructor(true),但是B.prototype===obj.constructor.prototype(false),因为前者是B的原型,具有成员:x,a,b2,
后者是A的原型,具有成员:a。如何修正这个问题呢,就在第16行,将B原型的构造器重新指向了B构造函数,那么B.prototype===obj.constructor.prototype(true),
都具有成员:x,a,b2。

  如果没有第16行,那是不是obj = new B(1,3)会去调用A构造函数实例化呢?答案是否定的,你会发现obj.y=3,所以仍然是调用的B构造函数实例化的。
虽然obj.constructor===A(true),但是对于new B()的行为来说,执行了上面所说的通过构造函数创建实例对象的3个步骤,第一步,创建空对象;第二步,
obj.__proto__ === B.prototype,B.prototype是具有x,a,b2成员的,obj.constructor指向了B.prototype.constructor,即构造函数A;
第三步,调用的构造函数B去设置和初始化成员,具有了属性x,y。虽然不加16行不影响obj的属性,但如上一段说,却影响obj.constructor和obj.constructor.prototype。
所以在使用了原型继承后,要进行修正的操作。
  关于第12、16行,总言之,第12行使得B原型继承了A的原型对象的所有成员,但是也使得B的实例对象的构造器的原型指向了A原型,所以要通过第16行修正这个缺陷。


原型eg2:
--------------------------------------------------------
function Foo() {
this.value = 42;
}
Foo.prototype = {
method: function() {}
};
function Bar() {}
// 设置Bar的prototype属性为Foo的实例对象
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
// 修正Bar.prototype.constructor为Bar本身
Bar.prototype.constructor = Bar;
var test = new Bar() // 创建Bar的一个新实例
---------------------------------------------------------
// 原型链
test [Bar的实例]
Bar.prototype [Foo的实例]
{ foo: 'Hello World' }
Foo.prototype
{method: ...};
Object.prototype
{toString: ... /* etc. */};
---------------------------------------------------------
test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此,
它能访问 Foo 的原型方法 method。同时,它也能够访问那个定义在原型上的 Foo 实例属性 value。
需要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是 重复使用它原型上的那个实例;
因此,所有的 Bar 实例都会共享相同的 value 属性。
注意: 不要使用 Bar.prototype = Foo,因为这不会执行 Foo 的原型,
而是指向函数 Foo。 因此原型链将会回溯到 Function.prototype 而不是 Foo.prototype,
因此 method 将不会在 Bar 的原型链上。
当查找一个对象的属性时,js会向上遍历原型链,直到顶层没找到就返回undefined。
要提防原型链过长带来的性能问题,并知道如何通过缩短原型链来提高性能。
更进一步,绝对不要扩展内置类型的原型,除非是为了和新的 JavaScript 引擎兼容。


js两个小括号()()连用:函数会被立即执行
---------------------------------------
(function(){alert("aaa");})();
function foo(){alert(1);}foo();
---------------------------------------

hasOwnProperty函数判断对象是否包含自定义属性而不是原型链上的属性。
如果hasOwnProperty被非法占用。可以用外部的hasOwnProperty函数获取
{}.hasOwnProperty.call(foo,'bar');
for in 循环不会遍历那些 enumerable 设置为 false 的属性;比如数组的 length 属性。


八.模块和名字空间
当定义一个全局变量时,有被其他模块覆盖的危险,为了避免定义全局变量,使用模块化编程。
---------------------------------------------
var ModuleClass={};
ModuleClass.函数名1 = function(){

};
ModuleClass.函数名2 = function(){

};
---------------------------------------------
使用ModuleClass对象作为名字空间,将所有函数变量以及函数都放入其中。
如果名字冲突,可以使用域的方式做多级域名
---------------------------------------------
var util;
if(!util)util={};
util.ModuleClass = {};
util.ModuleClass.函数名1 = function(){

};
util.ModuleClass.函数名2 = function(){

};
---------------------------------------------


九.正则表达式
正则表达式方法:
test()
检测指定的字符串是否存在,返回true或false
exec()
查找匹配
匹配失败返回null
匹配成功返回一个数组,数组的0元素包含完整的匹配,其他元素包含的是匹配中任意一个子匹配,并更新RegExp对象属性
index是匹配发生的字符位置,input是被检索的字符串
String方法
search()
指明是否存在相应匹配,成功返回第一个成功检索位置,失败返回-1
replace()
替换字符串,返回替换后的字符串
split()
分割字符串,返回分割数组
match()
如果没有找到匹配返回null,否则返回一个数组

RegExp的方法test()和exec()受全局标志"g"和lastIndex的影响,而string的方法match(),search()等则不受影响
在一次匹配成功后,会设置lastIndex,下一次匹配,就会从这个lastindex所指示的位置开始尝试匹配,
当匹配失败时,lastIndex会被重新置为0
---------------------------------------------------------------------
var arr = [1,2,3,4,5];
var reg = /^\d+$/g;
for(var i = 0;i<arr.length;i++){
document.write("源字符串:"+arr[i]+" 验证结果:"+reg.test(arr[i])+" lastindex:"+reg.lastIndex+"<br/>");
}
document.write("<br>");
var reg = /^\d+$/;
for(var j = 0;j<arr.length;j++){
document.write("源字符串:"+arr[j]+" 验证结果:"+reg.test(arr[j])+" lastindex:"+reg.lastIndex+"<br/>");
}
结果:
源字符串:1 验证结果:true lastindex:1
源字符串:2 验证结果:false lastindex:0
源字符串:3 验证结果:true lastindex:1
源字符串:4 验证结果:false lastindex:0
源字符串:5 验证结果:true lastindex:1

源字符串:1 验证结果:true lastindex:1
源字符串:2 验证结果:true lastindex:1
源字符串:3 验证结果:true lastindex:1
源字符串:4 验证结果:true lastindex:1
源字符串:5 验证结果:true lastindex:1
---------------------------------------------------------------------

[\u4e00-\u9fa5] 匹配任意一个汉字
\s 任意空白字符 (\r\n\f\t\v)
\b单词边界
. 匹配除\n以外的字符,匹配所有字符一般用[\s\S]或.加(?s)匹配模式
?s Single-line模式
用new RegExp()创建的正则要注意引号内的转义
js只支持顺序环视,不支持逆序环视。java中支持顺序环视和确定长度表达式的逆序环视。

0-100的数字
^([1-9]?[0-9]|100)$

捕获组
普通捕获组()/命名捕获组(?<name>(Expression))

非捕获组
(?:Expression)
消除一些不得不使用(),却又不需要使用捕获组而带来内存被占用,匹配效率降低的情况。

环视
匹配内容不计入最终匹配结果,零宽度[(?=Expression),(?<=Expression)]
----------------------------------------------------------------------
var str = "aa<p>one</p>bb<div>two</div>cc";
var reg = /<(?!\/?p\b)[^>]+>/;
alert(str.match(reg)); //div
----------------------------------------------------------------------

匹配优先[贪婪模式]({m},{m,n},{m},?,*,+)/忽略优先[非贪婪模式]({m}?,{m,n}?,{m,}?,??,*?,+?)
在匹配成功的情况下,贪婪模式进行了更少的回溯,回溯过程需要进行控制权的交接

反向引用
捕获组在匹配成功时,会将子表达式匹配到的内容,保存到内存中一个以数字编号的组里,可以通过反向引用方式,引用这个局部变量的值
\1/\k<name>
年份0001-9999,格式yyyy-MM-dd或yyyy-M-d
^(?:(?!0000)[0-9]{4}([-/.]?)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|
(?:0?[13578]|1[02])\1(?:31))|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)
([-/.]?)0?2\2(?:29))$

取img中的属性。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
var data = [' <img alt="" border="0" name="g6-o44-1" onload="DrawImage" src="/bmp/foo1.jpg" />', ' <img src="/bmp/foo2.jpg" alt="" border="0" name="g6-o44-2" onload="DrawImage" />'] ;
var reg = /<img\b(?=(?:(?!name=).)*name=(['"]?)([^'"\s>]+)\1)(?:(?!src=).)*src=(['"]?)([^'"\s>]+)\3[^>]*>/i;
for(var i=0;i<data.length;i++)
{
var s = data[i];
document.getElementById("result").value += "源字符串:" + s + "\n";
document.write("<br />");
if(reg.test(s))
{
document.getElementById("result").value += "name: " + RegExp.$2 + "\n";
document.getElementById("result").value += "src: " + RegExp.$4 + "\n";
}
}
Results:
源字符串: <img alt="" border="0" name="g6-o44-1" onload="DrawImage" src="/bmp/foo1.jpg" />
name: g6-o44-1
src: /bmp/foo1.jpg
源字符串: <img src="/bmp/foo2.jpg" alt="" border="0" name="g6-o44-2" onload="DrawImage" />
name: g6-o44-2
src: /bmp/foo2.jpg
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

<html>
<head>
</head>
<body>
<script type="text/javascript">
var s = " f e r r y ";
alert("s="+s.replace(/\s*/g,"")+"!"); //去所有空格
alert("s="+s.replace(/^\s*/g,"")+"!"); //去左空格
alert("s="+s.replace(/\s*$/g,"")+"!"); //去右空格
alert("s="+s.replace(/^\s*|\s*$/g,"")+"!"); //去左右空格
</script>
</body>
</html>