js红宝书总结笔记

一.JS的简介:javascript

1.宿主环境:浏览器、node、adobe flash;php

2.DOM(文档对象模型)是针对 XML 但通过扩展用于 HTML 的应用程序编程接口(API):css

DOM0级:即DHTML;    DOM1级:主要映射文档结构; DOM2级:增长视图,样式,事件,遍历和范围; DOM3级:增长验证等方法;html

3.BOM(浏览器对象模型)前端

 

二.在html中使用jshtml5

1.script的属性:defer(html4.01):脚本延迟至页面加载完成后执行;async(html5):没必要等待脚本下载,异步加载页面其余内容;java

 

三.基本概念:node

1.严格模式:"use strict";ios

2.用 var 操做符定义的变量将成为定义该变量的做用域中的局部变量;web

3.ECMAScript5 中有 5 种基本数据类型: Undefined 、 Null 、 Boolean 、 Number和 String 。还有 1种复杂数据类型—— Object;

a.typeof操做符:“undefined”、'boolean'、'string'、'number'、'object'、'function'.(null会被认为是一个空的对象引用,返回object);

b.自动数据类型转换:true(true,非空字符串,非0数字,任何对象)   false(false,空字符串,0和NaN,null,undefined);

c.转义字符:\n(换行),\t(制表),\b(空格),\r(回车),\\,  \' ,\";

d.将一个值转为字符串,能够+'';

e.object的属性和方法:constructor   hasOwnProperty('')   isPrototypeOf(object)   propertyIsEnumerable('propertyName')    toLocaleString()

toString()    valueOf()(返回对象的字符串、数值或布尔值表示,一般和toString()返回值相同)。

4.操做符:++a(先自加再运算);a++(先运算再自加);

5.语句:a.do-while:(至少执行一次,不管条件)

var i = 0;
do {
i += 2;
} while (i < 10);
alert(i);

 b.label语句:(可在未来由break或continue语句引用)

start: for (var i=0; i < count; i++) {
alert(i);
}

c.with语句:(将代码做用域设置到一个特定的对象中,通常不用)

6.函数:能够用arguments.length模拟重载;

 

四.变量、做用域和内存问题:

1.当复制保存着对象的某个变量时,操做的是对象的引用;为对象添加属性时,操做的是对象自己。

2.参数的传递是按值传递(不管基本类型仍是引用类型):即便在函数内部修改了参数的值,但原始的引用仍然保持未变

function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

能够把 ECMAScript 函数的参数想象成局部变量。

3.检测基本数据类型使用typeof  ,检测引用类型使用instanceof;

4.a.执行环境(上下文)定义了变量和函数有权访问的其余数据,每一个执行环境都有一个与之关联的变量对象,保存着环境中定义的全部变量和函数。(解析器使用);每一个函数都有本身的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行以后,栈将其环境弹出,把控制权返回给以前的执行环境;标识符解析是沿着做用域链一级一级地搜索标识符的过程。

b.catch块和with语句能够延长做用域链;

c.垃圾收集:标记清除与引用计数;管理内存:解除引用,适用于大多数全局变量和全局对象的属性(设置为null)

5.基本类型的值在内存中占据固定的大小空间,所以保存在栈内存中;引用类型的值是对象,保存在堆内存中;

 

5、引用类型:

 1.Object:点与花括号

alert(person["name"]); //"Nicholas"
alert(person.name); //"Nicholas"

var propertyName = "name";
alert(person[propertyName]); //"Nicholas"

person["first name"] = "Nicholas";

2.Array:

arr.join(''):返回包含全部数组项的字符串;

push() 方法能够接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
pop() 方法则从数组末尾移除最后一项,减小数组的 length 值,而后返回移除的项.

shift() ,它可以移除数组中的第一个项并返回该项,同时将数组长度减 1。

unshift() 它能在数组前端添加任意个项并返回新数组的长度。

reverse() 和 sort() 方法的返回值是通过排序以后的数组。

arr.sort(function(a,b){return a-b})

concat():这个方法会先建立当前数组一个副本,而后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。

var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]);
alert(colors); //red,green,blue
alert(colors2); //red,green,blue,yellow,black,brown

slice:不影响原始数组

var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1);
var colors3 = colors.slice(1,4);
alert(colors2); //green,blue,yellow,purple
alert(colors3); //green,blue,yellow

splice:始终都会返回一个数组,该数组中包含从原始数组中删除的项(若是没有删除任何项,则返回一个空数组)。

var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1); // 删除第一项
alert(colors); // green,blue
alert(removed); // red,返回的数组中只包含一项
removed = colors.splice(1, 0, "yellow", "orange"); // 从位置 1 开始插入两项
alert(colors); // green,yellow,orange,blue
alert(removed); // 返回的是一个空数组
removed = colors.splice(1, 1, "red", "purple"); // 插入两项,删除一项
alert(colors); // green,red,purple,orange,blue
alert(removed); // yellow,返回的数组中只包含一项

indexOf()和lastIndexOf():

var numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4)); //3
alert(numbers.lastIndexOf(4)); //5
alert(numbers.indexOf(4, 4)); //5
alert(numbers.lastIndexOf(4, 4)); //3
var person = { name: "Nicholas" };
var people = [{ name: "Nicholas" }];
var morePeople = [person];
alert(people.indexOf(person)); //-1
alert(morePeople.indexOf(person)); //0

迭代方法:每一个方法都接收两个参数:要在每一项上运行的函数和(可选的)运行该函数的做用域对象——影响 this 的值。传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象自己:(IE9+)

 every() :对数组中的每一项运行给定函数,若是该函数对每一项都返回 true ,则返回 true 。
 filter() :对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
 forEach() :对数组中的每一项运行给定函数。这个方法没有返回值。
 map() :对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
 some() :对数组中的每一项运行给定函数,若是该函数对任一项返回 true ,则返回 true 。
以上方法都不会修改数组中的包含的值。

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 numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(item, index, array){
return (item > 2);
});
alert(filterResult); //[3,4,5,4,3]


var numbers = [1,2,3,4,5,4,3,2,1];
var mapResult = numbers.map(function(item, index, array){
return item * 2;
});
alert(mapResult); //[2,4,6,8,10,8,6,4,2]


var numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array){
//执行某些操做
});

归并方法:reduce() 方法从数组的第一项开始,逐个遍历到最后。而 reduceRight() 则从数组的最后一项开始,向前遍历到第一项。

var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15

3.Date类型:

//取得开始时间
var start = Date.now();
//调用函数
doSomething();
//取得中止时间
var stop = Date.now(),
result = stop – start;

4.RegeExp类型:

 var reg= / pattern / flags ;

flags:i   g   m(多行模式,到文本末尾后还会继续查找下一行)

/*
* 匹配第一个"bat"或"cat",不区分大小写
*/
var pattern1 = /[bc]at/i;
/*
* 与 pattern1 相同,只不过是使用构造函数建立的
*/
var pattern2 = new RegExp("[bc]at", "i");

实例属性:

var pattern1 = /\[bc\]at/i;
alert(pattern1.global); //false
alert(pattern1.ignoreCase); //true
alert(pattern1.multiline); //false
alert(pattern1.lastIndex); //0
alert(pattern1.source); //"\[bc\]at"

实例方法1:exec():返回包含第一个匹配项信息的数组,没有的话返回null。额外属性input和index

var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;
var matches = pattern.exec(text);
alert(matches.index); // 0
alert(matches.input); // "mom and dad and baby"
alert(matches[0]); // "mom and dad and baby"
alert(matches[1]); // " and dad and baby"
alert(matches[2]); // " and baby"

如有g,则每次返回一个匹配项;若无g,则始终返回第一个匹配项;

var pattern2 = /.at/g;
var matches = pattern2.exec(text);
alert(matches.index); //0
alert(matches[0]); //cat
alert(pattern2.lastIndex); //3

matches = pattern2.exec(text);
alert(matches.index); //5
alert(matches[0]); //bat
alert(pattern2.lastIndex); //8

实例方法二:test():返回布尔值;

var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if (pattern.test(text)){
alert("The pattern was matched.");
}

构造函数属性:。。。。。。还有多达 9 个用于存储捕获组的构造函数属性。访问这些属性的语法是 RegExp.$1 、 RegExp.$2 … RegExp.$9 ,分别用于存储第1、第二……第九个匹配的捕获组。在调用 exec() 或 test() 方法时,这些属性会被自动填充。

var text = "this has been a short summer";
var pattern = /(..)or(.)/g;
if (pattern.test(text)){
alert(RegExp.$1); //sh
alert(RegExp.$2); //t
}

5.Function类型:

函数是对象,函数名是指针。函数没有重载。函数声明会提高

function sum(num1, num2){
return num1 + num2;
}
alert(sum(10,10)); //20
var anotherSum = sum;
alert(anotherSum(10,10)); //20
sum = null;
alert(anotherSum(10,10)); //20

以上代码即便将 sum 设置为 null ,让它与函数“断绝关系”,但仍然能够正常调用anotherSum()。

