Professional JavaScript for Web Developers 3rd Edition ---读书笔记
Posted rocky-fang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Professional JavaScript for Web Developers 3rd Edition ---读书笔记相关的知识,希望对你有一定的参考价值。
1. DOMContentLoaded DOM树构建完成时触发该事件
load 页面加载完毕触发
原生js
document.addEventListener(\'DOMContentLoaded\', function(){ //code..... }, false); document.addEventListener(\'load\', function(){ //code... }, false);
jquery
//DOMContentLoaded $(document).ready(function(){ //code... }); //load $(document).load(function(){ //code... });
2. Xhtml中的用法
小于号(<)再xhtml中会被当做开始一个新标签来解析, 作为标签后面不能根空格。
不兼容xhtml
3. 区分大小写
变量名test和Test表示两个不同的变量
4. 注释
//单行注释
/**/多行注释
5. 严格模式
"use strict";
6. ECMAScriptz中有5中简单的数据类型 Undefined、Null、Boolean、Number、String
和 1中复杂数据类型 Object(Object实际上是一组无序的名值对组成)
7. typeof操作符
typeof null 返回object, 因为特殊值null被认为是一个空的对象引用
8. Undefined类型
该类型只有一个值, 即undefined;
使用var声明变量但未初始化时, 这个变量的值就是undefined。var message; alert(message);//undefined alert(message == undefined);//true
如果变量未声明, 使用会出错,如alert(age); ReferenceError: age is not defined; typeof age //undefined 使用var声明或没声明都返回undefined
9.Null类型
该类型只有一个值null
如果定义的变量在将来用于保存对象, 那么最好将它初始化为null。
undefined派生自null alert(null == undefined)//true, (==)相等操作符属于比较的目的会转换其操作数
10. Boolean类型
该类型只有两个字面量值 true和false
要将一个值转换为其对应的Boolean值, 可以调用转型函数Boolean().
Boolean("hello world");//true 非空字符串
Boolean("");//false 空字符串
这些转换规则对流控制语句(if)自动执行相应的Boolean转换非常重要
如
var message = "hello world";
if(message){alert}
11. Number类型
11.1 8进制 在数字前面加0 如 071表示 57; 如果字面值超过了范围, 则前导0将被忽略 如 079 表示79
在严格模式下无效
16进制 在字面量0x a-f 可以大小写
11.2 浮点数 科学计数法 e , e前面的数值乘以10的指数次幂 var a = 3.123e3// 3123
最小值 Number.MIN_VALUE
最大值 Number.MAX_VALUE
NaN (Not a Number) b任何数值除以0 都会返回NaN
特点: 1. NaN/10 //NaN 任何操作返回NaN
2. NaN == NaN //false
11.3 isNan(param)函数 某些不是数值的值会被转换为数值,然后返回false, 如 "10"或者 true(被转换为1); 不能 被转换为数值的值返回true
11.4 数值转换
有3个函数可以把非数值转换为数值 Number(), parseInt(), parseFloat
例子
parseInt函数在转换字符串时,更多的是看其是否符合数值模式, 他会忽略字符串前面的空格, 直到第一个非空格字符
例子
注意
消除困惑, 提供第二个参数(转换时使用的基数 进制)
var num1 = parseInt(\'AF\', 16);//175
var num2 = parseInt(\'AF\');//NaN
建议:无论在什么情况下都明确指明基数
parseFloat的典型示例
12. String类型
转换为字符串
注意 null 和 undefined值没有这个方法; 默认十进制, 可以输出其他进制的字符串
String()函数
另一种转换成字符串的方式 (x + "")
13. Object类型
3.5 操作符
3.5.1 一元操作符
1. 递增 递减 操作符
示例
2. 有符号整数
3.5.3 布尔操作符
001 逻辑非
同时使用两个逻辑非操作符(!!)就会模拟Boolean()转型函数的行为
例子
002 逻辑与(&&)
注意 : 逻辑与是一个短路操作符
003 逻辑或
3.5.4 乘性操作符
001 乘法
002 除法
003 求模
3.5.5 加性操作符
001 加法
002 减法
几个例子
3.5.6 关系操作符
大写字母的字符编码全部小于小写字母的字符编码
任何操作数与NaN比较 结果都是false
var result1 = NaN < 3; //false
var result2 = NaN >= 3; //false
3.5.7 相等操作符
001 相等和不相等( == 和 !=)
比较之前转换操作数
比较时的规则
002 全等和不全等
比较之前不转换操作数
var result1 = "55" == 55;//true
var result2 = ("55" ===55); //false
3.5.8 条件操作符
3.5.9 赋值操作符
复合赋值操作符 +=之类
3.5.10 逗号操作符
在用于赋值时, 逗号运算符总是返回最后一项
var num = (5, 1, 3, 4, 0);//0
3.6.2 do-while语句
var i=0;
do{
i+=2;
}while(i<10);
alert(i);
3.6.4 for语句
由于ECMAScript 中不存在块级作用
域(第4 章将进一步讨论这一点),因此在循环内部定义的变量也可以在外部访问到。
即使i 是
在循环内部定义的一个变量,但在循环外部仍然可以访问到它。
3.6.5 for-in语句
这个过程会一直持续到对象中的
所有属性都被枚举一遍为止。与for 语句类似,这里控制语句中的var 操作符也不是必需的。但是,
为了保证使用局部变量,我们推荐上面例子中的这种做法。
ECMAScript 对象的属性没有顺序。因此,通过for-in 循环输出的属性名的顺序是不可预测的。
但是,如果表示要迭代的对象的变量值为null 或undefined,for-in 语句会抛出错误。
ECMAScript 5 更正了这一行为;对这种情况不再抛出错误,而只是不执行循环体。为了保证最大限度的
兼容性,建议在使用for-in 循环之前,先检测确认该对象的值不是null 或undefined
3.6.6 label语句
3.6.7 break和 continue语句
outermost : for(){};
break:outermost 从outermost后开始执行
continue: outermost 从outermost开始执行
3.7 函数
ECMAScript 中的函数在定义时不必指定是否返回值 实际上,任何函数在任何时候都可以通过
return 语句后跟要返回的值来实现返回值
另外,return 语句也可以不带有任何返回值。在这种情况下,函数在停止执行后将返回undefined
值。这种用法一般用在需要提前停止函数执行而又不需要返回值的情况下
3.7.1理解参数
这个事实说明了ECMAScript 函数的一个重要特点:命名的参数只提供便利,但不是必需的。另
外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来的调用必须与该签名一致。但
在ECMAScript 中,没有这些条条框框,解析器不会验证命名参数。
虽然这个特性算不上完美的重载,但也足够弥补ECMAScript 的这一缺憾了。
关于arguments 的行为,还有一点比较有意思。那就是它的值永远与对应命名参数的值保持同步。
,这并不是说读取这两个值会访问相同的内存空间;它们的内存空间是独立的,但它们的值会同步。
另外还要记住,如果只传入了一个参数,那么为arguments[1]设置的值不会反应到
命名参数中。这是因为arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名
参数的个数决定的。
4.1 基本类型和引用类型的值
基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。
4.1.1 动态的属性
var person = new Object();
person.name = "zhangsan";
4.1.2 复制变量值
4.1.3 传递参数
4.1.4 检测类型
typeof 检测基本类型
知道某个值是什么类型的对象 instanceof
var result = variable instanceof constructor
如果变量是给定引用类型的实例, 那么instanceof就返回true
如果使用instanceof检测基本类型的值, 则该操作符始终返回false, 因为基本类型不是对象
4.2 没有块级作用域
任何位于局部变量color 的声明之后的代码,如果不使用window.color 都无法访问全局color变量
4.3.2 引用计数
消除循环引用
myObject.element = null;
element.someObject = null;
为了解决上述问题,IE9 把BOM 和DOM 对象都转换成了真正的javascript 对象。这样,就避免了
两种垃圾收集算法并存导致的问题,也消除了常见的内存泄漏现象。
5.1 Object对象
创建Object对象的两种方式:
001 new 操作符
var person = new Object();
person.name = "zhangsan";
002 对象字面量
var person = {
name : "zhangsan",
age : 19
};
可以使用方括号来访问对象的属性
person["first name"]
5.2 Array类型
创建数组的基本方式有两种
001 Array 构造函数
var color = new Array();
002 使用数组字面量
var color = ["red", "blue", "green"];
数组的项数保存在length属性中( 0+) 通过设置这个属性, 可以从数组的末尾移除项 或向数组中添加新项
var colors = ["red", "blue", "green"];
colors.length = 2;
alert(colors[2]);//undefined
colors.length = 4;
alert(colors[3]);//undefined
利用这个特性可以方便的添加新项
colors[colors.length] = "gray";
colors[colors.length] = "yellow";
5.2.1 检测数组
5.2.2 转换方法
所有对象都有 toLocaleString(), toString(), valueOf()方法
var colors = ["red", "blue", "green"]; // 创建一个包含3 个字符串的数组
alert(colors.toString()); // red,blue,green
alert(colors.valueOf()); // red,blue,green
alert(colors); // red,blue,green
如果使用join() 方法, 可以使用不同的分隔符来创建这个字符串
colors.join("&");// red&blue&green
5.2.3 栈方法
push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。而
pop()方法则从数组末尾移除最后一项,减少数组的length 值,然后返回移除的项。
var colors = new Array();
var count = colors.push("green", "blue");
alert(count);//2
var item = colors.pop();
alert(item);//blue
5.2.4 队列方法
因此要模拟队列只需一个从数组前端取得项的方法。实现这一操作的数组方法就是shift(),它能够移
除数组中的第一个项并返回该项,同时将数组长度减1。结合使用shift()和push()方法,可以像使
用队列一样使用数组。
var item = colors.shift();
alert(item);//green
unshift()与shift()的用途相反:
它能在数组前端添加任意个项并返回新数组的长度。因此,同时使用unshift()和pop()方法,可以
从相反的方向来模拟队列,即在数组的前端添加项,从数组末端移除项
5.2.5 重排序
数组中有两个重排序方法
reverse() 反转数组项的顺序
sort() 即使数组中的每一项都是数值, sort() 方法比较的也是字符串(调用每一项的toString()方法 然后比较字符串)
var values = [0, 1, 5, 10, 15];
values.sort();
alert(values); //0,1,10,15,5
sort()方法可以接收一个比较函数作为参数,以便我们指定哪个值位于哪个值的前面。
比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等
则返回0,如果第一个参数应该位于第二个之后则返回一个正数
function compare(value1, value2) {//升序 if (value1 < value2) { return -1;//return 1 降序 } else if (value1 > value2) { return 1; } else { return 0; } } var values = [0, 1, 5, 10, 15]; values.sort(compare); alert(values); //0,1,5,10,15
5.2.6 操作方法
001 concat()方法
002 slice() 方法
003 splice()方法
splice()方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何
项,则返回一个空数组)
5.2.7 位置方法
indexOf()
lastIndexOf()
var numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4,4));
alert(numbers.lastIndexOf(4, 4));
5.2.8 迭代方法
var numbers = [1,2,3,4,5,4,3,2,1]; var everyResult = numbers.every(function(item, index, array){ return (item > 2); }); alert(everyResult); //false var someResult = numbers.some(function(item, index, array){ return (item > 2); }); alert(someResult); //true
var filterResult = numbers.filter(function(item, index, array){
return (item > 2);
});
alert(filterResult); //[3,4,5,4,3]
var mapResult = numbers.map(function(item, index, array){
return item * 2;
});
alert(mapResult); //[2,4,6,8,10,8,6,4,2]
最后一个方法是forEach(),它只是对数组中的每一项运行传入的函数。这个方法没有返回值,
本质上与使用for 循环迭代数组一样。来看一个例子。
var numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array){
//执行某些操作
});
5.2.9 归并方法
reduce()和reduceRight()。这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。
其中,reduce()方法从数组的第一项开始,逐个遍历到最后。
而reduceRight()则从数组的最后一项开始,向前遍历到第一项
给reduce()和reduceRight()的函数接收4 个参数:前一个值、当前值、项的索引和数组对象。这
个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第
一个参数是数组的第一项,第二个参数就是数组的第二项
var values = [1,2,3,4,5]; var sum = values.reduce(function(prev, cur, index, array){ return prev + cur; }); alert(sum); //15
reduceRight()的作用类似,只不过方向相反而已
5.3 Date类型
var now = new Date();不传递参数的情况下,新创建的对象自动获得当前日期和时间
001 Date.parse()方法接收一个表示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数。
如果直接将表示日期的字符串传递给Date 构造函数,也会在后台调用Date.parse()
var someDate = new Date(Date.parse("May 25, 2004"));等价于
var someDate = new Date("May 25, 2004");
002 Date.UTC() 日期和时间都基于本地时区而非GMT 来创建
// GMT 时间2005 年5 月5 日下午5:55:55
var allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
// 本地时间2005 年5 月5 日下午5:55:55
var allFives = new Date(2005, 4, 5, 17, 55, 55);
003 Data.now()
//取得开始时间
var start = Date.now();
使用+操作符把Data 对象转换成字符串,也可以达到同样的目的。
//取得开始时间
var start = +new Date();
5.3.1 继承的方法
Date 类型也重写了toLocaleString()、toString()和valueOf()方法;
5.3.3 日期/时间组件方法 p120
5.4 RegExp类型
创建正则表达式 var expression = /pattern/flags;
其中的模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符类、限定符、分组、向前查找以及反向引用
正则表达式的匹配模式支持下列3 个标志。
g:表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即
停止;
i:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模
式匹配的项。
因此,一个正则表达式就是一个模式与上述3 个标志的组合体。不同组合产生不同结果
001 以字面量形式来定义的正则表达式
/* * 匹配所有".at",不区分大小写 */ var pattern4 = /\\.at/gi;
002 RegExp 构造函数创建正则表达式
/* * 与pattern1 相同,只不过是使用构造函数创建的 */ var pattern2 = new RegExp("[bc]at", "i");
ECMAScript 5 明确规定,使用正则表达式字面量必须像直接调用RegExp 构造函数一样,每次都创
建新的RegExp 实例。
5.5 Function类型
函数实际上是对象
每个函数实际上都是Function类型的实例
函数名实际上也是一个指向函数对象的指针
5.5.3 作为值的函数
function callSomeFunction(someFunction, someArgument){
return someFunction(someArgument);
}
例子
function createComparisonFunction(propertyName){
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1 < value2){
return -1;
}else if( value1 > value2){
return 1;
}else{
return 0;
}
}
}
var data = [{name : "zhangsan", age : 15},{name : "lisi", age : 18}];
data.sort(createComparisonFunction(\'name\'));
alert(data[0].name);//lisi
data.sort(createComparisonFunction(\'age\'));
alert(data[0].name);//zhangsan
5.5.4 函数内部属性
001 arguments对象还有一个名叫callee 的属性,该属性是一个指针,指向拥有这个arguments 对象的函数
消除紧密耦合的现象
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * arguments.callee(num-1);
}
}
002 this 对象
window.color = "red";
var o = {color : "blue"};
function sayColor(){
alert(this.color);
}
sayColor();//red
o.sayColor = sayColor;
o.sayColor();//blue
003 函数对象的属性 caller
function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller);
}
outer();
5.5.5 函数属性和方法
001 length属性
length 属性表示函数希望接收的命名参数的个数
002 prototype属性
引用类型而言,prototype 是保存它们所有实例方法的真正所在
prototype 属性是不可枚举的,因此使用for-in 无法发现
003 apply() 和 call() 非继承而来的方法 每个函数都包含
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this, arguments); // 传入arguments 对象
}
function callSum2(num1, num2){
return sum.apply(this, [num1, num2]); // 传入数组
}
alert(callSum1(10,10)); //20
alert(callSum2(10,10)); //20
在使用call()方法时,传递给函数的参数必须逐个列举出来
function callSum(num1, num2){
return sum.call(this, num1, num2);
}
alert(callSum(10,10)); //20
这两个方法真正强大的地方是能够扩充函数赖以运行的作用域。
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
使用call()(或apply())来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。
004 bind()
这个方法会创建一个函数的实例 其this 值会被绑定到传给bind()函数的值。例如:
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
5.6 基本包装类型
var s1 = "some text";
var s2 = s1.substring(2);
当第二行代码访问s1 时,访问过程处于一种读取模式,也就是要从内存中读取这个字符串的值。
而在读取模式中访问字符串时,后台都会自动完成下列处理
(1) 创建String 类型的一个实例;
(2) 在实例上调用指定的方法;
(3) 销毁这个实例。
引用类型与基本包装类型的主要区别就是对象的生存期。使用new 操作符创建的引用类型的实例,
在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一
行代码的执行瞬间,然后立即被销毁
Object 构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。例如:
var obj = new Object("some text");
alert(obj instanceof String); //true
5.6.1 Boolean类型
var falseObject = new Boolean(false);
var result = falseObject && true;
alert(result); //true
var falseValue = false;
result = falseValue && true;
alert(result); //false
布尔表达式中的所有对象都会被转换为true,因此falseObject 对象在布尔表达式中代表的是true。
基本类型与引用类型的布尔值还有两个区别。首先,typeof 操作符对基本类型返回"boolean",
而对引用类型返回"object"。其次,由于Boolean 对象是Boolean 类型的实例,所以使用instanceof
操作符测试Boolean 对象会返回true,而测试基本类型的布尔值则返回false。例如:
alert(typeof falseObject); //object
alert(typeof falseValue); //boolean
alert(falseObject instanceof Boolean); //true
alert(falseValue instanceof Boolean); //false
5.6.2 Number类型
var num = 10;
alert(num.toFixed(2)); //"10.00"
5.6.3 String类型
001 字符方法
charAt() charCodeAt()
var stringValue = "hello world";
alert(stringValue.charAt(1)); //"e"
var stringValue = "hello world";
alert(stringValue.charCodeAt(1)); //输出"101"
002 字符串操作方法
concat()用于将一或多个字符串拼接起来,返回拼接得到的新字符串。
var stringValue = "hello ";
var result = stringValue.concat("world");
alert(result); //"hello world"
alert(stringValue); //"hello"
slice()、substr()和substring()。
这三个方法都会返回被操作字符串的一个子字符串,而且也都接受一或两个参数
slice()和
substring()的第二个参数指定的是子字符串最后一个字符后面的位置。而substr()的第二个参数指
定的则是返回的字符个数。如果没有给这些方法传递第二个参数,则将字符串的长度作为结束位置
var stringValue = "hello world";
alert(stringValue.slice(3)); //"lo world"
alert(stringValue.substring(3)); //"lo world"
alert(stringValue.substr(3)); //"lo world"
alert(stringValue.slice(3, 7)); //"lo w"
alert(stringValue.substring(3,7)); //"lo w"
alert(stringValue.substr(3, 7)); //"lo worl"
003 字符串位置方法
indexOf() lastIndexOf()
var stringValue = "hello world";
alert(stringValue.indexOf("o")); //4
alert(stringValue.lastIndexOf("o")); //7
var stringValue = "hello world";
alert(stringValue.indexOf("o", 6)); //7
alert(stringValue.lastIndexOf("o", 6)); //4
004 trim()方法
这个方法会创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果。
005 大小写转换
toLowerCase()、toLocaleLowerCase()、toUpperCase()和toLocaleUpperCase()
006 字符串模式匹配方法
006-1 match() 只接受一个参数,要么是一个正则表达式,要么是一个RegExp 对象 . 本质上与调用RegExp 的exec()方法相同
var text = "cat, bat, sat, fat";
var pattern = /.at/;
//与pattern.exec(text);相同
var matches = text.match(pattern);
alert(matches.index);//0
alert(matches[0]);//cat
alert(pattern.lastIndex);//0
006-2 search()
search()方法返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1。
var pos = text.search(/.at/);
alert(pos);//1
006-3 replace()
这个方法接受两个参数:第一个参数可以是一个RegExp 对象或者一个字符串(这个字符串不会被转换成正则表达式),
第二个参数可以是一个字符串或者一个函数。
如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,唯一的办法就是提供一个正则表达式,而且要指定全局(g)标志
var result = text.replace("at", "rocky");
alert(text);//"crocky, bat, sat, fat"
result = text.replace(/at/g, "rocky");
alert(text);//"crocky brocky, srocky, frocky"
replace() 第二个参数也可以是一个函数 这个函数传递3 个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串
function htmlEscape(text){
return text.replace(/[<>"&]/g, function(match, pos, originalText){
switch(match){
case "<" :
return "<";
case ">" :
return ">";
case "&" :
return "&";
case "\\"" :
return """;
}
})
}
alert(htmlEscape("<p class=\\"greeting\\">Hello world!</p>"));
006-4 split()
var colorText = "red,blue,green,yellow";
var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"]
var colors2 = colorText.split(",", 2); //["red", "blue"]
var colors3 = colorText.split(/[^\\,]+/); //["", ",", ",", ",", ""]
007 localeCompare()方法
var stringValue = "yellow";
alert(stringValue.localeCompare("brick")); //1
alert(stringValue.localeCompare("yellow")); //0
alert(stringValue.localeCompare("zoo")); //-1
008 fromCharCode()方法
与实例方法charCodeAt()执行的是相反的操作
alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"
5.7 单体内置对象
5.7.1 Global对象 不属于任何其他对象的属性和方法,最终都是它的属性和方法
没有全局变量或全局函数;所有在全局作用域中定义的属性和函数,都是Global 对象的属性。
001 URI编码方法
Global 对象的encodeURI()和encodeURIComponent()方法可以对URI(Uniform ResourceIdentifiers,通用资源标识符)进行编码
它们的主要区别在于,encodeURI()不会对本身属于URI 的特殊字符进行编码,例如冒号、正斜杠、
问号和井字号;而encodeURIComponent()则会对它发现的任何非标准字符进行编码。
var uri = "http://www.wrox.com/illegal value.htm#start";
//"http://www.wrox.com/illegal%20value.htm#start"
alert(encodeURI(uri));
//"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
alert(encodeURIComponent(uri));
decodeURI()只能对使用encodeURI()替换的字符进行解码
decodeURIComponent()能够解码使用encodeURIComponent()
002 eval()方法
eval("function sayHi() { alert(\'hi\'); }");
sayHi();
在eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,它们被包含在一个字
符串中;它们只在eval()执行的时候创建。
003 Global对象的属性
004 window对象
在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。
JavaScript中的window 对象除了扮演ECMAScript规定的Global 对象的角色外,还承担了很多别的任务
另一种取得Global 对象的方法是使用以下代码:
var global = function(){
return this;
}();
5.7.2 Math对象
002 min() max()
var max = Math.max(3, 54, 32, 16);
alert(max); //54
var min = Math.min(3, 54, 32, 16);
alert(min); //3
var values = [1, 2, 3, 4, 5, 6, 7, 8];
var max = Math.max.apply(Math, values);
003 舍入方法
Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;
Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数;
Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数(这也是我们在数学课
上学到的舍入规则)。
004 random() 方法
Math.random()方法返回大于等于0 小于1 的一个随机数。
var num = Math.floor(Math.random() * 10 + 1);// 1.....10
var num = Math.floor(Math.random() * 9 + 2);// 2... 10
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)
function selectFrom(lowerValue, upperValue){
var choices = upperValue - lowerValue + 1;
return Math.floor(Math.random() * choices + lowerValue);
}
var num = selectFrom(2, 10);// 2 || 3..||10
var colors = ["green", "red", "blue", "black", "white"];
var color = colors[selectFrom(0, colors.length-1)];
6 面向对象的程序设计
6.1 理解对象
对象字面量
var person = {
name : "Zhang san",
age : 18,
job : "Software Engineer",
sayName : function(){
alert(this.name);
}
6.1.1属性类型
001 数据属性
[[Configurable]]:表示能否通过delete 删除属性从而重新定义属性,能否修改属性的特
性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的
这个特性默认值为true。
[[Enumerable]]:表示能否通过for-in 循环返回属性。像前面例子中那样直接在对象上定
义的属性,它们的这个特性默认值为true。
[[Writable]]:表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的
这个特性默认值为true。
[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,
把新值保存在这个位置。这个特性的默认值为undefined。
要修改属性默认的特性,必须使用ECMAScript 5 的Object.defineProperty()方法。这个方法
接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属
性必须是:configurable、enumerable、writable 和value。设置其中的一或多个值,可以修改
对应的特性值。例如:
var person = {};
Object.defineProperty(person, name , {
writable : false,
value : "zhang san"
});
alert(person.name);//zhangsan
person.name = "lisi";
alert(person.name);//zhangsan
Object.defineProperty(person, name, {
configurable : false,
value : "zhangsan"
});
delete person.name;
alert(person.name);//zhangsan
一旦把属性定义为不可配置的,就不能再把它变回可配置了
//抛出错误
Object.defineProperty(person, "name", {
configurable: true,
value: "Nicholas"
});
002 访问器属性
[[Configurable]]:表示能否通过delete 删除属性从而重新定义属性,能否修改属性的特
性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,这个特性的默认值为
true。
[[Enumerable]]:表示能否通过for-in 循环返回属性。对于直接在对象上定义的属性,这
个特性的默认值为true。
[[Get]]:在读取属性时调用的函数。默认值为undefined。
[[Set]]:在写入属性时调用的函数。默认值为undefined。
访问器属性不能直接定义,必须使用Object.defineProperty()来定义
var book = {
_year : 2004,
edition : 1
};
Object.defineProperty(book, "year", {
get: function(){
return this._year;
},
set : function(newValue){
if(newValue > 2004){
this._year = newValue;
this.edition += newValue -2004;
}
}
});
book.year = 2005;
alert(book.edition);
_year 前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。
而访问器属性year 则包含一个
getter 函数和一个setter 函数。getter 函数返回_year 的值,setter 函数通过计算来确定正确的版本。因此,
把year 属性修改为2005 会导致_year 变成 2005,而edition 变为2。这是使用访问器属性的常见方
式,即设置一个属性的值会导致其他属性发生变化。
6.1.2 定义多个属性
Object.dedineProperties()
利用这个方法可以通过描述符一次定义多个属性。这个方法接收两个对象参数:
第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应。
var book = {};
Object.defineProperties(book, {
_year: {
value: 2014
},
edition: {
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if(newValue>2004){
this._year = newValue;
this.edition += newValue-2004;
}
}
}
});
6.1.3读取属性的特性
Object.getOwnPropertyDescriptor(book, "year");
6.2 创建对象
6.2.1 工厂模式
开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
}
return o;
}
var person1 = createPerson("zhangsan", 18, "engineer");
var person2 = createPerson("lisi", 16, "doctor");
6.2.2 构造函数模式
function Person(name, age, job){\'
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}
}
var person3 = new Person("wangwu", 20, "farmer");
alert(person3.constructor == Person);//true
alert(person3 instanceof Person);//true
alert(person3 instanceof Object);//true
001 将构造函数作为函数
// 当作构造函数使用
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"
// 作为普通函数调用
Person("Greg", 27, "Doctor"); // 添加到window
window.sayName(); //"Greg"
// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "zhaolui", 22, "worker");
o.sayName();//zhaolui
6.2.3 原型模式
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,
而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。如果按照字面意思来理解,那
么prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以
让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是
可以将这些信息直接添加到原型对象中
001 理解原型对象
Person.prototype.constructor指向Person
Person.prototype.isPrototypeOf(person1);//true
Object.getPrototypeOf(person1) == Person.prototype;//true
Object.getPrototypeOf(person1).name ;//"zhangsan"
虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们
在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该
属性将会屏蔽原型中的那个属性。
function Person(){}
Person.prototype.name = "zhangsan";
Person.prototype.age = 18;
Person.prototype.sayName = function(){
alert(this.name);
}
var person1 = new Person();
var person2 = new Person();
person1.name = "lisi";
alert(person1.name);//lisi 来自实例
alert(person2.name);//zhangsan 来自原型
delete person1.name;
alert(person1.name);//zhangsan 来自原型
hasOwnProperty()
alert(person1.hasOwnProperty("class"));//false
person1.class = "001";
alert(person1.hasOwnProperty("class"));//true
002 原型与in操作符
alert("name" in person1);//true
同时使用hasOwnProperty()方法和in 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中
function hasPrototypeProperty(object, name){
return !object.hasOwnProperty(name) && (name in object);
}
在使用for-in 循环时,返回的是所有能够通过对象访问的、可枚举的(enumerated)属性,其中
既包括存在于实例中的属性,也包括存在于原型中的属性。屏蔽了原型中不可枚举属性(即将
[[Enumerable]]标记为false 的属性)的实例属性也会在for-in 循环中返回,因为根据规定,所
有开发人员定义的属性都是可枚举的——只有在IE8 及更早版本中例外
取得对象上的所有可枚举属性 Object.keys() 这个的方法接受一个对象作为参数 返回一个包含所有可枚举属性的字符串数组
var keys = Object.keys(Person.prototype);
alert(keys);//"name,age, job, sayName"
var p1 = new Person();
p1.name = "zhangsan";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys);//"name, age"
003 更简单的原型语法
function Person(){
}
Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
以这种方式重设constructor 属性会导致它的[[Enumerable]]特性被设置为true
//重设构造函数,只适用于ECMAScript 5 兼容的浏览器
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false,
value: Person
});
004 原型的动态性
005 原生对象的原型
所有原生引用类型(Object、Array、String,等等)都在其构造函数的原型上定义了方法。
6.2.4 组合使用构造函数模式和原型模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["zhangsan", "lisi"];
}
Person.prototype = {
constructor: Person,
sayName: function(){
alert(this.name);
}
};
var person1 = new Person("wangwu", 22, "worker");
var person2 = new Person("zhaoliu", 23, "doctor");
person1.friends.push("qianqi");
alert(person1.friends);
alert(person2.friends);
alert(person1.friends == person2.friends);
alert(person2.sayName == person2.sayName);
6.2.5 动态原型模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
if(typeof this.sayName != \'function\'){
Person.prototype.sayName = function(){
alert(this.name);
}
}
}
var person1 = new Person("wangwu", 22, "worker");
person1.sayName();
6.2.6 寄生构造函数模式
function Person(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
}
return o;
}
var person1 = new Person("zhangwan", 11, "doctor");
person1.sayName();
6.2.7 稳妥构造函数模式
所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this 的对象。
稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建对象的实例方法不引用this;二是不使用new 操作符调用构造函数。
function Person(name, age, job){
var o = new Object();
o.sayName = function(){
alert(name);
}
return o;
}
var person1 = Person("zhangsan", 18, "doctor");
person1.sayName();
6.3 继承
ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链来实现的。
6.3.1原型链
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());
alert(instance.getSubValue());
001 别忘记默认的原型Object
002 确定原型和实例的关系
instance instanceof object//true
object.isProprotypeof(instance)//true
003 谨慎的定义方法 字面量
004 原型链的问题
问题一 包含引用类型值的原型属性会被所有实例共享
问题二 应该说是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数
6.3.2 借用构造函数(constructor stealing)
这种技术的基本思想相当简单,即在子类型构造函数的内部调用超类型构造函数
通过使用apply()和call()方法也可以在(将来)新创建的对象上执行构造函数,
function SuperType(){
this.colors = ["red", "green", "blue"];
}
function SubType(){
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);
var instance2 = new SubType();
alert(instance2.colors);
001 传递参数
function SuperType(name){
this.name = name;
}
function SubType(){
SuperType.call(this, "zhangsan");
this.age = 12;
}
var instance1 = new SubType();
alert(instance1.name);
alert(instance1.age);
6.3.3 组合继承(combination inheritance)
function SuperType(name){
this.name = name;
this.colors = ["red", "green", "blue"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name, age){
//继承属性
SuperType.call(this, name);
this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.costructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType("zhangsan", 11);
instance1.colors.push("black");
instance1.sayName();
alert(instance1.colors);
instance1.sayAge();
var instance2 = new SubType("lisi", 22);
instance2.sayName();
alert(instance2.colors);
instance2.sayAge();
6.3.4 原型式继承(Prototypal inheritance in JavaScript)
道格拉斯·克罗克服 他的想法是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型
function object(o){
function F(){};
F.prototype = o;
return new F();
}
在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的
原型,最后返回了这个临时类型的一个新实例。从本质上讲,object()对传入其中的对象执行了一次浅复制
function object(o){
function F(){}
F.prototype = o;
return new F();
}
var person = {
name : "zhangsan",
friends : ["lisi", "wangwu", "zhaoliu"]
};
var anotherPerson = object(person);
anotherPerson.name = "zhangsan2";
anotherPerson.friends.push("zhangxiong");
alert(anotherPerson.name);
alert(anotherPerson.friends);
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "zhangsan3";
yetAnotherPerson.friends.push("zhangwei");
alert(yetAnotherPerson.name);
alert(yetAnotherPerson.friends);
ECMAScript 5 通过新增Object.create()方法规范化了原型式继承。这个方法接收两个参数:一
个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象
var person = {
name : "zhangsan",
friends : ["lisi", "wangwu", "zhaoliu"]
};
var anotherPerson = Object.create(person, {
name: {
value: "zhangsan11"
}
});
alert(anotherPerson.name);
6.3.5 寄生式继承(parasitic)
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function createAnother(original){
var clone = object(original);
clone.sayH
以上是关于Professional JavaScript for Web Developers 3rd Edition ---读书笔记的主要内容,如果未能解决你的问题,请参考以下文章
pycharm-professional-2017.1.1.exe专业版激活方法
pycharm-professional-2017.1.1.exe专业版激活方法