JS基础学习

JS基本数据类型的值直接存储在栈内存
对象保存到堆内存中,变量保存的是对象的内存地址

// 变量声明了,但没有赋值
var i;
i // undefined

// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
  return x;
}
f() // undefined

// 对象没有赋值的属性
var  o = new Object();
o.p // undefined

// 函数没有返回值时,默认返回 undefined
function f() {}
f() // undefined

JS变量

JavaScript传递变量:值传递?引用传递

JavaScript的值传递和引用传递

值传递

当我们使用=将这些变量赋值到另外的变量,实际上是将对应的值拷贝了一份,然后赋值给新的变量。我们把它称作值传递

ax都包含 10,by都包含'abc',并且它们是完全独立的拷贝,互不干涉。如果我们将a的值改变,x不会受到影响。

var x = 10;
var y = "abc";
var a = x;
var b = y;
a = 5;
b = "def";
console.log(x, y, a, b); // 10, 'abc', 5, 'def'

引用传递

对象是通过引用传递,而不是值传递。也就是说,变量赋值只会将地址传递过去。

对于一个函数,给定一个输入,返回一个唯一的输出。除此之外,不会对外部环境产生任何附带影响。我们即会称该函数为纯函数。所有函数内部定义的变量在函数返回之后都被垃圾回收掉。

但是,如果函数的输入是对象(Array, Function, Object),那么传入的是一个引用。对该变量的操作将会影响到原本的对象。这样的编程手法将产生附带影响,使得代码的逻辑复杂和可读性变低。

function changeAgeAndReference(person) {
    person.age = 25;
    person = {
        name: "John",
        age: 50
    };

    return person;
}
var personObj1 = {
    name: "Alex",
    age: 30
};
var personObj2 = changeAgeAndReference(personObj1);
console.log(personObj1); //{name: "Alex", age: 25}
console.log(personObj2); //{name: "John", age: 50}

var的使用

//变量放在函数里——局部变量,函数外面访问不了
function f(){
       var name = "lyn";
       console.log(name)
   }
console.log("----"+name)     //先输出
f()                          //后输出
>>>----
>>>lyn

/*----------*/
function f(){
    //局部变量
    //不能给删除
    //会提升,仅仅是提升了声明
    console.log(b); //undefined
    var b = 2;
    console.log(b); //2
}
f();

/*----------*/
function f(){
    //全局变量
    //能够被删除,本质上是作为window对象的一个属性存在
    //不会被提升
    console.log(b); //直接报错
    b = 2;
}
f();

/*----------*/
(function ab() {
	var a=b=2;
	console.log(typeof a) //number
	console.log(typeof b) //number

})()
//a是局部变量,b是全局变量
console.log(typeof a) //undefined
console.log(typeof b)

let的使用

//let 声明的变量,不会提升
//let 不会成为window对象的属性
//let 可以形成一个块级作用域
//let 不能重复定义
//let 会出现暂存性死区
{	
    let a = 10;
    console.log(a) //10
}
console.log(a); //直接报错

/*----------*/
//暂存性死区
let a = 10;
{
	console.log(a)  //直接报错
	let a = 666;
}

/*----------*/
let a = 1;
let a = 2;
console.log(a); //直接报错

const的使用

//const 用来声明一个常量,声明时必须赋值且不能修改值
//const 声明的常量也是不能提升的
//const 不能重复声明
const PI = 3.14
PI = 666;
console.log(PI); //直接报错

函数

作用域

  1. 全局作用域
    • 全局作用域有一个全局对象window
    • 全局作用域中:创建的变量都会作为window对象的属性保存
    • 全局作用域中:创建的函数都会作为window对象的方法保存
  2. 函数作用域

声明提前

  1. 变量声明提前
  2. 函数声明提前

解析器在调用函数每次都会向函数内部传一个隐含的参数
这个隐含的参数就是this,this指向的是一个对象

function fun(){
	console.log(this)
}
var obj = {
	name:"123";
	sayName:fun;
};

以方法形式调用

obj.sayName();
>>>[object Object]  123

以函数形式调用

fun();
>>>[object Window]  全局

立即调用的函数表达式(IIFE)

(Immediately-Invoked Function Expression)

只对匿名函数使用这种“立即执行的函数表达式”

  1. 不必为函数命名,避免了污染全局变量
  2. IIFE内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();

//写法一
var tmp = newData;
processData(tmp);
storeData(tmp);
//写法二
(function(){
    var tmp = newData;
    processData(tmp);
    storeData(tmp);
}());

写法二比写法一更好,因为完全避免了污染全局变量。

arguments

JavaScript 函数参数

在调用函数时,浏览器每次都会传递两个隐含参数:

  1. 函数的上下文对象 this
  2. 封装实参的arguments
    • arguments是一个类数组对象(isArrayisinstanceof Array检查),它也可以通过索引来操作数据,也可以获取长度arguments.length
    • 它有一个属性叫callee ,这个属性对应一个函数对象,就是当前正在指向的函数对象
function fun(a,b){
    console.log(Array.isArray(arguments));
    console.log(arguments.callee == fun); //true
    //arguments[1]表示第二个实参
    console.log(arguments[1]);
}
fun("hello",true);

this

JavaScript 函数调用

总结

  1. this指向的,永远只可能是对象
  2. this指向谁,永远不取决于this写在哪!而是取决于函数在哪调用
  3. this指向的对象,我们称之为函数的上下文context,也叫函数的调用者

根据函数的调用方式不同,this 会指向不同的对象

  1. 以函数形式调用,this 是window
  2. 以方法形式调用,this 是调用方法的那个对象
  3. 以构造函数调用,this 是新创建的那个对象
  4. 使用callapply 调用时,this 是指定的那个对象
    • call()可以将实参在对象之后依次传递
    • apply()需要将实参封装到一个数组中统一传递
function fun(){
	console.log(this.name)	
}
var obj = {
	name:"123"
	sayName:fun
}
obj.sayName();

apply 和 call

JavaScript 函数 Call/Apply

在调用call()apply() 可以将一个对象指定为第一个参数

此时这个对象将会成为函数执行时的this

function fun(a,b){
    console.log("a = "+a);
    console.log("b = "+b);
}
var obj = {
    name:"obj",
    sayName:function(){
        alert(this.name);
    }
};
fun.call(obj,2,3);
fun.apply(obj,[2,3]);
>>>"a = 2"
>>>"b = 3"

闭包

JavaScript 闭包

  1. 可以读取函数内部的变量
  2. 让这些变量始终保持在内存中,即闭包可以使得它的诞生环境一直存在
  • 这个例子,闭包使得内部变量记住上一次调用时的运算结果(闭包可以看做是函数内部作用域的一个接口)
function creatIncrementor(start){
	return function(){
		return start++;
	};
}

var inc = creatIncrementor(5);
inc() //5
inc() //6
  • 这个例子,封装对象的私有属性和私有方法
function Person(name){
    var _age;
    function setAge(n){
        _age = n;
    }
    function getAge(){
        return _age;
    }
    return{
        name:name,
        getAge:getAge,
        setAge:setAge
    };
}

var p1 = Person("张三");
p1.setAge(25);
p1.getAge(); //25

注意:外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。

eval

eval没有自己的作用域,都在当前作用域内执行,因此可能会修改当前作用域的变量的值,造成安全问题。

(function f(){
    eval('var foo = 123');
    console.log(foo); // ReferenceError: foo is not defined
})()

eval的本质是在当前作用域之中,注入代码。通常情况下,eval 最常见的场合是解析 JSON 数据的字符串,不过正确的做法应该是使用原生的 JSON.parse 方法。

包装类

方法和属性能添加给对象,不能添加给基本数据类型

当我们对基本数据类型的值去调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后再调用对象的属性和方法。调用完以后,再将其转换为基本数据类型。

var s = 123;
s = s.toString();
s.hello = "你好";
console.log(s.hello) //undefined
console.log(s) //"123"
console.log(typeof s) //string

工厂方法创建对象

function creatPerson(name, age, gender){
	var obj = new Object();
	obj.name = name;
	obj.age = age;
	obj.gender = gender;
	obj.sayName = function(){
		alert(this.name)	
	};
	return obj;	
}
var obj2 = creatPearson("123",234,"345");

使用工厂方法创建对象,使用的构造函数都是Object
导致无法区分多种不同类型的对象

声明函数的三种方法

1.function命令

function print(s){
    console.log(s);
}

2.函数表达式

将一个匿名函数复制给变量,匿名函数又称函数表达式

name 属性返回function关键字之后的那个函数名

var print = function(s){
    console.log(s);
};
//var f = function f(){}

3.Function构造函数

构造函数可以解决这个问题 构造函数,习惯首字母大写
构造函数执行流程:

  1. 立即创建一个新的对象
  2. 将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
  3. 逐行执行函数中的代码
  4. 将新建的对象作为返回值返回
function Person(name,age,gender){
	this.name = name;
	this.age = age;
	this.gender = gender;
	this.sayName = function(){
		alert(this.name);
	}
}
var per = new Person("123",234,"345");
console.log(per.sayName)
>>>[object Object]  123

箭头函数

//ES5
var x = function(x,y){
    return x * y;
}
//ES6
const x = (x, y) => x * y;