做为值的函数:如下例子能够用传入的属性选择排序方式;

function createComparisonFunction(propName) {
    return function(obj1, obj2){
        var value1 = obj1[propName];
        var value2 = obj2[propName];
            if (value1 < value2){
                  return -1;
            } else if (value1 > value2){
                 return 1;
            } else {
                return 0;
           }
      };
}            

var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
data.sort(createComparisonFunction("name"));
alert(data[0].name); //Nicholas
data.sort(createComparisonFunction("age"));
alert(data[0].name); //Zachary

函数内部属性:arguments的callee属性,该属性指向拥有这个arguments对象的函数;能够利用它消除紧密耦合,以下阶乘例子:

function factorial(num){
  if (num <=1) {
    return 1;
  } else {
    return num * arguments.callee(num-1)
  }
}

caller:这个属性中保存着调用当前函数的函数的引用,若是是在全局做用域中调用当前函数,它的值为 null .

function outer(){
    inner();
}
function inner(){
    alert(arguments.callee.caller);//或者alert(inner.caller)
}
outer();

函数的属性和方法:

属性:length:表示但愿函数接收的参数的个数(形参);  prototype:保存各类实例方法的真正所在;

方法(非继承的):apply和call()和bind()

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

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);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue

基本包装类型:(Boolean Number String)

var s1 = "some text";
var s2 = s1.substring(2);
//以上代码的内部实现以下:
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;

Number: toFixed(0-20):显示0-20位小数,自动舍入;       toExponential():返回指数表示法(e)      toPrecision() :接收一个参数,即表示数值的全部数字的位数。会根据要处理的数值决定究竟是调用 toFixed() 仍是调用 toExponential() 。

 

String类型:length属性

方法:

var stringValue = "hello world";
alert(stringValue.charAt(1)); //"e"
alert(stringValue.charCodeAt(1)); // 输出"101"
alert(stringValue[1]); //"e"


var stringValue = "hello ";
var result = stringValue.concat("world", "!");
alert(result); //"hello world!"
alert(stringValue); //"hello
//不修改原值

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"
//不修改原值

var stringValue = "hello world";
alert(stringValue.slice(-3)); //"rld"
alert(stringValue.substring(-3)); //"hello world"
alert(stringValue.substr(-3)); //"rld"
alert(stringValue.slice(3, -4)); //"lo w"
alert(stringValue.substring(3, -4)); //"hel"
alert(stringValue.substr(3, -4)); //"" (空字符串)
//substring不适用于负数参数


var stringValue = "hello world";
alert(stringValue.indexOf("o", 6)); //7
alert(stringValue.lastIndexOf("o", 6)); //4


var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
var positions = new Array();
var pos = stringValue.indexOf("e");
while(pos > -1){
positions.push(pos);
pos = stringValue.indexOf("e", pos + 1);
}
alert(positions); //"3,24,32,35,52"



var stringValue = " hello world ";
var trimmedStringValue = stringValue.trim();
alert(stringValue); //" hello world "
alert(trimmedStringValue); //"hello world"


var stringValue = "hello world";
alert(stringValue.toLocaleUpperCase()); //"HELLO WORLD"
alert(stringValue.toUpperCase()); //"HELLO WORLD"
alert(stringValue.toLocaleLowerCase()); //"hello world"
alert(stringValue.toLowerCase()); //"hello world"



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


var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
alert(pos); //1 
//返回at在字符串中第一次出现的位置。



var text = "cat, bat, sat, fat";
var result = text.replace("at", "ond");
alert(result); //"cond, bat, sat, fat"
result = text.replace(/at/g, "ond");
alert(result); //"cond, bond, sond, fond"

var text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g, "word ($1)");
alert(result); //word (cat), word (bat), word (sat), word (fat)


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(/[^\,]+/); //["", ",", ",", ",", ""]


alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"

单体内置对象:

Global:

encodeURIComponent():编码;     decodeURIComponent():解码; eval();

window

Math:

var values = [1, 2, 3, 4, 5, 6, 7, 8];
var max = Math.max.apply(Math, values);
alert(Math.ceil(25.9)); //26
alert(Math.ceil(25.5)); //26
alert(Math.ceil(25.1)); //26
alert(Math.round(25.9)); //26
alert(Math.round(25.5)); //26
alert(Math.round(25.1)); //25
alert(Math.floor(25.9)); //25
alert(Math.floor(25.5)); //25
alert(Math.floor(25.1)); //25
function selectFrom(min, max) {
  var choices = max - min + 1;
  return Math.floor(Math.random() * choices + min);
}
var num = selectFrom(2, 10);
alert(num); // 介于 2 和 10 之间(包括 2 和 10)的一个数值

 

六.面向对象的程序设计:

 1.属性类型(属性的特性):

a.数据属性:

[[Configurable]]   [[Enumerable]]   [[Writable]]   [[Value]](默认undefined)。

Object.defineProperty(person,'name',{configurable:false,value:'jiuye'})  (IE9+)

若将configurable设置为false,则除了writable以外的特性都没法再修改,包括configurable;

在调用 Object.defineProperty() 方法时,若是不指定, configurable 、 enumerable 和writable 特性的默认值都是 false 。

b.访问器属性:

[[Configurable]]   [[Enumerable]]   [[Get]]   [[Set]]

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); //2

defineProperties:

var book = {};
Object.defineProperties(book, {
  _year: {
  value: 2004
  },
  edition: {
  value: 1
  },
  year: {
    get: function(){
       return this._year;
    },
    set: function(newValue){
        if (newValue > 2004) {
           this._year = newValue;
           this.edition += newValue - 2004;
          }
       }
    }
});

 Object.getOwnPropertyDescriptor():

var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value); //2004
alert(descriptor.configurable); //false
alert(typeof descriptor.get); //"undefined"
var descriptor = Object.getOwnPropertyDescriptor(book, "year");
alert(descriptor.value); //undefined
alert(descriptor.enumerable); //false
alert(typeof descriptor.get); //"function"

2.建立对象:

a.工厂模式:

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("Nicholas", 29,);
var person2 = createPerson("Greg", 27, "Doctor");

b.构造函数模式:

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

new后经历的步骤:

(1) 建立一个新对象;
(2) 将构造函数的做用域赋给新对象(所以 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。

c.原型模式:

实例内部存在(__proto__)指向构造函数的原型对象;

alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true

alert(Object.getPrototypeOf(person1) == Person.prototype); //true
alert(Object.getPrototypeOf(person1).name); //"Nicholas"

 in 操做符只要经过对象可以访问到属性就返回 true , hasOwnProperty() 只在属性存在于实例中时才返回 true。 ,所以只要 in 操做符返回 true 而 hasOwnProperty() 返回 false ,就能够肯定属性是原型中的属性。

function hasPrototypeProperty(object, name){
  return !object.hasOwnProperty(name) && (name in object);
}

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person = new Person();
alert(hasPrototypeProperty(person, "name")); //true
person.name = "Greg";
alert(hasPrototypeProperty(person, "name")); //false

 Object.keys():返回一个包含全部可枚举属性的字符串数组。

 Object.getOwnPropertyNames():返回全部实例属性,不管它是否可枚举。

若用对象字面量建立新对象,记得从新设置constructor,以及设置constructor的Enumerable为false。

原型具备动态性:因为在原型中查找值的过程是一次搜索,所以咱们对原型对象所作的任何修改都可以当即从实例上
反映出来——即便是先建立了实例后修改原型也照样如此。但要注意,若是重写原型,则会断开现有原型与以前存在的对象实例的关系。(他们仍然引用的是最初的原型)

d.组合使用构造函数和原型模式:

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.friends = ["Shelby", "Court"];
}
Person.prototype = {
  constructor : Person,
  sayName : function(){
    alert(this.name);
  }
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

e.动态原型模式:

function Person(name, age, job){
//属性
  this.name = name;
  this.age = age;
  this.job = job;
// 方法
  f (typeof this.sayName != "function"){
    Person.prototype.sayName = function(){
      alert(this.name);
    };
  }
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();

f.寄生构造函数模式:表面上很像普通构造函数。

g.稳妥构造函数模式:适合须要安全执行环境的代码中。

function Person(name, age, job){
//建立要返回的对象
var o = new Object();
//能够在这里定义私有变量和函数
//添加方法
o.sayName = function(){
alert(name);
};
//返回对象
return o;
}

3.继承:

a.原型链:SubType.prototype = new SuperType();搜索步骤:1)搜索实例;2)搜索 SubType.prototype ;3)搜索 SuperType.prototype。

4).搜索Object.Prototype

如何肯定原型和实例的关系:

alert(instance instanceof Object); //true
alert(instance instanceof SuperType); //true
alert(instance instanceof SubType); //true

alert(Object.prototype.isPrototypeOf(instance)); //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance)); //true

在经过原型链实现继承时,不能使用对象字面量建立原型方法。由于这样作就会重写原型链。

原型链的问题:1.原先的实例属性会变成了如今的原型属性;      2.没法向父类传递参数。

