JavaScript语言精粹---学习总结
????''?==?'0';??//false
????0?==?'';????//true
????0?==?'0';???//true
???
????false?==?'false';??//false
????false?==?'0';??????//true
???
????false?==?undefined;?//false
????false?==?null;??????//false
????null?==?undefined;??//true
???
????' \t\r\n '?==?0;????//true
?
通过上面的例子,大师建议我们:永远不要使用?==?和?!=?,请始终使用?===?和?!==?,有这两个运算符的话,以上例子全部为false!
?
2、eval
eval?函数传递一个字符串给JavaScript编译器,并且执行其结果。它是一个被滥用得最多的JavaScript特性。例如:如果你知道点表示法,但不知道下标表示法,就可能会这么写:(我为了实现一个功能,专门研究了一下eval函数,最后用下面的方法写出了想要的功能,高兴得很!当第二天看到这位大师这么说的时候,想死的心都有了!哎!)
????eval("myValue = myObject."+?myKey?+";");
而不是这么写:
????myValue = myObject[myKey];
使用eval形式的代码会更加难以阅读。而且也会降低语言的性能。
所以,大师建议我们:eval、Function、setTimeout、setInterval?这四个方法应该避免使用!
我决定了,以后都不用了,呵呵!
?
3、++ --
作为一条原则,大师建议我们:不再使用这两个运算符,用?+=?和?-=?代替!
?
4、function?语句对比函数表达式
下面的语句:
????function foo(){}
意思相当于:
????var foo = function (){};
大师建议我们:用第二种形式!
?
5、类型的包装对象
JavaScript?有一套类型的包装对象。例如
???????new Boolean(false)
会返回一个对象,该对象有一个valueOf方法会返回被包装的值。这其实完全没有必要,并且有时还令人困惑。
大师建议我们:不要使用new Boolean?、?new Number?或?new String,同时避免使用?new Object?和?new Array。可使用{}和[]来代替!
?
6、new
new这个东西说了很多,也很有用(个人感觉),可是大师建议我们:一个更好的应对策略就是根本不去使用?new?。
?
7、JavaScript的假值
?
这些值全部等同于假,但它们?是不可互换的。例如,这是用一种错误的方式去确定一个对象是否缺少一个成员元素:
????value = myObject[name];
???????if (value == null) {
?????????alert(name + ' not found. ');
????}
undefined?是缺失的成员元素的值,但该代码片段用null?来测试。它使用了会强制类型转换的==运算符,而不是更可靠的===运算符。
?
8、NaN
NaN是一个特殊的数量值,它表示不是一个数字,可是他的类型却是number?,可以通过下面的代码来验证:
????typeOf NaN === 'number'??// true
????NaN === NaN???????????//false
????NaN !== NaN????????????//true
?
????isNaN (NaN)?????????????//true
????isNaN (0)????????????????//false
????isNaN('oops')?????????????//true
????isNaN('0')????????????????//false
?
大师列出了上面几条,最后建议我们:自己写一个判断是不是数字的方法!
????????var isNumber = function(value){
??????????????return typeof value === 'number' && isFinite(value);
????????};
?
9、parseInt
????/**
?????*?parseInt?是一个将字符串转换为整数的函数,
?????*?它在遇到非数字时停止解析,
?????*?以致于出现下面的情况。
?????*/
????var?myValue1?=?parseInt("16");???????????????//myValue1 = 16
????var?myValue2?=?parseInt("16 is a number");???//myValue2 = 16
???
????/**
?????*?如果一个字符串是以0开头的,
?????*?那么该字符串将被基于八进制而不是十进制来求值。
?????*?在八进制中,8和9不是数字,所以会出现下面错误。
?????*/
????var?myValue3?=?parseInt("08");?//myValue3 = 0
????var?myValue4?=?parseInt("09");?//myValue4 = 0
???
????/**
?????*?这个错误导致了程序解析日期和时间时出现问题。
?????*?幸运的是,parseInt可以接受一个基数作为参数,
?????*?我们可以用下面的方法去代替
?????*/
????var?myValue5?=?parseInt("08",?10);?//myValue5 = 8
?
10、编码风格
大师建议我们:{}的{?一定要放到一行的结束,不要放到一行的开始!
?
二:对象
1、对象字面量(对象的定义)
????/**
?????*?1、对象是属性的容器。
?????*?2、“名/值”对?"first-name"/"Jerome"。
?????*?3、属性名只要是符合合法的命名且不是保留字,可以不用“”号括住,
?????*????所以"first-name"必需括住,因为“-”不是合法的命名,
?????*????而first_name,则不必括住。
?????*?4、属性之间用“,”号分隔。
?????*?5、对象可以嵌套。
?????*/
????var?empty_object?=?{};
???
????var?stooge?=?{
????????"first-name":?"Jerome",
????????"last-name":?"Howard"
????};
???
????var?flight?=?{
????????airline:?"Oceanic",
????????number:?815,
????????departure:?{
????????????IATA:?"SYD",
????????????time:?"2009-09-09 14:55",
????????????city:?"Sydney"
????????},
????????arrival:?{
????????????IATA:?"LAX",
????????????time:?"2009-09-09 14:55",
????????????city:?"Los Angeles"
????????}
????};
?
2、检索(对象属性访问)
????/**
?????*?要检索对象中的值,可以用[]和.两种方式,
?????*?但是要注意,属性名要符合规则且不是保留字的时候才能用.的方式访问
?????*/
????var?strValue1?=?stooge["first-name"];??//strValue1 = Jerome,这样是对的
????var?strValue2?=?stooge.first-name;?????//这样是错误的
????var?strValue3?=?stooge["last_name"];???//strValue3 = Howard,这样是对的
????var?strValue4?=?stooge.last_name;??????//strValue4 = Howard,这样是对的
???
????/**
?????*?如果你尝试检索一个不存在的成员元素的时候,将返回一个undefined值
?????*/
????stooge["middle-name"]??//undefined
????flight.status??????????//undefined
????stooge["FIRST-NAME"]???//undefined
???
????/**
?????*??||?运算符可以用来填充默认值
?????*/
????var?middle?=?stooge["middle-name"]?||?"asdf";
????var?status?=?flight.status?||?"unknown";
???
????/**
?????*对象通过引用来传递,它们永远不会被拷贝
?????*/
????var?x?=?stooge;
????x.nickname?=?'Curly';
????var?nick?=?stooge.nickname;??//nick = Curly
?
三:函数
1、函数字面量(函数定义)
var?add?=?function?(a,?b){
????return?a?+?b;
};
?
2、调用
函数除了声明时定义的形式参数,还有两参数this?和?arguments。
函数的调用有四种:方法调用模式、函数调用模式、构造器调用模式、apply?调用模式,这些模式在如何初始化关键参数this上存在差异。
?
方法调用模式
当一个函数保存为对象的一个属性时,我们称它为一个方法。
//创建?myObject,它有一个value属性和一个increment方法。
//increment方法接受一个可进的参数,如果不是数字,那么默认使用数字1
//this被绑定到myObject
var?myObject?=?{
????value:?0,
????increment:?function(inc){
????????this.value?+=?typeof?inc?===?'number'???inc?:?1;
????}
};
?
myObject.increment();
document.writeln(myObject.value);?//1
?
myObject.increment(2);
document.writeln(myObject.value);?//3
?
函数调用模式
当一个函数并非一个对象的属性时,那么它被当作一个函数来调用。
// sum的值为7,add函数在这里被调用是函数调用模式
// this被绑定到全局对象
var?sum?=?add(3,?4);
?
?
构造器调用模式
/**
?*?在调用函数的时候,前面加上一个new来调用,称为构造器调用
?*?this被绑定到新函数
?*?注意:大师建议不使用这种方式的构造器函数
?*/
//创建一个名为Quo的构造器函数,它构造一个带有status属性的对象
var?Quo?=?function(string){
????this.status?=?string;
};
?
//给Quo的所有实例提供一个名为get_status的公共方法
Quo.prototype.get_status?=?function(){
????return?this.status;
};
?
//构造一个Quo实例
var?myQuo?=?new?Quo("confused");
?
apply调用(看不懂,不记录了)
?
?
3、异常
var?add?=?function(a,?b){
????if(typeof?a?!==?'number'?||?typeof?b?!==?'number'){
????????throw?{
????????????name:?'TypeError',
????????????message:?'add needs numbers'
????????};
????}
};
?
var?try_it?=?function(){
????try{
????????add("seven");
????}catch(e){
????????document.writeln(e.name?+?':'?+?e.message);
????}
};
?
try_it();
?
4、给类型增加方法
//JavaScript给类型增加方法的时候,必须以下面这种格式
String.prototype.methodName?=?function(){
};
?
//这样做很麻烦,所以我们用一个方法解决
Function.prototype.method?=?function(methodName,?methodFunc){
????if(!this.prototype[methodName]){
????????this.prototype[methodName]?=?methodFunc;
????}
????return?this;
};
//这样我们在以后扩展方法的时候就方便多了
Number.method('integer',?function(){
????return?Math[this?<?0???'celling'?:?'floor'](this);
});
document.writeln((-10?/?3).integer());?//-3
?
//JavaScript缺少一个移除字符串末端空白的方法
String.method('trim',?function(){
????return?this.replace(/^\s+|\s+$/g,?'');
});
document.writeln(" asdf ".trim());
?
5、递归
?
?
?
?
?
?
6、闭包
一个函数可以访问它被创建时所处的上下文环境,这被称为闭包!
例:
//把一个节点的颜色由黄色渐到白色
var?face =?function(node){
??var?level = 1;
??var?step =?function(){
????var?hex = level.toString(16);
????node.style.backgroundColor =?'FFFF'?+ hex + hex;
????if(level < 15){
????????level += 1;
????????setTimeout(step, 100);
????}
??};
??setTimeout(setp, 100);
};
face(document.body);
?
一个很不好的例子:
/**
?*?可以想象一下,下面的alert会出现什么问题呢?
?*?alert只会出现1个数字,nodes.length?+?1?之后的数字,为什么呢?
?*?因为函数有访问它被创建时所处的上下文环境,这被称为闭包!i一直在变!
?*/
var?add_the_handlers =?function(nodes){
??var?i;
??for(i=0; i<nodes.length; i+=1){
????nodes.on allowScriptAccess="never" allowNetworking="internal" wmode="transparent"click =?function(){
????????alert(i);
????};
??}
};
?
/**
?*
?*/
var?add_the_handlers =?function(nodes){
????var?i;
????for(i=0; i<nodes.length; i+=1){
???????nodes.on allowScriptAccess="never" allowNetworking="internal" wmode="transparent"click =?function(){
?????????return?function(e){
???????????alert(e);
?????????}
???????}(i);
????}
};
?
7、继承
/**
?*?推荐以这种方式实现继承
?*/
if(typeof?Object.beget !==?'function'){
????Object.beget =?function(o){
???????var?F =?function(){};
???????F.prototype = o;
???????return?new?F();
????};
}
?
var?myMammal = {
????name :?'Herb the Mammal',
????get_name :?function(){
???????return?this.name;
????},
????says :?function(){
???????return?this.saying ||?'';
????}
};
?
var?myCat = Object.beget(myMammal);
myCat.name =?'Henrietta';
myCat.saying =?'meow';
myCat.purr =?function(n){
????var?i, s =?'';
????for(i = 0; i < n; i += 1){
???????if(s){
???????????s +=?'-';
???????}
???????s +=?'r';
????}
????return?s;
};
myCat.get_name =?function(){
????return?this.says +?' '?+?this.name +?' '?+?this.says;
};
?
三、数组
1、如何判断一个对像是不是数组
/**
?*?判断一个对象是不是数组
?*/
var?is_array =?function(value){
????return?value &&
???????????typeof?value ===?'object'?&&
???????????typeof?value.length ===?'number'?&&
???????????typeof?value.splice ===?'function'?&&
???????????!(value.propertyIsEnumerable('length'));
};
?
/**
?*?扩展reduce方法,
?*?接收一个计算函数和一个计算的初始值,
?*?并返回最后的计算结果
?*/
Array.method('reduce',?function(func, value){
??var?i;
??for(i=0; i<this.length; i+=1){
????value =?func(this[i], value);
??}
??return?value;
});
?
//下面是用法
?
var?data = [4, 8, 15, 16, 23, 42];
?
var?add =?function(a, b){
????return?a + b;
};
?
var?mult =?function(a, b){
????return?a * b;
};
?
var?sum = data.reduce(add, 0);?//sum = 108
var?product = data.reduce(mult, 1);?// product = 7418880
?
2、维度
JavaScript的数组通常不会初始化,如果你用[]得到一个新的数组,它将是空的。如果你访问一个不存在的元素,则将得到的值是undefined。我们可以设置一个Array.dim方法,用于创建和初始化数组。
/**
?*?创建并初始化一个数组
?*/
Array.dim =?function(dimension, initial){
????var?a = [], i;
????for(i=0; i<dimension; i+=1){
???????a[i] = initial;
????}
????return?a;
};
/**
?*?创建并初始化一个二维数组
?*/
Array.matrix =?function?(m, n, initial){
????var?a, i, j, mat = [];
????for(i=0; i<m; i+=1){
???????a = [];
???????for(j=0; j<n; j+=1){????
???????????a[j] = initial;
???????}
???????mat[i] = a;
????}
};
?
四、正则表达式
1、先确定哪些方法可以使用正则表达式
regexp.exec、regexp.test、string.match、string.replace、string.search、string.split
?
2、通过两个例子解析正则表达式
var?parse_url =?/^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
var?url =?"http://www.ora.com:80/goodparts?q#fragment";
?
/**
?*?让我们来调用parse_url的exec方法。
?*?如果能成功地匹配我们传给它的字符串,
?*?它将会返回一个数组,该数组包含了从这个url中提取出来的片段
?*?result结果为:
?*?['http://www.ora.com:80/goodparts?q#fragment',
?*??'http',
?*??'//',
?*??'www.ora.com',
?*??'80',
?*??'goodparts',
?*??'q',
?*??'fragment'
?*?]
?*/
var?result = parse_url.exec(url);
?
/**
?*?匹配一个数字,test方法返回boolean
?*/
var?parse_number =?/^-?\d+(?:\.\d*)?(?:e[+\-]?\d+)?$/i;
parse_number.test('1');??????//true
parse_number.test('number');?//false
parse_number.test('98.6');???//true
parse_number.test('132.21.03.10');?//false
parse_number.test('123.45E-67');???//true
parse_number.test('123.45D-67');???//false
?
?
/**
?*?解析:
?*?1、^字符表示这个字符串的开始。
?*?2、$字符表示这个字符串的结束。
?*?3、+字符表示1或多次。
?*?4、?字符表示0或1次。
?*?5、*字符表示0或多次。
?*?6、_字符表示任一字符
?*?7、[]字符表示只能对应包含的数据,[A-Za-z]表示:可以对应26个英文字母的大小写
?*?8、(?:...)字符表示一个非捕获型分组,(...)表示一个捕获型分组,
?*????说白了就是(...)括中的对应数据会放到匹配结果中,
?*????(?:...)就不会放到匹配结果中
?*?9、{m,?n}表示m-n之间次。
?*?10、|字符表示或
?*?11、.字符匹配除行结束符以外的任何字符
?*?12、\d=[0-9],\D相反。
?*?13、\s表示空白,\S相反。
?*?14、\w=[0-9A-Z_a-z],\W相反。
?*/
?