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 "&lt;";
                case ">" :
                    return "&gt;";
                case "&" :
                    return "&amp;";
                case """ :
                    return "&quot;";
            
            }
        })
    
    }
    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.sayHi = function(){
            alert("hi");
        }
        return clone;
    }
    var person = {
        name: "zhangsan",
        friends: ["lisi", "wangwu", "qianqi"]
    };
    var anotherPerson = createAnother(person);
    anotherPerson.sayHi();

6.3.6 寄生组合式继承

所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背
后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型
原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型
的原型。寄生组合式继承的基本模式如下所示

    function object(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
    function inheritPrototype(subType, superType){
        var protoobj = object(superType.prototype);//创建对象
        protoobj.constructor = subType;                //增强对象
        subType.prototype = protoobj;                //指定对象
    }
    
    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;
    }
    inheritPrototype(SubType, SuperType);
    SubType.prototype.sayAge = function(){
        alert(this.age);
    }

7 函数表达式

7.1 递归

arguments.callee是一个指向正在执行的函数的指针,用它来实现对函数的递归调用

//严格模式禁用
        function factorial(num){
            if(num<=1){
                return 1;
            }else{
                return num * arguments.callee(num-1);
            }
        }
        alert(factorial(5));

 //可以用命名函数表达式达到同样的效果

    var factorial = (function f(num){
            if(num <= 1){
                return 1;
            }else{
                return num * f(num - 1);
            }
    });
    var result = factorial(6);
    alert(result);

7.2 闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数

作用域链???

7.2.1 闭包与变量

闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量

    function createFunctions(){
        var result = new Array();
        for(var i=0; i<10; i++){
            result[i] = function(){
                return i;
            }
        }
        return result;
    }
    var r = createFunctions();
    alert(r[0]());//10 ,10...

創建匿名函数强制让闭包的行为符合预期

    function createFunctions(){
        var result = new Array();
        for(var i=0; i<10; i++){
            result[i] = function(num){
                return function(){
                    return num;
                };
            }(i);
        }
        return result;
    }
    var r = createFunctions();
    for(var j=0; j<r.length; j++){
        alert(r[j]());    
    }//0 1 2 ..

7.2.2 关于this对象

匿名函数的执行环境具有全局性, 因此其this对象通常指向window

  var name = "hello window";
  var object = {
    name : "my object",
    getNameFunc : function(){
        return function(){
            return this.name;
        };
    }
  };
  alert(object.getNameFunc()());//hello window

 每个函数在被调用时都会自动取得两个特殊变量, this和arguments.

内部函数在搜索这两个变量时, 只会搜索到其活动对象为止,因此不可能直接访问到外部函数中的这两个变量

不过将外部函数中的this对象保存到闭包能够访问到的变量里,就可以让闭包访问到该对象了 

  var name = "hello window";
  var object = {
    name : "my object",
    getNameFunc : function(){
        var that = this;
        return function(){
            return that.name;
        };
    }
  };
  alert(object.getNameFunc()());//my object

this的值可能会意外的改变

  var name = "hello window";
  var object = {
    name : "my object",
    getNameFunc : function(){
        return this.name;
    }
  };
  alert((object.getNameFunc = object.getNameFunc)());//

7.2.3内存泄漏

  <div id="myid">fffffff</div>
  <script>
window.onload = function(){
    function assignHandler(){
        var element = document.getElementById("myid");
        element.onclick = function(){
            alert(element.id);
        };
    }
    assignHandler();
}
  </script>     

由于匿名函数保存了一个对assignHandler()活动对象的引用,因此就会导致无法减少element的引用数  

     function assignHandler(){
        var element = document.getElementById("myid");
        var id = element.id;
        element.onclick = function(){
            alert(id + new Date());
        };
        element = null;
    }
    assignHandler();  

7.3 模仿块级作用域

用作块级作用域(通常称为私有作用域)的匿名函数的语法如下所示。
(function(){
//这里是块级作用域
})();

无论在什么地方,只要临时需要一些变量,就可以使用私有作用域  

    (function(){
        for(var i=0; i<10; i++){
        
        }
    })();
    
    alert(i);//i is not defined

通过创建私有作用域,每个开发人员既可以使用自己的变量,又不必担心搞乱全局作用域。

    (function(){
            var now = new Date();
            if(now.getMonth() ==0 && now.getDate() == 8){
                alert("good day 08/01");
            }
    })();

7.4 私有变量

任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量

function MyObject(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//特权方法
this.publicMethod = function (){
privateVariable++;
return privateFunction();
};
}

7.4.1 静态私有变量

(function(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//构造函数
MyObject = function(){
};
//公有/特权方法
MyObject.prototype.publicMethod = function(){
privateVariable++;
return privateFunction();
};
})();

MyObject 没使用var 是一个全局的变量

7.4.2 模块模式

,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有
数据的方法,那么就可以使用模块模式。

    var application = function(){
        var components = new Array();
         components.push("aaa");
         return {
            getComponentCount : function(){
                return components.length;
            },
            registerComponent : function(component){
                if(typeof component == "object"){
                    components.push(component);
                }
                
            }
         }
        
    }();
    alert(application.getComponentCount());
 7.4.3 增强的模块模式

    var application = function(){
        var components = new Array();
         components.push(new BaseComponent());
         var app = new BaseComponent();
         app.getComponentCount = function(){
            return components.length;
         };
         app.registerComponent = function(component){
            if(typeof component == "object"){
                components.push(component);
            }
         };
         return app;
        
        
    }();

  8. BOM

8.1 window对象

8.1.2 窗口关系及框架

001 top 对象始终指向最高(最外)层的框架,也就是浏览器窗口

       top.frames["topFrame"]

002 与top 相对的另一个window 对象是parent。顾名思义,parent(父)对象始终指向当前框架的
      直接上层框架。在某些情况下,parent 有可能等于top;但在没有框架的情况下,parent 一定等于
      top(此时它们都等于window)。

003 与框架有关的最后一个对象是self,它始终指向window

8.1.3窗口位置

var leftPos = (typeof window.screenLeft == "number")?(window.screenLeft):(window.screenX);
    var topPos = (typeof windwo.scrreenTop == "number")?(window.screenTop):(windwo.screenY);

使用moveTo()和moveBy()方法倒是有可能将窗口精确地移动到一个新位置。这两个方法都接收两个参数,其中

moveTo()接收的是新位置的x 和y 坐标值,而moveBy()接收的是在水平和垂直方向上移动的像素数

8.1.4 窗口大小

window.resizeTo(100, 100);//调整到(100, 100)

window.resizeBy(100, 50);//调整到(100+100, 100+50)

8.1.5 导航和打开窗口

001 使用window.open()方法既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口

接收4 个参数:要加载的URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值

第二个参数也可以是下列任何一个特殊的窗口名称:_self、_parent、_top 或_blank。

    var wroxWin = window.open("http://www.baidu.com", "wroxWindow", "width=400, height=400, top=10, left=10, resizable=true");
    wroxWin.resizeTo(500, 500);
    wroxWin.moveTo(100, 100);
    wroxWin.close();

8.1.6 超时调用和间歇调用

超时调用 window对象的setTimeout()方法, 他接受连个参数 1, 要执行的代码 2,毫秒表示的时间

该方法会返回一个数值ID,表示超时调用这个超时调用. ID 是计划执
行代码的唯一标识符,可以通过它来取消超时调用。要取消尚未执行的超时调用计划,可以调用
clearTimeout()方法并将相应的超时调用ID 作为参数传递给它,    

    var num = 0;
    var max = 10;
    var intervalId = null;
    function incrementNumber(){
        num++;
        if(num == max){
            clearInterval(intervalId);
            alert("Done");
        }
    }
    intervalId = setInterval(incrementNumber, 1000);

使用超时调用来模拟间歇调用的是一种最佳模式

8.1.7 系统对话框

alert()、confirm()和prompt()方法可以调用系统对话框向用户显示消息

通过这几个方法打开的对话框都是同步和模态的。也就是说,显示这
些对话框的时候代码会停止执行,而关掉这些对话框后代码又会恢复执行  

var result = prompt("What's your name?", "");
if(result !== null){
    alert("Welcome "+ result);
}  

8.2 location对象

location 对象是很特别的一个对象,因为它既是window 对象的属性,也是
document 对象的属性;换句话说,window.location 和document.location 引用的是同一个对象  

8.2.1 查询字符串参数

function getQueryStringArguments(){
    //取得查询字符串并去掉问号
    var qs = (window.location.search.length > 0 ? (window.location.search.substring(1)):""),
        //保存数据的对象
        args,
        //取得每一项
        items = qs.length ? qs.split('&') : [],
        item = null,
        name = null,
        value = null,
        //在for循环中使用
        i = 0,
        len = items.length;
        //逐个将每一项添加到args对象中
        for(i=0; i<len; i++){
            item = items[i].split('=');
            name = decodeURIComponent(item[0]);
            value = decodeURIComponent(item[1]);
            if(name.length){
                args[name] = value;
            }
        }
        return args;
}

8.2.2 位置操作

location.assign("http://www.wrox.com");

//假设初始URL 为http://www.wrox.com/WileyCDA/
//将URL 修改为"http://www.wrox.com/WileyCDA/#section1"
location.hash = "#section1";
//将URL 修改为"http://www.wrox.com/WileyCDA/?q=javascript"
location.search = "?q=javascript";
//将URL 修改为"http://www.yahoo.com/WileyCDA/"
location.hostname = "www.yahoo.com";
//将URL 修改为"http://www.yahoo.com/mydir/"
location.pathname = "mydir";
//将URL 修改为"http://www.yahoo.com:8080/WileyCDA/"
location.port = 8080;
每次修改location 的属性(hash 除外),页面都会以新URL 重新加载。  

location.reload(); //重新加载(有可能从缓存中加载)
location.reload(true); //重新加载(从服务器重新加载)

8.3 navigator对象

 8.3.1 检测插件

    function hasPlugin(name){
        name = name.toLowerCase();
        for(var i=0; i < navigator.plugins.length; i++){
            if(navigator.plugins[i].name.indexOf(name) > -1){
                return true;
            }
        }
        return false;
    }
    alert(hasPlugin("Flash"));
    alert(hasPlugin("QuickTime"));

IE 是以COM对象的方式实现插
件的,而COM对象使用唯一标识符来标识。因此,要想检查特定的插件,就必须知道其COM标识符

    function hasIEPlugin(name){
        try{
            new ActiveXObject(name);
            return true;
        }catch(ex){
            return false;
        }
    }
    alert(hasIEPlugin("ShockwaveFlash.ShockwaveFlash"));
    alert(hasIEPlugin("QuickTime.QuickTime")); 

结合

function hasFlash(){
    var result = hasPlugin("Flash");
    if(!result){
        result = hasIEPlugin("ShockwaveFlash.ShockwaveFlash");
    }
    return result;
}

 8.4 screen对象

window.resizeTo(screen.availWidth, screen.availHeight);

8.5 history对象

因为history 是window对象的属性,因此每个浏览器窗口、每个标签页乃至每个框架,都有自己的history 对象与特定的
window 对象关联。

使用go()方法可以在用户的历史记录中任意跳转

history.go(-1);//后退一页

history.go(1);//前进一页

history.go(2);//前进两页

也可以给go()方法传递一个字符串参数

//跳到最近的wrox.com

history.go("wrox.com");

back() forward()替代go()

history的length属性

if(history.length == 0){

  //这应该是用户打开窗口后的第一个页面

}

当页面的URL 改变时,就会生成一条历史记录。,这里所说的改变包括URL 中hash 的变
化(因此,设置location.hash 会在这些浏览器中生成一条新的历史记录)。

9  客户端检测

9.1 能力检测

function getElement(id){

  if(document.getElementById){

    return document.getElementById(id);

  }else if(document.all){

    return document.all[id];

  }else{

    throw new Error("No way to retrieve element");

  }

}

第一个概念就是先检测达成目的的最常用的特性。

第二个重要的概念就是必须测试实际要用到的特性

9.1.1 更可靠的能力检测

检测对象是否支持排序

function isSortable(object){

  return typeof object.sort == "function";

}

ActiveX对象和其他对象相差很大

function isHostMethod(object, property){
    var t = typeof object[property];
    return t=='function' || (t=='object' && object[property]) || t=='unknown';
}
var xhr = new ActiveXObject("Microsoft.XMLHttp");
alert(isHostMethod(xhr, 'open'));
alert(isHostMethod(xhr, "foo"));

9.1.2 能力检测不是浏览器检测

var hasNSPlugins = (!!(navigator.plugins && navigator.plugins.length)) ;

var hasDOM1 = (!!(document.getElementById && document.createElement && document.getElementsByTagName)); 

p238

原文地址:https://www.cnblogs.com/rocky-fang/p/6163829.html