b.借用构造函数:(不多单独使用)

function SuperType(name){
this.name = name;
}
function SubType(){
//继承了 SuperType,同时还传递了参数
SuperType.call(this, "Nicholas");
//实例属性
this.age = 29;
}
var instance = new SubType();
alert(instance.name); //"Nicholas";
alert(instance.age); //29

c.组合继承:(经常使用)(将原型链和借用构造函数组合)

function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
  alert(this.name);
};
function SubType(name, age){
  //继承属性
  SuperType.call(this, name);
  this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
  alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

d.原型式继承:

 Object.create()

var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person, {
name: {
value: "Greg"
}
});
alert(anotherPerson.name); //"Greg"

只想让一个对象与另外一个对象保持相似的状况下,原型式继承是彻底能够胜任的。不过别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模式同样。

e.寄生式继承:。建立一个仅用于封装继承过程的函数,该函数在内部以某种方式来加强对象,最后再像真地是它作了全部工做同样返回对象。

不能函数复用。

function createAnother(original){
  var clone = object(original); //经过调用函数建立一个新对象
  clone.sayHi = function(){ //以某种方式来加强这个对象
  alert("hi");
};
return clone; //返回这个对象
}
var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

 

f.寄生组合式继承:(引用类型最理想的继承范式)

function inheritPrototype(subType, superType){
  var prototype = object(superType.prototype); //建立对象
  prototype.constructor = subType; //加强对象
  subType.prototype = prototype; //指定对象
}
function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
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、函数表达式:

 函数表达式建立的函数是匿名函数,在把函数当成值来使用的状况下,均可以使用匿名函数。

a.递归:

//函数表达式递归
var factorial = (function f(num){
  if (num <= 1){
    return 1;
  } else {
    return num * f(num-1);
  }
});

//普通声明递归
function factorial(num){
  if (num <= 1){
    return 1;
  } else {
    return num * arguments.callee(num-1);
  }
}

b.闭包:

当某个函数被调用时,会建立一个执行环境及相应的做用域链。而后,使用 arguments 和其余命名参数的值来初始化函数的活动对象。

在另外一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的做用域链中。一般,函数的做用域及其全部变量都会在函数执行结束后被销毁。可是,当函数返回了一个闭包时,这个函数的做用域将会一直在内存中保存到闭包不存在为止。使用闭包能够在 JavaScript中模仿块级做用域。

function createFunctions(){
  var result = new Array();
  for (var i=0; i < 10; i++){
    result[i] = function(num){
      return function(){
        return num;
      };
    }(i);
  }
return result;
}

垃圾回收:

//HTML元素没法销毁
function assignHandler(){
  var element = document.getElementById("someElement");
  element.onclick = function(){
  alert(element.id);
  };
}

//修改后:
function assignHandler(){
var element = document.getElementById("someElement");
var id = element.id;
element.onclick = function(){
alert(id);
};
element = null;
}

c.模拟块级做用域:

(function(){
  var now = new Date();
  if (now.getMonth() == 0 && now.getDate() == 1){
    alert("Happy new year!");
  }
})();


function outputNumbers(count){
  (function () {
    for (var i=0; i < count; i++){
      alert(i);
    }
  })();
  alert(i); //致使一个错误!
}

d.私有变量:任何在函数中定义的变量,均可以认为是私有变量,由于不能在函数的外部访问这些变量。
私有变量包括函数的参数、局部变量和在函数内部定义的其余函数。

把有权访问私有变量和私有函数的公有方法称为特权方法。

function MyObject(){
//私有变量和私有函数
  var privateVariable = 10;
  function privateFunction(){
    return false;
}
//特权方法
this.publicMethod = function (){
  privateVariable++;
  return privateFunction();
  };
}
function Person(name){
  this.getName = function(){
  return name;
};
this.setName = function (value) {
  name = value;
};
}
var person = new Person("Nicholas");
alert(person.getName()); //"Nicholas"
person.setName("Greg");
alert(person.getName()); //"Greg"

以上代码的构造函数中定义了两个特权方法: getName() 和 setName() 。这两个方法均可以在构造函数外部使用,并且都有权访问私有变量 name 。但在 Person 构造函数外部,没有任何办法访问 name 。因为这两个方法是在构造函数内部定义的,它们做为闭包可以经过做用域链访问 name 。私有变量 name在 Person 的每个实例中都不相同,由于每次调用构造函数都会从新建立这两个方法。缺点是针对每一个实例都会建立一样一组新方法,而使用静态私有变量来实现特权方法就能够避免这个问题。

静态私有变量:

这个模式与在构造函数中定义特权方法的主要区别,就在于私有变量和函数是由实例共享的。因为特权方法是在原型上定义的,所以全部实例都使用同一个函数。而这个特权方法,做为一个闭包,老是保存着对包含做用域的引用。

(function(){
  var name = "";
  Person = function(value){
  name = value;
  };
  Person.prototype.getName = function(){
  return name;
  };
  Person.prototype.setName = function (value){
  name = value;
 };
})();
var person1 = new Person("Nicholas");
alert(person1.getName()); //"Nicholas"
person1.setName("Greg");
alert(person1.getName()); //"Greg"
var person2 = new Person("Michael");
alert(person1.getName()); //"Michael"
alert(person2.getName()); //"Michael"

模块模式:

var singleton = function(){
//私有变量和私有函数
  var privateVariable = 10;
  function privateFunction(){
    return false;
}
//特权/公有方法和属性
return {
  publicProperty: true,
  publicMethod : function(){
    privateVariable++;
    return privateFunction();
    }
  };
}();

从本质上来说,这个对象字面量定义的是单例的公共接口。这种模式在须要对单例进行某些初始化,同时又须要维护其私有
变量时是很是有用的。

加强的模块模式:

var singleton = function(){
//私有变量和私有函数
  var privateVariable = 10;
  function privateFunction(){
    return false;
}
//建立对象
var object = new CustomType();
//添加特权/公有属性和方法
object.publicProperty = true;
object.publicMethod = function(){
privateVariable++;
return privateFunction();
};
//返回这个对象
return object;
}();

这种加强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性和(或)方法对其加以加强的状况。

 

8、BOM

1.window对象:既是经过 JavaScript 访问浏览器窗口的一个接口,又是 ECMAScript 规定的 Global 对象。与全局对象的区别在于window对象的属性能够delete。

a.窗口位置:(没法取得精确坐标值)

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

窗口移动:(可能被浏览器禁用)

b.窗口大小:

IE9+、Firefox、Safari、Opera 和 Chrome 均为此提供了 4个属性: innerWidth 、 innerHeight 、 outerWidth 和 outerHeight 。在 IE9+、Safari和 Firefox中, outerWidth 和 outerHeight 返回浏览器窗口自己的尺寸(不管是从最外层的 window 对象仍是从某个框架访问)。在Opera中,这两个属性的值表示页面视图容器 的大小。而innerWidth 和 innerHeight则表示该容器中页面视图区的大小(减去边框宽度)。在 Chrome 中, outerWidth 、 outerHeight 与innerWidth 、 innerHeight 返回相同的值,即视口(viewport)大小而非浏览器窗口大小。

取得页面视口的大小:

var pageWidth = window.innerWidth,
  pageHeight = window.innerHeight;
if (typeof pageWidth != "number"){
  if (document.compatMode == "CSS1Compat"){
    pageWidth = document.documentElement.clientWidth;
    pageHeight = document.documentElement.clientHeight;
  } else {
    pageWidth = document.body.clientWidth;
    pageHeight = document.body.clientHeight;
 }
}

窗口移动:

//将窗口移动到屏幕左上角
window.moveTo(0,0);
//将窗向下移动 100 像素
window.moveBy(0,100);
//将窗口移动到(200,300)
window.moveTo(200,300);
//将窗口向左移动 50 像素
window.moveBy(-50,0)

窗口大小调整:(可能被浏览器禁用)

//调整到 100×100
window.resizeTo(100, 100);
//调整到 200×150
window.resizeBy(100, 50);
//调整到 300×300
window.resizeTo(300, 300);

c.导航和打开窗口:

window.open():

var a=window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");

a.close();

如下代码检测出调用 window.open() 打开的弹出窗口是否是被屏蔽了:

var blocked = false;
try {
  var wroxWin = window.open("http://www.wrox.com", "_blank");
  if (wroxWin == null){
    blocked = true;
  }
} catch (ex){
  blocked = true;
}
if (blocked){
  alert("The popup was blocked!");
}

d.间歇调用和超时调用:

setTimeout:全局做用域中执行

//设置超时调用
var timeoutId = setTimeout(function() {
  alert("Hello world!");
}, 1000);
//注意:把它取消
clearTimeout(timeoutId);

setInterval:

var num = 0;
var max = 10;
var intervalId = null;
function incrementNumber() {
  num++;
//若是执行次数达到了 max 设定的值,则取消后续还没有执行的调用
if (num == max) {
  clearInterval(intervalId);
  alert("Done");
 }
}
intervalId = setInterval(incrementNumber, 500);