typeof `运算符可以返回一个值的数据类型。

使用 instaceof 检查对象是否是一个类的实例

console.log(per instanceof Person);

函数补充

原型prototype

当函数以构造形式调用时,它所创建的对象都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象
我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中

function MyClass(){
}
//向MyClass的原型中添加属性name
MyClass.prototype.name = 123;
//向MyClass的原型中添加一个方法
MyClass.prototype.sayHello = function(){
    alert("hello");
};
var mc = new MyClass();

//使用in检查对象中是否包含某个属性时,如果对象中没有但是原型中有,也会返回true
console.log("name" in mc);  //true
//可以使用hasOwnProperty()来检查对象自身中是否包含该属性
console.log(mc.hasOwnProperty("name")); //false

当我们使用一个对象的属性或方法时,会先在自身中寻找

console.log(mc.__proto__.hasOwnProperty("hasOwnProperty")); //false
console.log(mc.__proto__.__proto__hasOwnProperty("hasOwnProperty")); //true
console.log(mc.__proto__.__proto__.__proto__); //null

toString

函数的 toString 方法返回一个字符串,内容是函数的源码

原生的函数,toString()方法返回function(){[native code]}

当我们直接在页面中打印一个对象时,实际上是输出对象的toString()方法的返回值

如果我们不希望在输出对象时输出[object Object],可以为对象添加一个toString()方法

function Person(name,age,gender){
	this.name = name;
	this.age = age;
	this,gender = gender;
}
//修改Person原型的toString
Person.prototype.toString = function(){
    return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
    
}
var per = new Person("孙悟空",18,"男");
console.log(per);

垃圾回收(GC)

当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。

var obj = new Object();
obj = null;

JavaScript对象

JS Array

JS Array

普通对象: 属性名 | 属性值

数组 : 索引 | 值

向数组添加元素:数组[索引] = 值

如果不存在的索引,返回undefined

使用字面量创建对象var obj = {};

使用字面量创建数组var arr = [];

一般不用构造函数创建数组:var arr = new Array();

数组的属性

length

  • 设置或返回数组中元素的数目

prototype

  • 向对象添加属性和方法

数组的方法

push()

  • 该方法可以向数组的末尾添加一个或多个元素,并返回数组新的长度

pop()

  • 该方法可以删除数组的最后一个元素,并返回删除的元素

unshift()

  • 向数组开头添加一个或多个元素,并返回数组的长度

shift()

  • 可以删除数组的第一个元素,并返回被删除的元素

遍历其它的方法

forEach()这个方法只支持IE8以上的浏览器

被传入的、后又被调用的函数就称为回调函数(我们创建,但不是由我们调用)

var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
//value 当前正在遍历的元素
//index 当前正在遍历元素的索引
//obj   正在遍历的数组
arr.forEach(function(value, index, obj){
    console.log(value);
});

slice()

  • 从数组提取指定元素,不改变原数组

splice()

  • 可以用于删除数组中的指定元素,并向数组添加新元素,会改变原数组
  • 第一个参数:开始位置的索引
  • 第二个参数:删除的数量
  • 第三个以后:这些元素会自动插入到开始位置索引前面

concat()

  • 可以连接两个或多个数组,并将新的数值返回,不改变原数组

join()

  • 该方法可以将数组转换成字符串,不改变原数组
  • 默认使用,作为连接符

reverse()

  • 该方法用来反转数组,改变原数组

sort()

  • 可以用来对数组中的元素进行排序,改变原数组
  • 对于纯数字的数组,也会按Unicode编码来排序
  • 可以在sort()添加一个回调函数,来指定排序规则
arr = [5,1,3,45,15];
arr.sort(function(a,b){
    //升序排列
    return a-b;
});
console.log(arr);

练习——数组去重

数组去重的12种方法

var arr = [1,2,3,2,2,1,3,4,2,5];
for(var i=0; i<arr.length; i++){
	for(var j=i+1; j<arr.length; j++){
		if(arr[i]==arr[j]){
			arr.splice(j,1);
			j--;
		}
	}
}
console.log(arr)

JS Boolean

JS Boolean

JS Date

JS Date

//直接使用构造函数创建Date对象,会封装当前代码执行时间
var d = new Date();
//getDate() 获取当前日期对象 返回0-6的值
var date = d.getDate();
//getTime() 获取当前日期对象的时间戳
var time = d.getTime();
console.log(time/1000/60/60/24/365)//利用时间戳测试代码性能
var start = Date.now();
var end = Date.now()
console.log(end-start)

JS Math

JS Math

Math不是构造函数

Math.PI 圆周率

Math.abs() 绝对值

Math.ceil() 向上取整

Math.floor() 向下取整

Math.round() 四舍五入取整

Math.random() 生成0-1之间的随机数

Math.max() 最大值

Math.min() 最小值

Math.pow(x,y) x的y次幂

Math.sqrt() 开方运算

//生成一个0-x之间的整数
Math.round(Math.random()*x)
//生成一个x-y之间的随机数
Math.round(Math.random()*(y-x)+x)

JS Number

JS Number

JS String

JS String

length 属性

charAt()

  • 返回字符串中指定位置的字符

  • str[5] = str.charAt(5)

charCodeAt()

  • 获取指定位置字符的字符编码

fromCharCode()

  • 根据字符编码去获取字符

  • 构造函数String.fromCharCode()

concat()

  • 连接连个或多个字符串
  • 作用和 + 一样

indexof()

  • 该方法可以检索一个字符串中是否包含指定内容
  • 从前往后找
  • 返回第一次出现的索引,没有返回 -1

lastIndexOf()

  • 从后往前找

slice()

  • 可以从字符串中截取指定的内容
  • 不会影响原字符串,将截取内容返回
  • 参数 第一个:开始位置;第二个:结束位置(可以传递负数,负数从后面计算)

substing()

  • 用来截取一个字符串,类似slice()
  • 这个方法不能接受负值
  • 如果第二个参数小于第一个,会自动交换参数位置

substr()

  • 截取字符串
  • 参数 第一个:开始位置索引;第二个:截取的长度

split()

  • 将一个字符串拆分为一个数组

toUpperCase()

  • 将一个字符串转换为大写并返回

toLowerCase()

  • 将一个字符串转换为小写并返回

JS RegExp

JS RegExp

  • 语法:var 变量 = new RegExp("正则表达式","匹配模式");

  • 在构造函数中可以传递一个匹配模式作为第二个参数

  • i 忽略大小写 g 全局匹配模式 m 执行多行匹配

正则表达式方法:

test()

  • 用来检查一个字符串是否符合正则表达式的规则,符合返回 true,不符合返回 false
var reg = new RegExp("ab","i");
var str = "a";
var result = reg.test(str);
console.log(reg.test("Ac"))

使用字面量来创建正则表达式:

  • 语法:var 变量 = /正则表达式/匹配模式

  • 使用 | 表示 或 的意思

  • [a-z] [A-Z] [A-z] [0-9]

支持正则表达式的 String 对象的方法:

split()

  • 可以将一个字符串拆分为一个数组

search()

  • 可以搜索字符串中是否包含指定内容
  • 如果搜索到指定内容,则会返回第一次出现的索引,没有返回-1

match()

  • 从一个字符串中将符合条件的内容提取出来
  • 默认只会找到第一个符合要求的内容,设置全局匹配模式,则会匹配到所有内容

replace()

  • 可以将字符串中指定内容替换为新的内容
var str = "1a2b3c4d5e6f7";
var result1 = str.split(/[A-z]/);
var result2 = str.search(/2[abc]3/);
var result3 = str.match(/[A-z]/ig);
var result4 = str.replace(/[a-z]/ig,"");

量词

{n} 正好出现n次
{m,n} 出现m-n次
{m,} m次以上
+ 至少1个,{1,}
* 1个或多个,{0,}
? 0个或1个,{0,1}
^ 表示开头
$ 表示结尾
检查一个字符串中是否含有.  \.
\w 任意字母、数字、_  [A-z0-9_]
\W 除了字母、数字、_  [^A-z0-9_]
\d 任意的数字 [0-9]
\D 除了数字 [^0-9]
\s 空格
\S 除了空格
\b 单词边界
\B 除了单词边界

JS 全局属性/函数

JavaScript 全局属性/函数

JS 运算符

JavaScript 运算符

DOM 对象

Document Object Model

出现问题

  1. 报错 : [Uncaught TypeError: Cannot set property ‘onclick’ of null

    参考文章

    //添加window.onload解决问题
    window.onload = function(){ 
        // your code 
    };
    

for循环执行顺序

//for循环会在页面加载完成之后立即执行,而响应函数会在超链接被点击时才执行,当响应函数执行时,for循环早已执行完毕
for(var i=0; i<allA.length; i++){
    alert("for循环正在执行"+i);
    all[i].onclick = function(){
      alert("响应函数正在执行"+i);
    };
}

浏览器渲染机制

参考链接:浏览器渲染机制

  • 当我们浏览器获得HTML文件后,会自上而下的加载,并在加载过程中进行解析和渲染
  • 加载说的就是获取资源文件的过程,如果在加载过程中遇到外部CSS文件和图片,浏览器会另外发送一个请求,去获取CSS文件和相应的图片,这个请求是异步的,并不会影响HTML文件的加载
  • 但是如果遇到JavaScript文件,HTML文件会挂起渲染的进程,等待JavaScript文件加载完毕后,再继续进行渲染
  1. 当用户输入一个URL时,浏览器就会向服务器发出一个请求,请求URL对应的资源

  2. 接受到服务器的响应内容后,浏览器的HTML解析器,会将HTML文件解析成一棵DOM树,DOM树的构建是一个深度遍历的过程,当前节点的所有子节点都构建完成以后,才会去构建当前节点的下一个兄弟节点。

  3. 将CSS解析成CSSOM树(CSS Rule Tree)

  4. 根据DOM树和CSSOM树,来构建Render Tree(渲染树),注意渲染树,并不等于DOM树,因为一些像head或display:none的东西,就没有必要放在渲染树中了。

  5. 有了Render Tree,浏览器已经能知道网页中有哪些节点,各个节点的CSS定义,以及它们的从属关系,下一步操作就是Layout,顾名思义,就是计算出每个节点在屏幕中的位置。

  6. Layout后,浏览器已经知道哪些节点要显示,每个节点的CSS属性是什么,每个节点在屏幕中的位置是哪里,就进入了最后一步painting,按照算出来的规则,通过显卡,把内容画到屏幕上。

HTML DOM Document 对象

HTML DOM Document 对象

节点

Node——构成HTML文档最基本的单元

常用节点分为四类:

  • 文档节点

    document对象作为window对象的属性存在的,我们不用获取可以直接使用

  • 元素节点

    浏览器会将页面中所有的标签都转换为一个元素节点,我们可以通过document的方法来获取元素节点

  • 属性节点

    可以通过元素节点来获取指定的属性节点

  • 文本节点

    获取文本节点时,一般先要获取元素节点。在通过元素节点获取文本节点

nodeName nodeType nodeValue
文档节点 #document 9 null
元素节点 标签名 1 null
属性节点 属性名 2 属性值
文本节点 #text 3 ※文本内容

事件

文档或浏览器窗口中发生的一些特定的交互瞬间

onload 事件会在整个页面加载完成之后才出发

可以确保我们代码执行所有的DOM对象已经加载完毕了

//这种写法我们成为结构和行为耦合,不方便维护,不推荐使用
<button id="btn" onmousemove="alert('点我干嘛!');">我是一个按钮</button>

<button id="btn">我是一个按钮</button>

var btn = document.getElementById("btn");
btn.onclick = function(){
    alert('你还点');
};

window.onload = function(){
    var btn = document.getElementByID("btn");
    btn.onclick = function(){
        alert('点点点');
    };
};
window.onload = function(){
	var btn01 = document.getElementById('btn01');
	btn01.onclick = function(){
		var bj = document.getElementById('bj');
		alert(bj.innerHTML);
	};
	var btn02 = document.getElementById('btn02');
	btn02.onclick = function(){
		var lis = document.getElementsByTagName('li');
//		alert(lis.length);
		for(var i=0;i<lis.length;i++){
			alert(lis[i].innerHTML);
		}
	};
	var btn03 = document.getElementById('btn03');
	btn03.onclick = function(){
		var inputs = document.getElementsByName('gender');
//		alert(inputs.length);
		for(var i=0;i<inputs.length;i++){
			alert(inputs[i].value)
		}
	};			
};

innerHTML通过这个属性可以获取到元素内部的html代码

  • 对于自结束标签,这个属性没有意义
  • 如果需要读取元素节点属性,可以直接使用 元素.属性名
  • class属性不能采用这种方式,读取class属性需要使用元素.className

innnerText 可以获取到元素内部的文本内容

var bj = document.getElmentById('bj');
//获取文本方法1
alert(bj.innerText);
//获取文本方法2
var fc = bj.firstChild;
alert(fc.nodeValue);

DOM查询方法

  1. getElementById() 返回对拥有指定id的第一个对象的引用
  2. getElementsByName() 返回带有指定名称的对象集合
  3. getElmentsByTagName() 返回带有指定标签名的对象集合
    • 2 和3 返回的是数组

DOM查询的其它方法

//保存body的引用
var body = document.body;
//保存html根标签
var html = document.documentElement;
//页面中所有的元素
var all = document.all;
var all = document.getElmentsByTagName('*');
console.log(all.length);  //undefined
//根据元素的class属性值查询一组元素节点对象 
//getElmentsByClassName() 不支持IE8以下浏览器

//document.querySelectoAll()
//需要一个选择器的字符串作为参数,可以根据一个CSS选择器来查询一个元素节点对象
//使用该方法只会返回唯一的一个元素
var div = document.querySelector('.box div')
练习——上一张/下一张 图片
window.onload = function(){
	var pre = document.getElementById('pre');
	var next = document.getElementById('next');
	var index = 0;
	var img = document.getElementsByTagName('img')[0];
	var imgArr = ["img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg","img/5.jpg"];
	var info = document.getElementById('info');
				
	info.innerHTML = "一共"+imgArr.length+"张图片,当前第"+(index+1)+"张"
	pre.onclick = function(){
		index--;
		if(index<0){
			index=imgArr.length-1;
		};		
		img.src = imgArr[index];
		info.innerHTML = "一共"+imgArr.length+"张图片,当前第"+(index+1)+"张"
	};
				
	next.onclick = function(){
		index++;
		if(index>imgArr.length-1){
			index=0;
		}
		img.src = imgArr[index];
		info.innerHTML = "一共"+imgArr.length+"张图片,当前第"+(index+1)+"张"
	};
};

DOM增删改

//document.creatElemnt() 用于创建一个元素节点对象
var li = document.creatElement('li');
//document.creatTextNode() 用于创建一个文本节点对象
var gzText = document.creatTextNode('gz');
//appendChild() 向一个父节点中添加一个新的子节点
li.appendChid(gzText);
var city = document.getElementById('city');
city.appendChild(li);
//insertBefore() 在指定的子节点钱插入新的子节点
var bj = document.getElementById(‘bj’);
city.insertBefore(li, bj);
//replaceChild() 使用指定的子节点替换已有的子节点
city.replaceChild(li, bj);
//removeChild() 删除一个子节点
city.removeChild(bj); //知道父元素是city
bj.parentNode.removeChild(bj) //更常用
/*使用innerHTML也可以完成DOM的增删改的相关操作
但是这个动作太大,所有节点都是新的,一般使用两种方式结合*/
city.innerHTML += "
  • gz
  • "
    ; //结合使用,推荐使用 var li = document.creatElement('li'); li.innerHTML = '广州'; //向li中设置文本 city.appendChild(li); /*点击超链接,超链接会跳转页面,这个是超链接默认行为 我们不希望默认行为出现 可以通过响应函数的最后return false来取消默认行为 也可以通过*/
    练习——添加/删除 信息
    function delA(){
    	var tr = this.parentNode.parentNode;
    //	var name = tr.getElementsByTagName('td')[0].innerHTML;
    	var name = tr.children[0].innerHTML;
    	var flag = confirm('确认删除'+ name +'吗?')
    	if(flag){
    		tr.parentNode.removeChild(tr);
    	}
    	return false;
    	};
    
    window.onload = function(){
    	var allA = document.getElementsByTagName('a');
    	for(var i=0;i<allA.length;i++){
    		allA[i].onclick = delA;
    	}
    	var addEmpButton = document.getElementById('addEmpButton');
    	//tbody.innerHTML添加 tr 不推荐
    	addEmpButton.onclick = function(){
    		var name = document.getElementById('empName').value;
    		var email = document.getElementById('email').value;
    		var salary = document.getElementById('salary').value;
    			
    		var tr = document.createElement('tr');
    			
    //		方法一:			
    //		var nameTd = document.createElement('td');
    //		var emailTd = document.createElement('td');
    //		var salaryTd = document.createElement('td');
    //		var aTd = document.createElement('td');
    //			
    //		var a = document.createElement('a');
    //			
    //		var nameText = document.createTextNode(name);
    //		var emailText = document.createTextNode(email);
    //		var salaryText = document.createTextNode(salary);
    //		var delText = document.createTextNode('Delete');
    //			
    //		nameTd.appendChild(nameText);
    //		emailTd.appendChild(emailText);
    //		salaryTd.appendChild(salaryText);
    //			
    //		a.appendChild(delText);
    //		a.href = 'javascript:;';
    //		aTd.appendChild(a);
    //		a.onclick = delA;
    //			
    //		tr.appendChild(nameTd);
    //		tr.appendChild(emailTd);
    //		tr.appendChild(salaryTd);
    //		tr.appendChild(aTd);
    
    //		方法二:
    		tr.innerHTML = ''+ name +''+
    						''+ email +''+
    						''+ salary +''+
    						'Delete';
    							
    		var a = tr.getElementsByTagName('a')[0];
    		a.onclick = delA;
    			
    		var employeeTable =  document.getElementById('employeeTable');
    		var tbody = employeeTable.getElementsByTagName('tbody')[0];
    		tbody.appendChild(tr);
    	};
    		
    }
    

    HTML DOM Element 对象

    HTML DOM Element 对象

    获取元素子节点

    1. getElmentsByTagName() 方法,返回当前节点的指定标签名后代节点

    2. childNodes 属性,会获取包括文本节点在内的所有子节点

      在IE8及以下的浏览器中,不会将空白文本当成子节点

    3. firstChild 属性,当前节点的第一个子节点

    4. lastChild 属性,当前节点的最后一个子节点

    5. children 属性,可以获取当前元素的所有子元素

    6. firstElementChild 获取当前元素的第一个子元素

      不支持IE8及以下的浏览器

    获取父节点或兄弟节点

    1. parentNode 属性,当前节点的父节点
    2. previousSibling 属性,当前节点的前一个兄弟节点
    3. nextSibling 属性,当前节点的后一个兄弟节点
    //isStr 要绑定单击响应函数的对象的id属性值
    //fun 事件的回调函数,当单击元素时,该函数将会被触发
    function myClick(idStr, fun){
        var btn = document.getElementById(idStr);
        btn.onclick = fun;
    }
    //最初写法
    var btn01 = document.getElementById('btn01');
    btn01.onclick = function(){
        var bj = document.getElementById('bj');
        alert(bj.innerHTML);
    };
    //改版写法
    myClick('btn01',function(){
        var bj = document.getElementById('bj');
        alert(bj.innerHTML);
    });
    
    练习——全选/全不选

    HTML DOM Checkbox 对象

    在事件的响应函数中,响应函数是给谁绑定的,this就是谁

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>全选练习</title>
    <script type="text/javascript">
    
    	window.onload = function(){
    		function myClick(isStr,fun){
    			var btn = document.getElementById(isStr);
    			btn.onclick = fun;
    		}
    		var item = document.getElementsByName('items');		
    		//全选
    		myClick('checkedAllBtn',function(){
    			for(var i=0;i<item.length;i++){
    				item[i].checked = true;
    			}
    			checkedAllBox.checked = true;
    		});
    		
    		//全不选
    		myClick('checkedNoBtn',function(){
    			for(var i=0;i<item.length;i++){
    				item[i].checked = false;
    			}
    			checkedAllBox.checked = false;
    		});
    		
    		//反选
    		myClick('checkedRevBtn',function(){
    			for(var i=0;i<item.length;i++){				
    				item[i].checked = !item[i].checked;
    				if(!item[i].checked){
    					checkedAllBox.checked = false;			
    				}
    			}
    		});
    		
    		//提交
    		myClick('sendBtn',function(){
    			for(var i=0;i<item.length;i++){
    				if(item[i].checked){
    					alert(item[i].value);
    				}
    			}
    		});
    		
    		//全选/全不选
    		myClick('checkedAllBox',function(){
    			for(var i=0;i<item.length;i++){
    				item[i].checked = this.checked
    			}
    		});
    		
    		//items
    		for(var i=0;i<item.length;i++){
    			item[i].onclick = function(){
    				checkedAllBox.checked = true;
    				for(var j=0;j<item.length;j++){
    					if(!item[j].checked){
    						checkedAllBox.checked = false;
    						break;
    					}
    				}
    			};
    		}
    	};
    	
    </script>
    </head>
    <body>
    
    	<form method="post" action="">
    		你爱好的运动是?<input type="checkbox" id="checkedAllBox" />全选/全不选 
    		
    		<br />
    		<input type="checkbox" name="items" value="足球" />足球
    		<input type="checkbox" name="items" value="篮球" />篮球
    		<input type="checkbox" name="items" value="羽毛球" />羽毛球
    		<input type="checkbox" name="items" value="乒乓球" />乒乓球
    		<br />
    		<input type="button" id="checkedAllBtn" value="全 选" />
    		<input type="button" id="checkedNoBtn" value="全不选" />
    		<input type="button" id="checkedRevBtn" value="反 选" />
    		<input type="button" id="sendBtn" value="提 交" />
    	</form>
    </body>
    </html>
    

    修改CSS

    参考链接:CSS参考手册

    修改样式语法:元素.style.样式名 = 样式值

    • 如果CSS样式名中含有-,这种名在JS中是不合法的,需要将这种样式名修改为驼峰命名法,去掉-,将-后的字母大写,比如:background-color -> backgroundColor

    • 通过style属性设置的样式为内联样式,但是如果在样式中写了!important,此时样式会有最高的优先级。

    • 如果设置偏移量(left/top)需要开启定位:positon

    读取样式语法:元素.style.样式名

    • 通过style属性设置和读取的都是内联样式

    读取当前显示样式语法:元素.currentStyle.样式名

    • backgroundColor 默认值为 transparent

    • height/width 默认值为 auto

    • 只有 IE浏览器 支持

    • 读取属性,只读不能修改

    其它浏览器可以使用getComputedStyle(),IE9+

    getComputedStyle()

    • 第一个参数:要获取样式的元素

    • 第二个参数:可以传递一个伪元素,一般都传null

    • 该方法返回一个对象,对象中封装了当前元素对应的样式

    • 读取属性,只读不能修改

    alert(getStyle(box1,'width'));
    function getStyle(obj, name)(){
        if(window.getComputedStyle){
            return getComputedStyle(obj, null)[name];
        }else{
            return obj.currentStyle[name];
        }
        //或者是
        //return windo.getComputedStyle?getComputedStyle(obj, null)[name]:obj.currentStyle[name]
    }
    

    HTML DOM Element 其它的对象

    参考链接:HTML DOM Element 对象

    clientHeightclientWidth

    • 获取可见宽度和高度,包括内容区和内边距
    • 属性不带px,返回都是一个数字,可以直接进行计算
    • 属性是只读,不能修改

    offsetHeightoffsetWidth

    • 获取元素的整个宽度和高度,包括内容区、内边距和边框
    • 属性不带px,返回都是一个数字,可以直接进行计算
    • 属性是只读,不能修改

    offsetParent

    • 获取当前元素的定位父元素
    • 会获取离当前元素最近的开启定位的祖先元素(position: …)
    • 如果所欲的祖先元素都没有开启定位,则返回body

    offsetLeftoffsetTop

    • 当前元素相对其定位父元素的 水平/垂直 偏移量

    scrollHeightscrollWidthscrollLeftscrollTop

    • 获取元素整个滚动区域的高度和宽度
    • 获取水平(Left)、垂直(Top)滚动条滚动的距离
    • scrollHeight - scrollTop == clientHeight 说明滚动条滚动到底
    • scrollWidth - scrollLeft == clientWidth 说明水平滚动条滚动到底
    练习——用户阅读协议

    onscroll ,该事件会在元素的滚动条滚动时触发

    CSS overflow 属性

    #info{
    overflow:auto;
    }
    
    window.onload = function(){
    	var info = document.getElementById('info');
    	var inputs = document.getElementsByTagName('input');
    	info.onscroll = function(){
    		if(info.scrollHeight - info.scrollTop == info.clientHeight){
    			inputs[0].disabled = false;
    			inputs[1].disabled = false;
    		}
    	};
    };
    
    练习——魔方变换
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Documenttitle>
        <style type="text/css">
            *{
                padding: 0;
                margin: 0;
            }
            #container{
                height: 300px;
                width: 300px;
                margin: 150px auto;
            }
            .box{
                height: 300px;
                width: 300px;
                transform-style: preserve-3d;
                /* transform: rotateX(45deg) rotateY(45deg); */
                animation: rotate 8s linear infinite;
            }
            /* 动画参数
               animation-timing-function:linear
               animation-iteration-count:infinite*/
            @keyframes rotate{
                0%{
                    transform: rotateX(0deg) rotateY(0deg);
                }
                100%{
                    transform:rotateX(360deg) rotateY(360deg)
                }
            }
            .boxpage{
                height: 300px;
                width: 300px;
                position: absolute;
                transform-style: preserve-3d;
            }
            .top{
                /* background-color: red; */
                transform: translateZ(150px)
            }
            .bottom{
                /* background-color: green; */
                transform: translateZ(-150px) rotateX(180deg);
            }
            .right{
                /* background-color: yellow; */
                transform: translateX(150px) rotateY(90deg);
            }
            .left{
                /* background-color: orange; */
                transform: translateX(-150px) rotateY(-90deg);
            }
            .front{
                /* background-color: blue; */
                transform: translateY(150px) rotateX(90deg);
            }
            .back{
                /* background-color: purple; */
                transform: translateY(-150px) rotateX(-90deg);
            }
            .boxpage div:nth-child(1){
                animation: rotate-div 4.5s ease-in;
            }
            .boxpage div:nth-child(2){
                animation: rotate-div 4.5s ease-in 0.5s;
            }
            .boxpage div:nth-child(3){
                animation: rotate-div 4.5s ease-in 1s;
            }
            .boxpage div:nth-child(4){
                animation: rotate-div 4.5s ease-in 1.5s;
            }
            .boxpage div:nth-child(5){
                animation: rotate-div 4.5s ease-in 2s;
            }
            .boxpage div:nth-child(6){
                animation: rotate-div 4.5s ease-in 2.5s;
            }
            .boxpage div:nth-child(7){
                animation: rotate-div 4.5s ease-in 3s;
            }
            .boxpage div:nth-child(8){
                animation: rotate-div 4.5s ease-in 3.5s;
            }
            .boxpage div:nth-child(9){
                animation: rotate-div 4.5s ease-in 4s;
            }
            @keyframes rotate-div{
                0%{
                    transform: translateZ(0px) scale(1) rotateZ(0deg);
                }
                20%{
                    transform: translateZ(300px) scale(0) rotateZ(720deg);
                }
                70%{
                    transform: translateZ(300px) scale(0) rotateZ(720deg);
                }
                100%{
                    transform: translateZ(0px) scale(1) rotateZ(0deg);
                }
            }
        style>
    head>
    <body>
        <div id="container">
            <div class="box">
                <div class="boxpage top">div>
                <div class="boxpage bottom">div>
                <div class="boxpage right">div>
                <div class="boxpage left">div>
                <div class="boxpage front">div>
                <div class="boxpage back">div>
            div>
        div>
        
        <script type="text/javascript">
            /* 通过CSS选择器查找 */
            var arr = document.querySelectorAll(".boxpage");
            /* 遍历6个面的每一个面 */
            for(var n = 0; n < arr.length; n++){
                /* 外层循环 遍历行 */
                for(var r = 0; r < 3; r++){
                    /* 内层循环 遍历列 */
                    for(var c = 0; c < 3; c++){
                        /* 创建新的 HTML 元素 */
                        var divs = document.createElement("div");
                        /* border-box 通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度 */
                        divs.style.cssText = "width: 100px;height: 100px;border: 2px solid #fff;\
                        box-sizing: border-box;background-color: red;position: absolute;\
                        background-image:url(images/B"+n+".png);background-size: 300px 300px;"
                        /* 追加到已有的元素上 */
                        arr[n].appendChild(divs);
                        /* length 定义元素的左边到最近一个具有定位设置父元素的左部边缘的位置 */
                        divs.style.left = c * 100 + "px";
                        divs.style.top = r * 100 + "px";               
                        /* background-repeat: no-repeat 	background-image不会重复 */
                        /* X轴往左移动 Y轴往上移动,值应为负数 */
                        divs.style.backgroundPositionX = -c * 100 + "px";
                        divs.style.backgroundPositionY = -r * 100 + "px";
                    }
                }
    
            }
        script>
    body>
    html>
    

    HTML DOM Event 对象

    HTML DOM 事件

    onmousemove 该事件将会在鼠标在元素中移动时被触发

    事件对象

    • 当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数
    • 当事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标、键盘哪个按键被按下、鼠标滚轮滚动的方向

    clientXclientY 可以获得鼠标指针的 水平/垂直 坐标

    • IE8及以下的浏览器,是将事件对象作为window对象的属性保存的

    pageXpageY 可以获取鼠标相对于当前页面的坐标

    • IE8以下不支持

    chorme 认为浏览器的滚动条是body的,可以通过body.scrollTop 来获取

    火狐等浏览器认为浏览器的滚动条是html的,可以通过documentElement.scroolToP 来获取

    练习——获取坐标系/div跟鼠标移动
    window.onload = function(){
    	var areaDiv = document.getElementById('areaDiv');
    	var coordinate = document.getElementById('coordinate');
    	var box = document.getElementById('box');
    	areaDiv.onmousemove = function(event){
    /*		if(!event){
    			event = window.event;
    		}*/
    		event = event || window.event
    		var x = event.clientX;
    		var y = event.clientY;
    		coordinate.innerHTML = 'x = ' + x + ', y = ' + y ;		
    	};
    	document.onmousemove = function(event){
    		var st = document.body.scrollTop || document.documentElement.scrollTop;
    		var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
    		var x1 = event.clientX;
    		var y1 = event.clientY;
    		box.style.left = x1 + sl + 'px';
    		box.style.top = y1 + st + 'px';
    	};				
    };
    

    事件的冒泡(Bubble)

    • 冒泡就是事件的向上传到,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
    • 在开发中大部分情况冒泡都是有用的,如果不希望发生冒泡可以通过事件对象来取消冒泡 event.cancelBubble = true

    事件的委派

    • 将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素从而通过祖先元素的响应函数来处理事件
    • 事件委派是利用冒泡,通过委派可以减少事件绑定的次数,提高程序的性能

    target 表示触发事件的对象

    • event.target.className == "link" 来执行我们期望的元素

    事件的绑定

    addEventListener()

    addEventListener() 可以为元素绑定响应函数,可同时为一个元素的相同事件同时绑定多个响应函数,当事件被触发时,响应函数将会按照函数的绑定顺序执行

      1. 事件的字符串,不要on
      1. 回调函数,当时间触发时该函数会被调用
      1. 是否在捕获阶段触发事件,需要一个布尔值,一般都传false
    • 不支持IE8及以下浏览器
    • this,是绑定事件的对象

    addEventListener("click",function(){},false)

    attachEvent() ,可以同时为一个事件绑定多个处理函数,不同的是它是后绑定先执行,执行顺序和addEventListener() 相反

    • IE8中用来绑定事件
      1. 事件的字符串
      1. 回调函数
    • 浏览器调用 this,是window
    • 自己调用 callback.call(obj) 相当于改this

    attachEvent("onclick",function(){})

    window.onload = function(){
    	var box1 = document.getElementById('box1');
    	bind(box1,'click',function(){alert(this)});
    };
    //obj要绑定的对象
    //eventStr 事件的字符串(不要on)
    //callback 回调函数
    function bind(obj, eventStr, callback){
    	if(obj.addEventListener){
    		//一般情况我们不希望在捕获阶段触发事件,所以第三个参数一般都是false
    		obj.addEventListener(eventStr, callback, false);
    	}else{
    		//this 是谁由调用方式决定
    		obj.attachEvent('on'+eventStr, function(){callback.call(obj);});
    	}
    }
    

    事件的传播

    微软公司认为事件应该是由内向外传播,事件应该在冒泡阶段执行

    网景公司认为事件应该是由外向内传播,事件应该在捕获阶段执行

    W3C综合两公司方案,将事件传播分成三个阶段

    1. 捕获阶段
      • 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但默认此时不会触发事件
      • IE8及以下的浏览器没有捕获阶段
    2. 目标阶段
      • 事件捕获到目标元素,捕获结束在目标元素上触发事件
    3. 冒泡阶段
      • 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件

    拖拽

    1. 当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
    2. 当鼠标移动时被拖拽元素跟鼠标移动 onmousemove
    3. 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup

    当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,此时会导致拖拽功能异常,这个是浏览器提供的默认行为,如果不希望发生这个行为,则可以通过 return false 来取消默认行为

    IE8需要使用 setCapture ,只有IE支持,火狐调用时不会报错,Chrome调用会报错

    window.onload = function(){
    	var box1 = document.getElementById('box1');
    	drag(box1);
    };
    
    function drag(obj){
    	obj.onmousedown = function(event){
    		event = event || window.event;
    		obj.setCapture && obj.setCapture();
    		var ol = event.clientX - obj.offsetLeft;
    		var ot = event.clientY - obj.offsetTop;
    		//获取鼠标坐标
    		document.onmousemove = function(event){
    			event = event || window.event;
    			var x = event.clientX - ol;
    			var y = event.clientY - ot;
    			obj.style.left = x + 'px';
    			obj.style.top = y + 'px';
    		};
    		//全部取消,相当于一次性事件
    		document.onmouseup = function(){
    			document.onmousemove = null;
    			document.onmouseup = null;
    			obj.releaseCapture && obj.releaseCapture();
    		};
    		return false;
    	};
    }
    

    滚轮

    onmousewheel 已废弃。 使用onwheel 事件替代

    onmousewheel鼠标滚轮的事件,会在滚轮滚动时触发,但是火狐不支持该属性

    火狐需要使用DOMMouseScroll来绑定滚动事件,该事件需要通过addEventListener() 函数来绑定

    event.wheelDelta 可以获取鼠标滚轮的方向

    当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,这是浏览器的默认行为,如果不希望发生,则可以取消默认行为 return false

    使用addEventListener() 方法绑定响应函数,取消默认行为时不能使用return false,需要使用 event.preventDefault()来取消默认行为

    window.onload = function(){
    	var box1 = document.getElementById('box1');
    	box1.onmousewheel = function(event){
    		event = event || window.event;
            alert(event.detail); //火狐 向上滚是-3 向下滚是3
            alert(event.wheelDelta); //谷歌 向上滚是120 向下滚是-120
            //如果box1.onmousewhell 改为box1.onwheel
            alert(event.detail); //火狐 向上向下滚都是0
    		if(event.wheelDelta > 0 || event.detail < 0){
    			box1.style.height = box1.clientHeight - 10 +'px'; 
    		}else{
    			box1.style.height = box1.clientHeight + 10 +'px'; 
    		}
    		event.preventDefault && event.preventDefault();
    		return false;
    	};
    	//火狐绑定滚动事件
    	bind(box1,"DOMMouseScroll",box1.onmousewheel);
    };
    function bind(obj, eventStr, callback){
    	if(obj.addEventListener){
    		obj.addEventListener(eventStr, callback, false)
    	}else{
    		obj.attachEvent('on'+eventStr, function(){callback.call(obj);})
    	}
    }
    

    键盘

    键盘事件

    • onkeydown 按键被按下

    • onkeyup 按键被松开

    • onkeypress 按键被按下并松开

    • keyCode 通过它可以判断哪个按键被按下了

    键盘属性

    • altKey
    • ctrlKey
    • shiftKey
    • 这三个用来判断 alt、ctrl、 shift 是否被按下

    在文本框中输入内容,属于onkeydown 的默认行为,如果在onkeydown 中取消默认行为,则输入内容,不会出现在文本框中 return false

    window.onload = function(){
    	document.onkeydown = function(event){
    		//alert(event.keyCode);
    		event = event || window.event;
    		var speed = 10;
    		if(event.shiftKey){
    			speed = 100;
    		}
    		switch(event.keyCode){
    			case 37:
    				box1.style.left = box1.offsetLeft - speed +'px';
    				break;
    			case 38:
    				box1.style.top = box1.offsetTop - speed +'px';
    				break;				
    			case 39:
    				box1.style.left = box1.offsetLeft + speed +'px';
    				break;										
    			case 40:
    				box1.style.top = box1.offsetTop + speed +'px';
    				break;				
    		}
    	};
    };
    

    Browser 对象

    The Browser Object Model (BOM)

    1. Window
      • 代表整个浏览器的窗口,同时window也是网页中的全局对象
    2. Navigator
      • 代表当前浏览器的信息,通过该对象可以来识别不同的浏览器
    3. Location
      • 代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
    4. History
      • 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录。由于隐私原因,该对象不能获取到具体得历史记录,只能操作浏览器向前或向后翻页,而且该操作只在当前访问时有效
    5. Screen
      • 代表用户的屏幕信息,通过该对象可以获取到用户的显示器的相关信息

    这些BOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用

    Navigator

    Navigator 对象

    • 代表的当前浏览器的信息,通过该对象可以识别不同的浏览器

    现在我们一般只是用userAgent 来判断浏览器的信息

    IE浏览器可以通过浏览器中特有的对象,来判断浏览器的信息,比如:ActiveObject

    History

    • 对象可以用来操作浏览器向前或向后翻页

    length 属性,可以获取到当前访问的链接数量

    back 方法,可以用来回退到上一个页面,作用和浏览器的回退按钮一样

    forward 方法,可以跳转下一个页面,作用和浏览器的前进按钮一样

    go() 方法,可以用来跳转到指定的页面

    • 它需要一个整数作为参数
    • 1:表示向前跳转一个页面 history.go(1)
    • -1:表示向后跳转一个页面 history.go(-1)

    Location

    Location 对象

    • 该对象中封装了浏览器的地址栏信息
    • 如果将location属性修改为一个完整的路径或相对路径,则页面会自动跳转到该路径,并且会生成响应的历史记录

    assign() 用来跳转到其它的页面,作用和直接修改location一样

    reload() 用于重新加载当前页面,左右和刷新按钮一样,如果方法中传递一个true ,作为参数,则会强制清空缓存刷新页面

    replace() 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面,不会生成历史记录,不能使用回退按钮回退

    Window

    Window对象

    confirm() 用于弹出一个带有确定和取消按钮的提示框,需要一个字符串作为参数,该字符串将会作为提示文字显示出来

    • 如果点击确定 返回true;如果点击取消 返回 false
    <input type="text" name="empName" id="empName" />
    var name = document.getElementById('empName');
    alert(name);  //[object HTMLInputElement]
    //文本框内容就是文本框的value属性
    var name = document.getElementById('empName').value;
    alert(name);  //aaa(文本框内容)
    

    setInterval 定时调用。可以将一个函数没隔一段时间执行一次

    1. 回调函数,该函数会每隔一段时间被调用一次
    2. 每次调用间隔的时间,单位是毫秒

    计时器

    window.onload = function(){
    	var num = 1;
    	var timer = setInterval(function(){
    		count.innerHTML = num++;
    		if(num == 11){
    			clearInterval(timer);
    		}
    	},1000);
    };
    

    图片自动切换

    window.onload = function(){
    	var img1 = document.getElementById('img1');
    	var index = 0;
    	var imgArr  = ["img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg","img/5.jpg"];
    	var timer;
    	var start = document.getElementById('start');
    	start.onclick = function(){
    		clearInterval(timer);
    		timer = setInterval(function(){
    			index++;
    			index %= imgArr.length;
    			img1.src = imgArr[index];
    		},1000);
    	};
    	var end = document.getElementById('end');
    	end.onclick = function(){
    		clearInterval(timer);
    	};
    };
    

    移动div

    window.onload = function(){
    	var speed = 10;
    	var dir = 0;
    	setInterval(function(){
    		switch(dir){
    			case 37:
    				box1.style.left = box1.offsetLeft - speed +'px';
    				break;
    			case 38:
    				box1.style.top = box1.offsetTop - speed +'px';
    				break;				
    			case 39:
    				box1.style.left = box1.offsetLeft + speed +'px';
    				break;										
    			case 40:
    				box1.style.top = box1.offsetTop + speed +'px';
    				break;				
    		}
    	},10)
    	document.onkeydown = function(event){
    		event = event || window.event;
    		if(event.shiftKey){
    			speed = 100;
    		}else{
    			speed = 10;
    		}
    		dir = event.keyCode;
    	};
    	document.onkeyup = function(){
    		dir = 0;
    	};
    };
    

    setTimeout 延时调用。不马上执行,隔一段时间以后再执行,而且只会执行一次。clearTimeout() 来关闭一个延时调用

    定时调用与延时调用区别,定时调用会执行多次,而延时调用只会执行一次。

    生硬——切换

    window.onload = function(){
    	var box1 = document.getElementById('box1');
    	var btn01 = document.getElementById('btn01');
    	btn01.onclick = function(){
    		move(box1, 'width', 800, 2, function(){
    			move(box1, 'height', 800, 2, function(){
    				move(box1, 'top', 0, 2, function(){
    				});
    			});
    		});
    	};
    	function move(obj, attr, target, speed, callback){
    		clearInterval(obj.timer);
    		var current = parseInt(getStyle(obj, attr));
    		if(current > target){
    			speed = -speed;
    		}
    		obj.timer = setInterval(function(){
    			var oldValue = parseInt(getStyle(obj, attr));
    			var newValue = oldValue + speed;
    			if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)){
    				newValue = target;
    			}
    			obj.style[attr] = newValue + 'px';
    			if(newValue == target){
    				clearInterval(obj.timer);
    				callback && callback();
    			}
    		});
    	}
    	function getStyle(obj, name){
    		return window.getComputedStyle ? getComputedStyle(obj, null)[name] : obj.currentStyle[name]
    	}
    };
    

    轮播图

    
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title>title>
    		<style type="text/css">
    			*{
    				padding: 0;
    				margin: 0;
    			}
    			#outer{
    				width: 520px;
    				height: 333px;
    				margin: 50px auto;
    				background-color: #ADFF2F;
    				padding: 10px 0;
    				position: relative;
    				overflow: hidden;	
    			}
    			#imgList{
    				list-style: none;
    				left: 0;
    				position: absolute;
    			}
    			#imgList li{
    				float: left;
    				margin: 0 10px;
    			}
    			#navDiv{
    				position: absolute;
    				bottom: 15px;
    			}
    			#navDiv a{
    				float: left;
    				width: 15px;
    				height: 15px;
    				background: red;
    				margin: 0 5px;
    				opacity: 0.5;
    				filter: alpha(opacity=50);
    			}
    			#navDiv a:hover{
    				background-color: black;
    			}
    		style>
    	head>
    <script type="text/javascript">
    window.onload = function(){
    	var imgList = document.getElementById('imgList');
    	var imgArr = document.getElementsByTagName('img');
    	imgList.style.width = 520*imgArr.length + 'px';
    	var navDiv = document.getElementById('navDiv');
    	var outer = document.getElementById('outer');
    	navDiv.style.left = (outer.offsetWidth - navDiv.offsetWidth)/2 +'px'
    	index = 0;
    	var allA = document.getElementsByTagName('a');
    	allA[index].style.backgroundColor = 'black';
    	for(var i=0;i<allA.length;i++){
    		allA[i].num = i;
    		allA[i].onclick = function(){
    			clearInterval(timer);
    			index = this.num;
    			setA();
    			move(imgList,'left',-520*index,10,function(){
    				autoChange();
    			});
    		};
    	}
    	autoChange();
    	function setA(){
    		if(index >= imgArr.length-1){
    			index = 0;
    			imgList.style.left = 0;
    		}
    		for(var i=0;i<allA.length;i++){
    			allA[i].style.backgroundColor = '';
    		}
    		allA[index].style.backgroundColor = 'black';
    	}
    	function move(obj, attr, target, speed, callback){
    		clearInterval(obj.timer);
    		var current = parseInt(getStyle(obj, attr));
    		if(current > target){
    			speed = -speed;
    		}
    		obj.timer = setInterval(function(){
    			var oldValue = parseInt(getStyle(obj, attr));
    			var newValue = oldValue + speed;
    			if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)){
    				newValue = target;
    			}
    			obj.style[attr] = newValue + 'px';
    			if(newValue == target){
    				clearInterval(obj.timer);
    				callback && callback();
    			}
    		});
    	}
    	function getStyle(obj, name){
    		return window.getComputedStyle ? getComputedStyle(obj, null)[name] : obj.currentStyle[name]
    	}
    	var timer;
    	function autoChange(){
    		timer = setInterval(function(){
    			index ++;
    			index %= imgArr.length;
    			move(imgList,'left',-520*index,10,function(){
    				setA();
    			});
    		},3000);
    	}
    };
    script>
    	<body>
    		<div id="outer">
    			<ul id="imgList">
    				<li><img src="img/1.jpg" alt="" />li>
    				<li><img src="img/2.jpg" alt="" />li>
    				<li><img src="img/3.jpg" alt="" />li>
    				<li><img src="img/4.jpg" alt="" />li>
    				<li><img src="img/5.jpg" alt="" />li>
    				<li><img src="img/1.jpg" alt="" />li>
    			ul>
    			<div id="navDiv">
    				<a href="javascript:;">a>
    				<a href="javascript:;">a>
    				<a href="javascript:;">a>
    				<a href="javascript:;">a>
    				<a href="javascript:;">a>
    			div>
    		div>
    	body>
    html>
    
    

    box.className

    可以修改元素的class属性来间接的修改样式,表现和行为进一步分离

    能先改类 尽量改类,其次再使用 style

    window.onload = function(){
        var box = document.getElementById('box');
        var btn01 = document.getElementById('btn01');
        btn01.onclick = function(){
            toggleClass(box,'b2');
        };
        function addClass(obj, cn){
            if(!hasClass(obj, cn)){
                obj.className += " "+cn;
             }
        }
        function hasClass(obj, cn){
            var reg = new RegExp("\\b"+cn+"\\b");
        	return reg.test(obj.className);
    	}
    	function removeClass(obj, cn){
    	    var reg = new RegExp("\\b"+cn+"\\b");
    	    obj.className = obj.className.replace(reg, "");
    	}
    	function toggleClass(obj, cn){
    	    if(hasClass(obj, cn)){
    	        removeClass(obj, cn);
    	    }else{
    	        addClass(obj, cn);
    	    }
    	}
    };			
    

    二级菜单

    @charset "utf-8";
    
    /* sdmenu */
    
    div.sdmenu {
    	width: 150px;
    	margin: 0 auto;
    	font-family: Arial, sans-serif;
    	font-size: 12px;
    	padding-bottom: 10px;
    	background: url(bottom.gif) no-repeat right bottom;
    	color: #fff;
    }
    
    div.sdmenu div {
    	background: url(title.gif) repeat-x;
    	overflow: hidden;
    }
    
    div.sdmenu div:first-child {
    	background: url(toptitle.gif) no-repeat;
    }
    
    div.sdmenu div.collapsed {
    	height: 25px;
    }
    
    div.sdmenu div span {
    	display: block;
    	height: 15px;
    	line-height: 15px;
    	overflow: hidden;
    	padding: 5px 25px;
    	font-weight: bold;
    	color: white;
    	background: url(expanded.gif) no-repeat 10px center;
    	cursor: pointer;
    	border-bottom: 1px solid #ddd;
    }
    
    div.sdmenu div.collapsed span {
    	background-image: url(collapsed.gif);
    }
    
    div.sdmenu div a {
    	padding: 5px 10px;
    	background: #eee;
    	display: block;
    	border-bottom: 1px solid #ddd;
    	color: #066;
    }
    
    div.sdmenu div a.current {
    	background: #ccc;
    }
    
    div.sdmenu div a:hover {
    	background: #066 url(linkarrow.gif) no-repeat right center;
    	color: #fff;
    	text-decoration: none;
    }
    
    window.onload = function(){
    	var menuSpan = document.querySelectorAll('.menuSpan');
    	var openDiv = menuSpan[0].parentNode;
    	for(var i=0;i<menuSpan.length;i++){
    		menuSpan[i].onclick = function(){
    			var parentDiv = this.parentNode;
    			toggleMenu(parentDiv);
    			if(openDiv!=parentDiv && !hasClass(openDiv,'collapsed')){
    				toggleMenu(openDiv);
    			}
    			openDiv = parentDiv;
    		}
    	};
    	function toggleMenu(obj){
    		var begin = obj.offsetHeight;
    		toggleClass(obj,'collapsed');
    		var end = obj.offsetHeight;
    		obj.style.height = begin + 'px';
    		move(obj, 'height', end, 10, function(){
    			obj.style.height = '';
    		});	
    	}
    	function move(obj, attr, target, speed, callback){
    		clearInterval(obj.timer);
    		var current = parseInt(getStyle(obj, attr));
    		if(current > target){
    			speed = -speed;
    		}
    		obj.timer = setInterval(function(){
    			var oldValue = parseInt(getStyle(obj, attr));
    			var newValue = oldValue + speed;
    			if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)){
    				newValue = target;
    			}
    			obj.style[attr] = newValue + 'px';
    			if(newValue == target){
    				clearInterval(obj.timer);
    				callback && callback();
    			}
    		});
    	}
    	function getStyle(obj, name){
    		return window.getComputedStyle ? getComputedStyle(obj, null)[name] : obj.currentStyle[name]
    	}
        function addClass(obj, cn){
            if(!hasClass(obj, cn)){
                obj.className += " "+cn;
             }
        }
        function hasClass(obj, cn){
            var reg = new RegExp("\\b"+cn+"\\b");
        	return reg.test(obj.className);
    	}
    	function removeClass(obj, cn){
    	    var reg = new RegExp("\\b"+cn+"\\b");
    	    obj.className = obj.className.replace(reg, "");
    	}
    	function toggleClass(obj, cn){
    	    if(hasClass(obj, cn)){
    	        removeClass(obj, cn);
    	    }else{
    	        addClass(obj, cn);
    	    }
    	}		
    };
    

    Json

    Json就是一个特殊格式的字符串,这个字符串可以被任意语言所识别,并且可以转换成任意语言汇总的对象,Json在开发中主要用来数据的交互

    • Javascript Object Notation JS对象表示法

    • Json和JS的格式一样,只不过Json字符串中的属性名必须加双引号,其他的和JS语法一致

    Json分类:

    1. 对象 {}
    2. 数组 []

    Json中允许的值

    1. 字符串
    2. 数值
    3. 布尔值
    4. null
    5. 对象
    6. 数组

    Json–> JS对象

    JSON.parse()

    • 可以将Json字符串转换为JS对象
    • 需要一个Json字符串作为参数,会将该字符串转换为JS对象并返回

    JS对象 --> Json

    JSON.stringify()

    • 可以将一个JS对象转换为Json字符串
    • 需要一个JS对象作为参数,会返回一个Json字符串

    Json这个对象在IE7及以下的浏览器中不支持,所以在这些浏览器调用时会报错

    eval()

    • 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回

    • 如果使用eval() 执行的字符串中含所有{},它会将{}当成代码块

    • 如果不希望将其当成代码块解析,则需要在字符串前后各加一个()

    尽量避免使用,性能比较差,具有安全隐患

    var str = '{"name":"孙悟空","age":18,"gender":"男"}';
    var obj = eval('('+str+')');
    

    如果需要兼容IE7及以下的JSON操作,则可以通过引入一个外部的js文件来处理

    //  json2.js
    //  2016-05-01
    //  Public Domain.
    //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
    //  See http://www.JSON.org/js.html
    //  This code should be minified before deployment.
    //  See http://javascript.crockford.com/jsmin.html
    
    //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    //  NOT CONTROL.
    
    //  This file creates a global JSON object containing two methods: stringify
    //  and parse. This file is provides the ES5 JSON capability to ES3 systems.
    //  If a project might run on IE8 or earlier, then this file should be included.
    //  This file does nothing on ES5 systems.
    
    //      JSON.stringify(value, replacer, space)
    //          value       any JavaScript value, usually an object or array.
    //          replacer    an optional parameter that determines how object
    //                      values are stringified for objects. It can be a
    //                      function or an array of strings.
    //          space       an optional parameter that specifies the indentation
    //                      of nested structures. If it is omitted, the text will
    //                      be packed without extra whitespace. If it is a number,
    //                      it will specify the number of spaces to indent at each
    //                      level. If it is a string (such as "\t" or " "),
    //                      it contains the characters used to indent at each level.
    //          This method produces a JSON text from a JavaScript value.
    //          When an object value is found, if the object contains a toJSON
    //          method, its toJSON method will be called and the result will be
    //          stringified. A toJSON method does not serialize: it returns the
    //          value represented by the name/value pair that should be serialized,
    //          or undefined if nothing should be serialized. The toJSON method
    //          will be passed the key associated with the value, and this will be
    //          bound to the value.
    
    //          For example, this would serialize Dates as ISO strings.
    
    //              Date.prototype.toJSON = function (key) {
    //                  function f(n) {
    //                      // Format integers to have at least two digits.
    //                      return (n < 10)
    //                          ? "0" + n
    //                          : n;
    //                  }
    //                  return this.getUTCFullYear()   + "-" +
    //                       f(this.getUTCMonth() + 1) + "-" +
    //                       f(this.getUTCDate())      + "T" +
    //                       f(this.getUTCHours())     + ":" +
    //                       f(this.getUTCMinutes())   + ":" +
    //                       f(this.getUTCSeconds())   + "Z";
    //              };
    
    //          You can provide an optional replacer method. It will be passed the
    //          key and value of each member, with this bound to the containing
    //          object. The value that is returned from your method will be
    //          serialized. If your method returns undefined, then the member will
    //          be excluded from the serialization.
    
    //          If the replacer parameter is an array of strings, then it will be
    //          used to select the members to be serialized. It filters the results
    //          such that only members with keys listed in the replacer array are
    //          stringified.
    
    //          Values that do not have JSON representations, such as undefined or
    //          functions, will not be serialized. Such values in objects will be
    //          dropped; in arrays they will be replaced with null. You can use
    //          a replacer function to replace those with JSON values.
    
    //          JSON.stringify(undefined) returns undefined.
    
    //          The optional space parameter produces a stringification of the
    //          value that is filled with line breaks and indentation to make it
    //          easier to read.
    
    //          If the space parameter is a non-empty string, then that string will
    //          be used for indentation. If the space parameter is a number, then
    //          the indentation will be that many spaces.
    
    //          Example:
    
    //          text = JSON.stringify(["e", {pluribus: "unum"}]);
    //          // text is '["e",{"pluribus":"unum"}]'
    
    //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
    //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
    
    //          text = JSON.stringify([new Date()], function (key, value) {
    //              return this[key] instanceof Date
    //                  ? "Date(" + this[key] + ")"
    //                  : value;
    //          });
    //          // text is '["Date(---current time---)"]'
    
    //      JSON.parse(text, reviver)
    //          This method parses a JSON text to produce an object or array.
    //          It can throw a SyntaxError exception.
    
    //          The optional reviver parameter is a function that can filter and
    //          transform the results. It receives each of the keys and values,
    //          and its return value is used instead of the original value.
    //          If it returns what it received, then the structure is not modified.
    //          If it returns undefined then the member is deleted.
    
    //          Example:
    
    //          // Parse the text. Values that look like ISO date strings will
    //          // be converted to Date objects.
    
    //          myData = JSON.parse(text, function (key, value) {
    //              var a;
    //              if (typeof value === "string") {
    //                  a =
    //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
    //                  if (a) {
    //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
    //                          +a[5], +a[6]));
    //                  }
    //              }
    //              return value;
    //          });
    
    //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
    //              var d;
    //              if (typeof value === "string" &&
    //                      value.slice(0, 5) === "Date(" &&
    //                      value.slice(-1) === ")") {
    //                  d = new Date(value.slice(5, -1));
    //                  if (d) {
    //                      return d;
    //                  }
    //              }
    //              return value;
    //          });
    
    //  This is a reference implementation. You are free to copy, modify, or
    //  redistribute.
    
    /*jslint
        eval, for, this
    */
    
    /*property
        JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
        getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
        lastIndex, length, parse, prototype, push, replace, slice, stringify,
        test, toJSON, toString, valueOf
    */
    
    
    // Create a JSON object only if one does not already exist. We create the
    // methods in a closure to avoid creating global variables.
    
    if (typeof JSON !== "object") {
        JSON = {};
    }
    
    (function () {
        "use strict";
    
        var rx_one = /^[\],:{}\s]*$/;
        var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
        var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
        var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
        var rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
    
        function f(n) {
            // Format integers to have at least two digits.
            return n < 10
                ? "0" + n
                : n;
        }
    
        function this_value() {
            return this.valueOf();
        }
    
        if (typeof Date.prototype.toJSON !== "function") {
    
            Date.prototype.toJSON = function () {
    
                return isFinite(this.valueOf())
                    ? this.getUTCFullYear() + "-" +
                            f(this.getUTCMonth() + 1) + "-" +
                            f(this.getUTCDate()) + "T" +
                            f(this.getUTCHours()) + ":" +
                            f(this.getUTCMinutes()) + ":" +
                            f(this.getUTCSeconds()) + "Z"
                    : null;
            };
    
            Boolean.prototype.toJSON = this_value;
            Number.prototype.toJSON = this_value;
            String.prototype.toJSON = this_value;
        }
    
        var gap;
        var indent;
        var meta;
        var rep;
    
    
        function quote(string) {
    
    // If the string contains no control characters, no quote characters, and no
    // backslash characters, then we can safely slap some quotes around it.
    // Otherwise we must also replace the offending characters with safe escape
    // sequences.
    
            rx_escapable.lastIndex = 0;
            return rx_escapable.test(string)
                ? "\"" + string.replace(rx_escapable, function (a) {
                    var c = meta[a];
                    return typeof c === "string"
                        ? c
                        : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
                }) + "\""
                : "\"" + string + "\"";
        }
    
    
        function str(key, holder) {
    
    // Produce a string from holder[key].
    
            var i;          // The loop counter.
            var k;          // The member key.
            var v;          // The member value.
            var length;
            var mind = gap;
            var partial;
            var value = holder[key];
    
    // If the value has a toJSON method, call it to obtain a replacement value.
    
            if (value && typeof value === "object" &&
                    typeof value.toJSON === "function") {
                value = value.toJSON(key);
            }
    
    // If we were called with a replacer function, then call the replacer to
    // obtain a replacement value.
    
            if (typeof rep === "function") {
                value = rep.call(holder, key, value);
            }
    
    // What happens next depends on the value's type.
    
            switch (typeof value) {
            case "string":
                return quote(value);
    
            case "number":
    
    // JSON numbers must be finite. Encode non-finite numbers as null.
    
                return isFinite(value)
                    ? String(value)
                    : "null";
    
            case "boolean":
            case "null":
    
    // If the value is a boolean or null, convert it to a string. Note:
    // typeof null does not produce "null". The case is included here in
    // the remote chance that this gets fixed someday.
    
                return String(value);
    
    // If the type is "object", we might be dealing with an object or an array or
    // null.
    
            case "object":
    
    // Due to a specification blunder in ECMAScript, typeof null is "object",
    // so watch out for that case.
    
                if (!value) {
                    return "null";
                }
    
    // Make an array to hold the partial results of stringifying this object value.
    
                gap += indent;
                partial = [];
    
    // Is the value an array?
    
                if (Object.prototype.toString.apply(value) === "[object Array]") {
    
    // The value is an array. Stringify every element. Use null as a placeholder
    // for non-JSON values.
    
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || "null";
                    }
    
    // Join all of the elements together, separated with commas, and wrap them in
    // brackets.
    
                    v = partial.length === 0
                        ? "[]"
                        : gap
                            ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
                            : "[" + partial.join(",") + "]";
                    gap = mind;
                    return v;
                }
    
    // If the replacer is an array, use it to select the members to be stringified.
    
                if (rep && typeof rep === "object") {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        if (typeof rep[i] === "string") {
                            k = rep[i];
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (
                                    gap
                                        ? ": "
                                        : ":"
                                ) + v);
                            }
                        }
                    }
                } else {
    
    // Otherwise, iterate through all of the keys in the object.
    
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (
                                    gap
                                        ? ": "
                                        : ":"
                                ) + v);
                            }
                        }
                    }
                }
    
    // Join all of the member texts together, separated with commas,
    // and wrap them in braces.
    
                v = partial.length === 0
                    ? "{}"
                    : gap
                        ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
                        : "{" + partial.join(",") + "}";
                gap = mind;
                return v;
            }
        }
    
    // If the JSON object does not yet have a stringify method, give it one.
    
        if (typeof JSON.stringify !== "function") {
            meta = {    // table of character substitutions
                "\b": "\\b",
                "\t": "\\t",
                "\n": "\\n",
                "\f": "\\f",
                "\r": "\\r",
                "\"": "\\\"",
                "\\": "\\\\"
            };
            JSON.stringify = function (value, replacer, space) {
    
    // The stringify method takes a value and an optional replacer, and an optional
    // space parameter, and returns a JSON text. The replacer can be a function
    // that can replace values, or an array of strings that will select the keys.
    // A default replacer method can be provided. Use of the space parameter can
    // produce text that is more easily readable.
    
                var i;
                gap = "";
                indent = "";
    
    // If the space parameter is a number, make an indent string containing that
    // many spaces.
    
                if (typeof space === "number") {
                    for (i = 0; i < space; i += 1) {
                        indent += " ";
                    }
    
    // If the space parameter is a string, it will be used as the indent string.
    
                } else if (typeof space === "string") {
                    indent = space;
                }
    
    // If there is a replacer, it must be a function or an array.
    // Otherwise, throw an error.
    
                rep = replacer;
                if (replacer && typeof replacer !== "function" &&
                        (typeof replacer !== "object" ||
                        typeof replacer.length !== "number")) {
                    throw new Error("JSON.stringify");
                }
    
    // Make a fake root object containing our value under the key of "".
    // Return the result of stringifying the value.
    
                return str("", {"": value});
            };
        }
    
    
    // If the JSON object does not yet have a parse method, give it one.
    
        if (typeof JSON.parse !== "function") {
            JSON.parse = function (text, reviver) {
    
    // The parse method takes a text and an optional reviver function, and returns
    // a JavaScript value if the text is a valid JSON text.
    
                var j;
    
                function walk(holder, key) {
    
    // The walk method is used to recursively walk the resulting structure so
    // that modifications can be made.
    
                    var k;
                    var v;
                    var value = holder[key];
                    if (value && typeof value === "object") {
                        for (k in value) {
                            if (Object.prototype.hasOwnProperty.call(value, k)) {
                                v = walk(value, k);
                                if (v !== undefined) {
                                    value[k] = v;
                                } else {
                                    delete value[k];
                                }
                            }
                        }
                    }
                    return reviver.call(holder, key, value);
                }
    
    
    // Parsing happens in four stages. In the first stage, we replace certain
    // Unicode characters with escape sequences. JavaScript handles many characters
    // incorrectly, either silently deleting them, or treating them as line endings.
    
                text = String(text);
                rx_dangerous.lastIndex = 0;
                if (rx_dangerous.test(text)) {
                    text = text.replace(rx_dangerous, function (a) {
                        return "\\u" +
                                ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
                    });
                }
    
    // In the second stage, we run the text against regular expressions that look
    // for non-JSON patterns. We are especially concerned with "()" and "new"
    // because they can cause invocation, and "=" because it can cause mutation.
    // But just to be safe, we want to reject all unexpected forms.
    
    // We split the second stage into 4 regexp operations in order to work around
    // crippling inefficiencies in IE's and Safari's regexp engines. First we
    // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
    // replace all simple value tokens with "]" characters. Third, we delete all
    // open brackets that follow a colon or comma or that begin the text. Finally,
    // we look to see that the remaining characters are only whitespace or "]" or
    // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
    
                if (
                    rx_one.test(
                        text
                            .replace(rx_two, "@")
                            .replace(rx_three, "]")
                            .replace(rx_four, "")
                    )
                ) {
    
    // In the third stage we use the eval function to compile the text into a
    // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
    // in JavaScript: it can begin a block or an object literal. We wrap the text
    // in parens to eliminate the ambiguity.
    
                    j = eval("(" + text + ")");
    
    // In the optional fourth stage, we recursively walk the new structure, passing
    // each name/value pair to a reviver function for possible transformation.
    
                    return (typeof reviver === "function")
                        ? walk({"": j}, "")
                        : j;
                }
    
    // If the text is not JSON parseable, then a SyntaxError is thrown.
    
                throw new SyntaxError("JSON.parse");
            };
        }
    }());
    
    

    你可能感兴趣的:(JS,javascript)