更好的方式是用setTimeOut模拟:

var num = 0;
var max = 10;
function incrementNumber() {
  num++;
// 若是执行次数未达到 max  设定的值,则设置另外一次超时调用
if (num < max) {
  setTimeout(incrementNumber, 500);
} else {
  alert("Done");
}
}
setTimeout(incrementNumber, 500);

e.系统对话框:

alert()  confirm() prompt()  find() print();

2.location对象:

 window.location 和 document.location 引用的是同一个对象。

属性:hash  host("www.wrox.com:80")  hostname("www.wrox.com") href("http:/www.wrox.com") pathname("/WileyCDA/")

port('8080') protocol('http') search("?q=javascript").

a.查询字符串参数

function getQueryStringArgs(){
//取得查询字符串并去掉开头的问号
  var qs = (location.search.length > 0 ? 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;
}

//假设查询字符串是?q=javascript&num=10
var args = getQueryStringArgs();
alert(args["q"]); //"javascript"
alert(args["num"]); //"10"

b.位置操做:

location.href = "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.replace("http://www.wrox.com/"):没法后退;

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

3.navigator对象:

a.检测插件:

//检测全部浏览器中的 Flash
function hasFlash(){
var result = hasPlugin("Flash");
if (!result){
result = hasIEPlugin("ShockwaveFlash.ShockwaveFlash");
}
return result;
}
//检测全部浏览器中的 QuickTime
function hasQuickTime(){
var result = hasPlugin("QuickTime");
if (!result){
result = hasIEPlugin("QuickTime.QuickTime");
}
return result;
}
//检测 Flash
alert(hasFlash());
//检测 QuickTime
alert(hasQuickTime());

b.注册处理程序:

 registerContentHandler() 和 registerProtocolHandler() 方法。这两个方法可让一个站点指明它能够处理特定类型的信息。(MIME)

4.screen对象:

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

5.history对象:

//后退一页
history.go(-1);
//前进一页
history.go(1);
//前进两页
history.go(2);
//跳转到最近的 wrox.com 页面
history.go("wrox.com");
//跳转到最近的 nczonline.net 页面
history.go("nczonline.net");
//后退一页
history.back();
//前进一页
history.forward();

if (history.length == 0){
//这应该是用户打开窗口后的第一个页面
}

 

9、客户端监测:

先设计最通用的方案,而后再使用特定于浏览器的技术加强该方案。

1.能力监测:(!!通常用来将后面的表达式强制转换为布尔类型的数据(boolean))

function isHostMethod(object, property) {
  var t = typeof object[property];
  return t=='function' ||
    (!!(t=='object' && object[property])) ||
      t=='unknown';
}
能够像下面这样使用这个函数:
result = isHostMethod(xhr, "open"); //true
result = isHostMethod(xhr, "foo"); //false
//肯定浏览器是否支持 Netscape 风格的插件
var hasNSPlugins = !!(navigator.plugins && navigator.plugins.length);
//肯定浏览器是否具备 DOM1 级规定的能力
var hasDOM1 = !!(document.getElementById && document.createElement &&
document.getElementsByTagName);

应该将能力检测做为肯定下一步解决方案的依据,而不是用它来判断用户使用的是什么浏览器。

2.怪癖监测:

怪癖检测是想要知道浏览器存在什么缺陷。

例如,IE8 及更早版本中存在一个 bug,即若是某个实例属性与 [[Enumerable]] 标记为 false 的某个原型属性同名,那么该实例属性将不会出如今
fon-in 循环当中。可使用以下代码来检测这种“怪癖”。

var hasDontEnumQuirk = function(){
  var o = { toString : function(){} };
  for (var prop in o){
    if (prop == "toString"){
      return false;
   }
 }
return true;
}();

3.用户代理监测:

经过 JavaScript 的 navigator.userAgent 属性访问检测用户代理字符串来肯定实际使用的浏览器。

 

IE模仿mozilla   webkit(safari)模仿mozilla  webkit(chrome)模仿mozilla opera有本身独自的版本号开头。

ios和Android的默认浏览器机遇webkit

应该主要检测五大呈现引擎:IE、Gecko、WebKit、KHTML 和 Opera。

检测顺序:opera. webkit. KHTML. Gecko.  IE.

在某些条件下,平台多是必须关注的问题。那些具备各类平台版本的浏览器在不一样的平台下可能会有不一样的问题。目前的三大主流平台是 Windows、Mac 和 Unix(包括各类 Linux)。

识别windows

识别移动设备

识别游戏设备

完整代码(略):

使用场景:优先使用能力监测和怪癖监测。用户代理监测通常适用于下列情形:

a.不能直接准确地使用能力检测或怪癖检测。例如,某些浏览器实现了为未来功能预留的存根
(stub)函数。在这种状况下,仅测试相应的函数是否存在还得不到足够的信息。
b.同一款浏览器在不一样平台下具有不一样的能力。这时候,可能就有必要肯定浏览器位于哪一个平
台下。

c.为了跟踪分析等目的须要知道确切的浏览器。

 

10、DOM(针对 HTML 和 XML 文档的一个 API)

1.节点层次:

a.node类型:

JavaScript 中的全部节点类型都继承自 Node 类型,所以全部节点类型都共享着相同的基本属性和方法。每一个节点都有一个 nodeType 属性,用于代表节点的类型。对于元素节点, nodeName 中保存的始终都是元素的标签名,而 nodeValue 的值则始终为 null 。

节点关系:

每一个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象。 NodeList 是一种类数组对象。

 第一个节点的 previousSibling 属性值为 null ,而列表中最后一个节点的 nextSibling 属性的值一样也为 null。

if (someNode.nextSibling === null){
alert("Last node in the parent’s childNodes list.");
} else if (someNode.previousSibling === null){
alert("First node in the parent’s childNodes list.");
}

父节点的 firstChild 和 lastChild属性分别指向其 childNodes 列表中的第一个和最后一个节点。 hasChildNodes() 在节点包含一或多个子节点的状况下返回 true 。这是比查询 childNodes列表的 length 属性更简单的方法。

操做节点:

appendChild():

任何 DOM 节点也不能同时出如今文档中的多个位置上。所以,若是在调用 appendChild() 时传入了父节点的第一个子节点,那么该节点就会成为父节点的最后一个子节点。

var returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode); //true
alert(someNode.lastChild == newNode); //true

insertBefore():接受两个参数:要插入的节点和做为参照的节点。

//插入后成为最后一个子节点
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); //true
//插入后成为第一个子节点
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); //true
alert(newNode == someNode.firstChild); //true
//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true

 replaceChild():接受的两个参数是:要插入的节点和要替换的节点。

//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);

 removeChild():接受一个参数,即要移除的节点。

//移除第一个子节点
var formerFirstChild = someNode.removeChild(someNode.firstChild);
//移除最后一个子节点
var formerLastChild = someNode.removeChild(someNode.lastChild);

 cloneNode():接受一个布尔值参数,表示是否执行深复制。(深复制(true):复制节点和整个子节点数;浅复制:只复制节点自己)

IE会复制事件处理程序(应该先移除事件处理程序)。

 

b.Document类型:

 document 对象是 HTMLDocument的一个实例,表示整个 HTML 页面。并且, document 对象是 window 对象的一个属性,所以能够将其做为全局对象来访问。 Document 节点具备下列特征:

 nodeType 的值为 9;
 nodeName 的值为 "#document" ;
 nodeValue 的值为 null ;
 parentNode 的值为 null ;
 ownerDocument 的值为  null ;

var html = document.documentElement; //取得对<html>的引用
alert(html === document.childNodes[0]); //true
alert(html === document.firstChild); //true

var body = document.body; //取得对<body>的引用

var doctype = document.doctype; //取得对<!DOCTYPE>的引用

//取得文档标题
var originalTitle = document.title;
//设置文档标题
document.title = "New page title";

//取得完整的 URL
var url = document.URL;
//取得域名
var domain = document.domain;
//取得来源页面的 URL
var referrer = document.referrer;

URL 与 domain 属性是相互关联的。例如,若是 document.URL 等于 http://www.wrox.com/WileyCDA/,那么 document.domain 就等于 www.wrox.com。

//假设页面来自于 p2p.wrox.com 域
document.domain = "wrox.com"; //松散的(成功)
document.domain = "p2p.wrox.com"; //紧绷的(出错!)

var allElements = document.getElementsByTagName("*");能够取得文档全部元素。

 getElementsByName():能够用于单选按钮的name值;

 document.anchors ,包含文档中全部带 name 特性的 <a> 元素;

document.links ,包含文档中全部带 href 特性的 <a> 元素;

 document.forms ,包含文档中全部的 <form> 元素,与 document.getElementsByTagName("form")获得的结果相同;

document.images ,包含文档中全部的 <img> 元素,与 document.getElementsByTagName("img") 获得的结果相同;

var hasXmlDom = document.implementation.hasFeature("XML", "1.0"):检测dom功能;

若是在文档加载结束后再调用 document.write() ,那么输出的内容将会重写整个页面; writeln()在最后加换行符\n

window.onload = function(){
document.write("Hello world!");
};

c.Element类型:用于表现 XML或 HTML元素,提供了对元素标签名、子节点及特性的访问。 Element 节点具备如下特征:

nodeType 的值为 1;
nodeName 的值为元素的标签名;
nodeValue 的值为 null ;
 parentNode 多是 Document 或 Element ;

  其子节点多是 Element 、 Text 、 Comment 、 ProcessingInstruction 、 CDATASection 或EntityReference 。

if (element.tagName == "div"){ //不能这样比较,很容易出错!
//在此执行某些操做
}
if (element.tagName.toLowerCase() == "div"){ //这样最好(适用于任何文档)
//在此执行某些操做
}

取得特性:

每一个元素都有一或多个特性,这些特性的用途是给出相应元素或其内容的附加信息。操做特性的DOM 方法主要有三个,分别是 getAttribute() 、 setAttribute() 和 removeAttribute() 。

在经过 JavaScript 以编程方式操做 DOM 时,开发人员常常不使用 getAttri-bute() ,而是只使用对象的属性。只有在取得自定义特性值的状况下,才会使用 getAttribute() 方法。

div.setAttribute("id", "someOtherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "Some other text");

div.removeAttribute("class");

  attributes 属性:通常用于遍历。

var div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);

IE不将空白符计入节点数,其余浏览器会计入节点数。

Text类型:包含的是能够照字面解释的纯文本内容。纯文本中能够包含转义后的HTML 字符,但不能包含 HTML 代码。 Text 节点具备如下特征:

nodeType 的值为 3;
nodeName 的值为 "#text" ;
nodeValue 的值为节点所包含的文本;
parentNode 是一个 Element ;
不支持(没有)子节点。

操做方法:

appendData(text) :将 text 添加到节点的末尾。
deleteData(offset, count) :从 offset 指定的位置开始删除 count 个字符。
insertData(offset, text) :在 offset 指定的位置插入 text 。
replaceData(offset, count, text) :用 text 替换从 offset 指定的位置开始到 offset+count 为止处的文本。
splitText(offset) :从 offset 指定的位置将当前文本节点分红两个文本节点。
substringData(offset, count) :提取从 offset 指定的位置开始到 offset+count 为止处的字符串。
除了这些方法以外,文本节点还有一个 length 属性,保存着节点中字符的数目。并且,nodeValue.length 和 data.length 中也保存着一样的值。

建立文本节点:

var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);

 normalize():能够将全部文本节点合并成一个节点。

 splitText():分割文本节点;

 

Comment类型:(注释):

nodeType 的值为 8;
nodeName 的值为 "#comment" ;
nodeValue 的值是注释的内容;
parentNode 多是 Document 或 Element ;
不支持(没有)子节点。

 

Attr类型(特性):

nodeType 的值为 2;
nodeName 的值是特性的名称;
nodeValue 的值是特性的值;
parentNode 的值为 null ;
在 HTML 中不支持(没有)子节点;
在 XML 中子节点能够是 Text 或 EntityReference 。

 

2.DOM操做技术:

动态脚本:

function loadScript(url){
 var script = document.createElement("script");
 script.type = "text/javascript";
 script.src = url;
 document.body.appendChild(script);
}
loadScript("client.js");

动态样式:

function loadStyles(url){
  var link = document.createElement("link");
  link.rel = "stylesheet";
  link.type = "text/css";
  link.href = url;
  var head = document.getElementsByTagName("head")[0];
  head.appendChild(link);
}
loadStyles("styles.css");

操做表格:

<table border="1" width="100%">
  <tbody>
    <tr>
      <td>Cell 1,1</td>
      <td>Cell 2,1</td>
    </tr>
    <tr>
      <td>Cell 1,2</td>
      <td>Cell 2,2</td>
    </tr>
  </tbody>
</table>

核心DOM方法:
//建立 table
var table = document.createElement("table");
table.border = 1;
table.width = "100%";
//建立 tbody
var tbody = document.createElement("tbody");

table.appendChild(tbody);
//建立第一行
var row1 = document.createElement("tr");
tbody.appendChild(row1);
var cell1_1 = document.createElement("td");
cell1_1.appendChild(document.createTextNode("Cell 1,1"));
row1.appendChild(cell1_1);
var cell2_1 = document.createElement("td");
cell2_1.appendChild(document.createTextNode("Cell 2,1"));
row1.appendChild(cell2_1);
//建立第二行
var row2 = document.createElement("tr");
tbody.appendChild(row2);
var cell1_2 = document.createElement("td");
cell1_2.appendChild(document.createTextNode("Cell 1,2"));
row2.appendChild(cell1_2);
var cell2_2= document.createElement("td");
cell2_2.appendChild(document.createTextNode("Cell 2,2"));
row2.appendChild(cell2_2);
//将表格添加到文档主体中
document.body.appendChild(table);

使用特殊方法:
//建立 table
var table = document.createElement("table");
table.border = 1;
table.width = "100%";
//建立 tbody
var tbody = document.createElement("tbody");
table.appendChild(tbody);
// 建立第一行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1"));
// 建立第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2"));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2"));
//将表格添加到文档主体中
document.body.appendChild(table);

 

使用 NodeList:

//死循环
var divs = document.getElementsByTagName("div"),
  i,
  div;
for (i=0; i < divs.length; i++){
  div = document.createElement("div");
  document.body.appendChild(div);
}

//用len保存divs.length后便可;
var divs = document.getElementsByTagName("div"),
  i,
  len,
  div;
for (i=0, len=divs.length; i < len; i++){
  div = document.createElement("div");
  document.body.appendChild(div);
}

 

11、DOM扩展:

 querySelector():

querySelectorAll():返回的值其实是带有全部属性和方法的 NodeList ,而其底层实现则相似于一组元素的快照,而非不断对文档进行搜索的动态查询。这样实现能够避免使用 NodeList 对象一般会引发的大多数性能问题。只要传给 querySelectorAll() 方法的 CSS 选择符有效,该方法都会返回一个 NodeList 对象,而无论找到多少匹配的元素。若是没有找到匹配的元素, NodeList 就是空的。

 matchesSelector():返回boolean;

 getElementsByClassName():

//取得全部类中包含"username"和"current"的元素,类名的前后顺序无所谓
var allCurrentUsernames = document.getElementsByClassName("username current");
//取得 ID 为"myDiv"的元素中带有类名"selected"的全部元素
var selected = document.getElementById("myDiv").getElementsByClassName("selected");

document.activeElement:这个属性始终会引用 DOM 中当前得到了焦点的元素。

 document.hasFocus():

var button = document.getElementById("myButton");
button.focus();
alert(document.activeElement === button); //true

var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus()); //true
if (document.readyState == "complete"){
//执行操做
}

以上为  readyState 属性(loading   complete)

document.charset

自定义数据属性:data-

 innerHTML:读(子节点)、写 ,应避免频繁操做。

for (var i=0, len=values.length; i < len; i++){
  ul.innerHTML += "<li>" + values[i] + "</li>"; //要避免这种频繁操做!!
}

//如下较为合理
var itemsHtml = "";
for (var i=0, len=values.length; i < len; i++){
  itemsHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = itemsHtml;

 

 outerHTML:读(包括调用它的元素及和全部子节点)、写

 insertAdjacentHTML()

//做为前一个同辈元素插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>");
//做为第一个子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>");
//做为最后一个子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>");
//做为后一个同辈元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>");

  children:(childNodes相似,处理文本节点的空白符有差别);

 contains():调用 contains() 方法的应该是祖先节点,
也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。若是被检测的节点是后代节点,该方法返回 true ;不然,返回 false 。

innerText()   outText()(不经常使用);

 

12、DOM2和DOM3:

 getComputedStyle()(非IE)     currentStyle(IE);

元素大小:

1.偏移量:包括元素在屏幕上占用的全部可见的空间。

offsetHeight :元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度。
offsetWidth :元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框宽度和右边框宽度。
offsetLeft :元素的左外边框至包含元素的左内边框之间的像素距离。
offsetTop :元素的上外边框至包含元素的上内边框之间的像素距离。

其中, offsetLeft 和 offsetTop 属性与包含元素有关,包含元素的引用保存在 offsetParent属性中。 offsetParent 属性不必定与 parentNode 的值相等。例如, <td> 元素的 offsetParent 是做为其祖先元素的 <table> 元素,由于 <table> 是在 DOM层次中距 <td> 最近的一个具备大小的元素。

2.客户区大小:指的是元素内容及其内边距所占据的空间大小。有关客户区大小的属性有两个: clientWidth 和 clientHeight 。其中, clientWidth 属性是元素内容区宽度加上左右内边距宽度; clientHeight 属性是元素内容区高度加上上下内边距高度。

最经常使用到这些属性的状况,就是像第 8 章讨论的肯定浏览器视口大小的时候。以下面的例子所示,要肯定浏览器视口大小,可使用 document.documentElement 或 document.body (在 IE7 以前的版本中)的clientWidth 和 clientHeight 。

3.滚动大小:

scrollHeight :在没有滚动条的状况下,元素内容的总高度。
scrollWidth :在没有滚动条的状况下,元素内容的总宽度。
scrollLeft :被隐藏在内容区域左侧的像素数。经过设置这个属性能够改变元素的滚动位置。
scrollTop :被隐藏在内容区域上方的像素数。经过设置这个属性能够改变元素的滚动位置。

4.肯定元素大小: getBoundingClientRect():这个方法返回会一个矩形对象,包含 4 个属性: left 、 top 、 right 和 bottom 。这些属性给出了元素在页面中相对于视口的位置。

遍历:

NodeIterator  TreeWalker

范围:

 createRange()......

 

十三:事件(文档或浏览器窗口中发生的一些特定的交互瞬间。)

1.事件流描述的是从页面中接收事件的顺序。

事件冒泡(IE):即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,而后逐级向上传播到较为不具体的节点(文档)。

事件捕获(Netscape):思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。(特殊时使用)

DOM事件流:“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。(IE9)

 

2.事件处理程序:响应某个事件的函数就叫作事件处理程序(或事件侦听器)。事件处理程序的名字以 "on" 开头.

 a.HTML事件处理程序:会形成HTML和JS的紧密耦合;

b.DOM0级事件处理程序:

var btn = document.getElementById("myBtn");
  btn.onclick = function(){
  alert(this.id); //"myBtn"
};
btn.onclick = null; //删除事件处理程序

c.DOM2级事件处理程序: addEventListener()和 removeEventListener() 。(true为捕获阶段调用,false为冒泡阶段调用)IE9+

var btn = document.getElementById("myBtn");
  var handler = function(){
  alert(this.id);
};
btn.addEventListener("click", handler, false);
// 这里省略了其余代码
btn.removeEventListener("click", handler, false); // 有效

以上代码表示若是第二个参数的匿名函数,则没法经过removeEventListener删除事件处理程序;

d.IE8-的事件处理程序: attachEvent() 和 detachEvent() 。this指向window

var btn = document.getElementById("myBtn");
  btn.attachEvent("onclick", function(){
  alert("Clicked");
});

e.跨浏览器的事件处理程序:

var EventUtil = {
  addHandler: function(element, type, handler){
    if (element.addEventListener){
      element.addEventListener(type, handler, false);
    } else if (element.attachEvent){
    element.attachEvent("on" + type, handler);
    } else {
      element["on" + type] = handler;
    }
},
removeHandler: function(element, type, handler){
    if (element.removeEventListener){
      element.removeEventListener(type, handler, false);
   } else if (element.detachEvent){
      element.detachEvent("on" + type, handler);
   } else {
      element["on" + type] = null;
    }
  }
};

var btn = document.getElementById("myBtn");
var handler = function(){
  alert("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
// 这里省略了其余代码
EventUtil.removeHandler(btn, "click", handler);

3.事件对象:

currentTarget  :其事件处理程序当前正在处理事件的那个元素;

document.body.onclick = function(event){
  alert(event.currentTarget === document.body); //true
  alert(this === document.body); //true
  alert(event.target === document.getElementById("myBtn")); //true
};

当单击这个例子中的按钮时, this 和 currentTarget 都等于 document.body ,由于事件处理程序是注册到这个元素上的。然而, target 元素却等于按钮元素,由于它是 click 事件真正的目标。因为按钮上并无注册事件处理程序,结果 click 事件就冒泡到了 document.body ,在那里事件才获得了处理。

在须要经过一个函数处理多个事件时,可使用 type 属性。

var btn = document.getElementById("myBtn");
var handler = function(event){
switch(event.type){
  case "click":
    alert("Clicked");
    break;
  case "mouseover":
    event.target.style.backgroundColor = "red";
    break;
  case "mouseout":
    event.target.style.backgroundColor = "";
    break;
  }
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;

 preventDefault():组织特定事件的默认行为;(只有 cancelable 属性设置为 true 的事件,才可使用.)

var link = document.getElementById("myLink");
link.onclick = function(event){
  event.preventDefault();
};

 stopPropagation():当即中止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
  alert("Clicked");
  event.stopPropagation();
};
document.body.onclick = function(event){
  alert("Body clicked");
};

 eventPhase:用来肯定事件当前正位于事件流的哪一个阶段。若是是在捕获阶段调用的事件处理程序,那么 eventPhase 等于 1 ;若是事件处理程序处于目标对象上,则 event-Phase 等于 2 ;若是是在冒泡阶段调用的事件处理程序, eventPhase 等于 3 。

IE的事件对象:

 returnValue 属性至关于 DOM中的 preventDefault() 方法; cancelBubble 属性与 DOM 中的 stopPropagation() 方法做用相同;

跨浏览器的事件对象:

var EventUtil = {
addHandler: function(element, type, handler){
//省略的代码
},
getEvent: function(event){
  return event ? event : window.event;
},
getTarget: function(event){
  return event.target || event.srcElement;
},
preventDefault: function(event){
  if (event.preventDefault){
    event.preventDefault();
  } else {
    event.returnValue = false;
  }
},
removeHandler: function(element, type, handler){
//省略的代码
},
stopPropagation: function(event){
  if (event.stopPropagation){
    event.stopPropagation();
  } else {
    event.cancelBubble = true;
  }
 }
};

4.事件类型:

a.UI事件:指的是那些不必定与用户操做有关的事件;

load:当页面彻底加载后在 window 上面触发;     unload :当页面彻底卸载后在 window 上面触发;

abort :在用户中止下载过程时,若是嵌入的内容没有加载完,则在 <object> 元素上面触发。

error :当发生 JavaScript 错误时在 window 上面触发,当没法加载图像时在 <img> 元素上面触发,当没法加载嵌入内容时在 <object> 元素上面触发;

select :当用户选择文本框( <input> 或 <texterea> )中的一或多个字符时触发。

resize :当窗口或框架的大小变化时在 window 或框架上面触发。浏览器窗口最小化或最大化时也会触发 resize 事件。

scroll :当用户滚动带滚动条的元素中的内容时,在该元素上面触发。 <body> 元素中包含所加载页面的滚动条。

b.焦点事件:

blur:在元素失去焦点时触发。这个事件不会冒泡;全部浏览器都支持它。

focus :在元素得到焦点时触发。这个事件不会冒泡;全部浏览器都支持它。

focusin :在元素得到焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。

focusout :在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。

c.鼠标与滚轮事件:

click :在用户单击主鼠标按钮(通常是左边的按钮)或者按下回车键时触发。

dblclick :在用户双击主鼠标按钮(通常是左边的按钮)时触发。

 mousedown :在用户按下了任意鼠标按钮时触发。不能经过键盘触发这个事件。

mouseenter :在鼠标光标从元素外部首次移动到元素范围以内时触发。这个事件不冒泡,并且在光标移动到后代元素上不会触发。

 mouseleave :在位于元素上方的鼠标光标移动到元素范围以外时触发。这个事件不冒泡,并且在光标移动到后代元素上不会触发。

 mousemove :当鼠标指针在元素内部移动时重复地触发。

 mouseout :在鼠标指针位于一个元素上方,而后用户将其移入另外一个元素时触发。又移入的另外一个元素可能位于前一个元素的外部,也多是这个元素的子元素。

mouseover :在鼠标指针位于一个元素外部,而后用户将其首次移入另外一个元素边界以内时触发。

mouseup :在用户释放鼠标按钮时触发。

 客户区坐标位置:

鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的 clientX 和clientY 属性中。全部浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。

页面坐标位置:

页面坐标经过事件对象的 pageX 和pageY 属性,能告诉你事件是在页面中的什么位置发生的。这两个属性表示鼠标光标在页面中的位置,所以坐标是从页面自己而非视口的左边和顶边计算的。

在页面没有滚动的状况下, pageX 和 pageY 的值与 clientX 和 clientY 的值相等。

屏幕坐标位置:

鼠标事件发生时,不只会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而经过 screenX 和 screenY 属性就能够肯定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。

修改键:

虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也能够影响到所要采起的操做。这些修改键就是 Shift、Ctrl、Alt 和 Meta(在 Windows键盘中是 Windows键,在苹果机中是 Cmd 键),它们常常被用来修改鼠标事件的行为。DOM 为此规定了 4 个属性,表示这些修改键的状态: shiftKey 、 ctrlKey 、 altKey 和 metaKey 。这些属性中包含的都是布尔值,若是相应的键被按下了,则值为 true ,不然值为 false 。当某个鼠标事件发生时,经过检测这几个属性就能够肯定用户是否同时按下了其中的键。

相关元素:

 event 对象的 relatedTarget 属性提供了相关元素的信息。这个属性只对于 mouseover和 mouseout 事件才包含值;对于其余事件,这个属性的值是 null 。

鼠标按钮:

0.左键  1滚轮键 2右键

事件信息:

 event 对象中还提供了 detail 属性,用于给出有关事件的更多信息。对于鼠标事件来讲, detail 中包含了一个数值,表示在给定位置上发生了多少次单击。在同一个元素上相继地发生一次 mousedown 和 mouseup 事件算做一次单击。 detail 属性从 1 开始计数,每次单击发生后都会递增。

鼠标滚轮事件:

 mousewheel 事件,会冒泡。 wheelDelta 属性。当用户向前滚动鼠标滚轮时, wheelDelta 是 120 的倍数;当用户向后滚动鼠标滚轮时, wheelDelta 是-120 的倍数。

跨浏览器的实现:。。。

触摸设备。。。

d.键盘与文本事件:

 keydown :当用户按下键盘上的任意键时触发,并且若是按住不放的话,会重复触发此事件。

 keypress :当用户按下键盘上的字符键时触发,并且若是按住不放的话,会重复触发此事件。按下 Esc 键也会触发这个事件。

keyup :当用户释放键盘上的键时触发。

键码:在发生 keydown 和 keyup 事件时, event 对象的 keyCode 属性中会包含一个代码,与键盘上一个特定的键对应。

e.变更事件:。。。

HTML5事件:

1.contextmenu 事件:提供自定义上下文菜单;

2.beforeunload 事件:能够用做询问用户是否真的要关闭页面,仍是但愿继续留下来;

EventUtil.addHandler(window, "beforeunload", function(event){
  event = EventUtil.getEvent(event);
  var message = "I'm really going to miss you if you go.";
  event.returnValue = message;
  return message;
});

3. DOMContentLoaded 事件:在造成完整的 DOM树以后就会触发,不理会图像、JavaScript 文件、CSS 文件或其余资源是否已经下载完毕。

与 load 事件不一样,DOMContentLoaded 支持在页面下载的早期添加事件处理程序,这也就意味着用户可以尽早地与页面进行交互。

4.readystatechange 事件:目的是提供与文档或元素的加载状态有关的信息;

5.pageshow 和 pagehide 事件

6.hashchange事件:在 URL 的参数列表(及 URL 中“#”号后面的全部字符串)发生变化时通知开发人员。

设备事件:。。。

5.内存和性能:添加到页面上的事件处理程序数量将直接关系到页面的总体运行性能。致使这一问题的缘由是多方面的。首先,每一个
函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定全部事件处理程序而致使的 DOM访问次数,会延迟整个页面的交互就绪时间。事实上,从如何利用好事件处理程序的角度出发,仍是有一些方法可以提高性能的。

a.事件委托:利用事件冒泡,只指定一个事件处理程序,就能够管理某一类型的全部事件。

var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
  event = EventUtil.getEvent(event);
  var target = EventUtil.getTarget(event);
  switch(target.id){
    case "doSomething":
      document.title = "I changed the document's title";
      break;
    case "goSomewhere":
      location.href = "http://www.wrox.com";
      break;
    case "sayHi":
      alert("hi");
      break;
    }
});

若是可行的话,也能够考虑为 document 对象添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件。

b.移除事件处理程序:若是你知道某个元素即将被移除,那么最好手工移除事件处理程序。

<div id="myDiv">
  <input type="button" value="Click Me" id="myBtn">
</div>

----------------------------------------------------- var btn = document.getElementById("myBtn"); btn.onclick = function(){ //先执行某些操做 btn.onclick = null; // 移除事件处理程序 document.getElementById("myDiv").innerHTML = "Processing..."; };

只要是经过 onload 事件处理程序添加的东西,最后都要经过 onunload 事件处理程序将它们移除。

6.模拟事件: createEvent() 方法建立 event 对象(鼠标,键盘,其余,自定义)

 

十4、表单脚本:

 在 JavaScript 中,表单对应的则是 HTMLForm-Element 类型。 HTMLFormElement 继承了 HTMLElement ,于是与其余 HTML 元素具备相同的默认属性。

form.submit():不会触发 submit 事件,所以要记得在调用此方法以前先验证表单数据。

form.reset():与调用 submit() 方法不一样,调用 reset() 方法会像单击重置按钮同样触发 reset 事件。

var form = document.getElementById("form1");
//取得表单中的第一个字段
var field1 = form.elements[0];
//取得名为"textbox1"的字段
var field2 = form.elements["textbox1"];
//取得表单中包含的字段的数量
var fieldCount = form.elements.length;

var colorFields = form.elements["color"]:能够经过name属性返回一个NodeList;

除了 form 属性以外,能够经过 JavaScript 动态修改其余任何属性。

var form = document.getElementById("myForm");
var field = form.elements[0];
//修改 value 属性
field.value = "Another value";
//检查 form 属性的值
alert(field.form === form); //true
//把焦点设置到当前字段
field.focus();
//禁用当前字段
field.disabled = true;

在第一次单击后就禁用提交按钮。(防止信用卡消费时等操做致使费用翻番):

EventUtil.addHandler(form, "submit", function(event){
  event = EventUtil.getEvent(event);
  var target = EventUtil.getTarget(event);
  //取得提交按钮
  var btn = target.elements["submit-btn"];
  //禁用它
btn.disabled = true;
})

每一个表单字段都有两个方法: focus() 和 blur() 。HTML5 为表单字段新增了一个 autofocus 属性。

2.文本框脚本:

text和textarea支持select()方法,选择文本框中的全部文本;

取得选择的文本:

function getSelectedText(textbox){
  return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
}

选择部分文本:

textbox.value = "Hello world!"
//选择全部文本
textbox.setSelectionRange(0, textbox.value.length); //"Hello world!"
//选择前 3 个字符
textbox.setSelectionRange(0, 3); //"Hel"
//选择第 4 到第 6 个字符
textbox.setSelectionRange(4, 7); //"o w

过滤输入;

 操做剪贴板;

自动切换焦点;

HTML5验证API:required,email\url等,min max,pattren='正则'    checkValidity() 方法能够检测表单中的某个字段是否有效。 novalidate;

3.选择框脚本;

4.表单序列化;

5.富文本编辑: contenteditable 属性

 

十5、Canvas

十6、HTML5脚本编程

postMessage()(跨文档消息传递)

原生拖放

媒体元素

历史状态管理:history.pushState()   history.popState()

 

十7、错误处理与调试:

try {
  window.someNonexistentFunction();
} catch (error){
  alert(error.message);
}

 finally 子句,则不管 try 或 catch 语句块中包含什么代码——甚至 return 语句,都不会阻止 finally 子句的执行。

错误类型:Error:基类型;  EvalError;  RangeError;   ReferenceError(找不到对象);SyntaxError;   TypeError(变量的类型并不符合要求所致);  URIError。

在用大型JS库的函数时,可使用try-catch语句。

function process(values){
  if (!(values instanceof Array)){
    throw new Error("process(): Argument must be an array.");
  }
  values.sort();
  for (var i=0, len=values.length; i < len; i++){
  if (values[i] > 100){
    return values[i];
  }
 }
return -1;
}

常见的错误类型:类型转换错误,数据类型错误,通讯错误

把错误记录到服务器:

function logError(sev, msg){
  var img = new Image();
  img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" +
  encodeURIComponent(msg);
}

十8、JS与XML

十9、E4X

二10、JSON

简单值:字符串用双引号;

对象:没有变量,属性要加双引号,末尾没有分号;

数组:没有变量和分号;

JSON对象的方法:

stringify():把JavaScript 对象序列化为 JSON 字符串;全部函数及原型成员都会被有意忽略,不体如今结果中。此外,值为undefined 的任何属性也都会被跳过。还能够接收另外两个参数,这两个参数用于指定以不一样的方式序列化 JavaScript 对象。第一个参数是个过滤器,能够是一个数组,也能够是一个函数;第二个参数是一个选项,表示是否在 JSON 字符串中保留缩进。

能够给对象定义 toJSON() 方法,返回其自身的 JSON 数据格式。(优先级高)

parse():把 JSON 字符串解析为原生 JavaScript 值;也接受第二个参数:

var book = {
  "title": "Professional JavaScript",
  "authors": [
    "Nicholas C. Zakas"
  ],
  edition: 3,
  year: 2011,
  releaseDate: new Date(2011, 11, 1)
};
var jsonText = JSON.stringify(book);
var bookCopy = JSON.parse(jsonText, function(key, value){
  if (key == "releaseDate"){
    return new Date(value);
  } else {
    return value;
  }
});
alert(bookCopy.releaseDate.getFullYear());

二11、Ajax(Asynchronous JavaScript + XML)和Comet

function createXHR(){
  if (typeof XMLHttpRequest != "undefined"){
      return new XMLHttpRequest();
  } else if (typeof ActiveXObject != "undefined"){
  if (typeof arguments.callee.activeXString != "string"){
    var versions = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i, len;
  for (i=0,len=versions.length; i < len; i++){
    try {
      new ActiveXObject(versions[i]);
      arguments.callee.activeXString = versions[i];
      break;
    } catch (ex){
    //跳过
    }
  }
}
   return new ActiveXObject(arguments.callee.activeXString);
 } else {
    throw new Error("No XHR object available.");
  }
}
var xhr = createXHR();

xhr.open("get", "example.txt", false);
xhr.send(null):参数为做为请求主体发送的数据;

在收到响应后,响应的数据会自动填充 XHR 对象的属性,

responseText :做为响应主体被返回的文本。

 responseXML;

status :响应的 HTTP 状态。(200成功,304未更新,404未找到资源)

statusText :HTTP 状态的说明。

var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "example.txt", true);
xhr.send(null);

发送异步请求,才能让JavaScript 继续执行而没必要等待响应。此时,能够检测 XHR 对象的 readyState 属性,该属性表示请求
/响应过程的当前活动阶段。(01234 4为已完成)

HTTP头部信息:使用 setRequestHeader() 方法能够设置自定义的请求头部信息。

FormData:为序列化表单以及建立与表单格式相同的数据(用于经过 XHR 传输)提供了便利。

var data = new FormData();
data.append("name", "Nicholas");
....
xhr.send(data)

跨源资源共享(CORS):

Origin: http://www.nczonline.net
----------------------------------------------------------------
Access-Control-Allow-Origin: http://www.nczonline.net

其余跨域技术:

图像Ping: 最经常使用于跟踪用户点击页面或动态广告曝光次数。只能GET。

JSONP:动态 <script> 元素来使用的,使用时能够为src 属性指定一个跨域 URL。

function handleResponse(response){
  alert("You’re at IP address " + response.ip + ", which is in " +
    response.city + ", " + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

 

var img = new Image();
img.onload = img.onerror = function(){
  alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";

Comet:(服务器推送)

长轮询:页面发起一个到服务器的请求,而后服务器一直保持链接打开,直到有数据可发送。发送完数据以后,浏览器关闭链接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断。使用 XHR 对象和 setTimeout() 就能实现。

 HTTP 流:经过侦听 readystatechange 事件及检测 readyState的值是否为 3,就能够利用 XHR 对象实现 HTTP 流。

服务器发送事件:(SSE)Server-Sent Event,单向通讯时推荐如读取比赛成绩

Web Sockets:聊天室等 双向通讯时推荐;

 

二12、JS高级技巧

1.高级函数

a.安全的类型检测:

function isFunction(value){
  return Object.prototype.toString.call(value) == "[object Function]";
}
function isRegExp(value){
  return Object.prototype.toString.call(value) == "[object RegExp]";
}

b.做用域安全的构造函数:(防止没有new)

function Person(name, age, job){
  if (this instanceof Person){
    this.name = name;
    this.age = age;
    this.job = job;
  } else {
    return new Person(name, age, job);
  }
}
var person1 = Person("Nicholas", 29, "Software Engineer");
alert(window.name); //""
alert(person1.name); //"Nicholas"
var person2 = new Person("Shelby", 34, "Ergonomist");
alert(person2.name); //"Shelby"

c.惰性载入函数:

惰性载入表示函数执行的分支仅会发生一次。有两种实现惰性载入的方式,第一种就是在函数被调用时再处理函数。

在这个惰性载入的 createXHR() 中, if 语句的每个分支都会为 createXHR 变量赋值,有效覆盖了原有的函数。最后一步即是调用新赋的函数。下一次调用 createXHR() 的时候,就会直接调用被分配的函数,这样就不用再次执行 if 语句了。

第二种方式return function(){}

d.函数绑定bind;

e.函数柯里化:调用另外一个函数并为它传入要柯里化的函数和必要参数。用于建立已经设置好了一个或多个参数的函数。

2.防篡改对象:

a.不可扩展对象:

Object.preventExtensions() 方法能够改变这个行为,让你不能再给对象添加属性和方法。

var person = { name: "Nicholas" };
Object.preventExtensions(person);
person.age = 29;
alert(person.age); //undefined

 Object.istExtensible() 方法还能够肯定对象是否能够扩展。

b.密封的对象:密封对象不可扩展,并且已有成员的 [[Configurable]] 特性将被设置为 false 。

var person = { name: "Nicholas" };
Object.seal(person);
person.age = 29;
alert(person.age); //undefined
delete person.name;
alert(person.name); //"Nicholas"

Object.isExtensible()

c.冻结的对象:冻结的对象既不可扩展,又是密封的,并且对象数据属性的 [[Writable]] 特性会被设置为 false 。

var person = { name: "Nicholas" };
Object.freeze(person);
person.age = 29;
alert(person.age); //undefined
delete person.name;
alert(person.name); //"Nicholas"
person.name = "Greg";
alert(person.name); //"Nicholas

 Object.isFrozen() 方法用于检测冻结对象。

3.高级定时器:

重复定时器:

setTimeout(function(){
  var div = document.getElementById("myDiv");
  left = parseInt(div.style.left) + 5;
  div.style.left = left + "px";
  if (left < 200){
    setTimeout(arguments.callee, 50);
  }
}, 50);

在前一个定时器代码执行完以前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。并且,它能够保证在下一次定时器代码执行以前,至少要等待指定的间隔,避免了连续的运行。

数组分块:

function chunk(array, process, context){
  setTimeout(function(){
  var item = array.shift();
  process.call(context, item);
  if (array.length > 0){
    setTimeout(arguments.callee, 100);
   }
  }, 100);
}

chunk() 方法接受三个参数:要处理的项目的数组,用于处理项目的函数,以及可选的运行该函数的环境。

函数节流:

var processor = {
  timeoutId: null,
//实际进行处理的方法
  performProcessing: function(){
//实际执行的代码
  },
//初始处理调用的方法
  process: function(){
    clearTimeout(this.timeoutId);
    var that = this;
    this.timeoutId = setTimeout(function(){
    that.performProcessing();
  }, 100);
}
};
//尝试开始执行
processor.process();

在这段代码中,建立了一个叫作 processor 对象。这个对象还有 2 个方法: process() 和performProcessing() 。前者是初始化任何处理所必须调用的,后者则实际进行应完成的处理。当调用了 process() ,第一步是清除存好的 timeoutId ,来阻止以前的调用被执行。而后,建立一个新的
定时器调用 performProcessing() 。时间间隔设为了 100ms,这表示最后一次调用 process() 以后至少 100ms 后才会调用 perform-Processing() 。因此若是 100ms以内调用了 process() 共 20 次, performanceProcessing() 仍只会被调用一次。

4.自定义事件:有助于解耦相关对象,保持功能的隔绝。

 

二十3、离线应用与客户端存储:

离线检测: navigator.onLine

应用缓存;

数据存储: 在 JavaScript 中经过 document.cookie 能够访问 cookie。 sessionStorage 和 localStorage 。前者严格用于在一个浏览器会话中存储数据,由于数据在浏览器关闭后会当即删除;后者用于跨会话持久化数据并遵循跨域安全策略。

二十4、最佳实践:

缩进大小为 4 个空格常见、合理的注释、变量和函数命名应规范、变量类型透明(当定义了一个变量后,它应该被初始化为一个值,来暗示它未来应该如何应用。或者用匈牙利标记法 "o" 表明对象, "s" 表明字符串, "i"表明整数, "f" 表明浮点数, "b" 表明布尔型。)、松散耦合、避免全局量。

命名空间:

//为 Professional Ajax 建立命名空间
Wrox.ProAjax = {};
//附加该书中所使用的其余对象
Wrox.ProAjax.EventUtil = { ... };
Wrox.ProAjax.CookieUtil = { ... };
//ProJS 还能够继续分别访问
Wrox.ProJS.EventUtil.addHandler( ... );
//以及 ProAjax
Wrox.ProAjax.EventUtil.addHandler( ... );

避免与null比较(好比能够if (values instanceof Array){})

性能:

一、避免全局查找

function updateUI(){
  var doc = document;
  var imgs = doc.getElementsByTagName("img");
  for (var i=0, len=imgs.length; i < len; i++){
    imgs[i].title = doc.title + " image " + i;
  }
  var msg = doc.getElementById("msg");
  msg.innerHTML = "Update complete.";
}

将在一个函数中会用到屡次的全局对象存储为局部变量老是没错的。

2.避免 with 语句

3.优化循环

对于大的 DOM 更改,使用 inner HTML 要比使用标准 DOM 方法建立一样的 DOM 结构快得多。

最小化现场更新

 HTMLCollection 对象:

发生如下状况时会返回 HTMLCollection 对象:
1.进行了对 getElementsByTagName() 的调用;
2.获取了元素的  childNodes 属性;
3.获取了元素的  attributes 属性;
4.访问了特殊的集合,如 document.forms 、 document.images 等。

var images = document.getElementsByTagName("img"),
image,
i, len;
for (i=0, len=images.length; i < len; i++){
image = images[i];
//处理
}

这段代码添加了 image 变量,保存了当前的图像。这以后,在循环内就没有理由再访问 images 的HTMLCollection 了 。

DOM 交互开销很大,因此须要限制 DOM 操做的次数。

相关文章
相关标签/搜索