js
js基础
一、 js代码编写的位置
- 参考文档 w3school
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--位置4:可以将js代码编写在外部js文件中,然后通过script标签引入
推荐使用这种方法。script标签一旦用于引用外部文件,其标签内部就不能在写代码,即使编写了也不会被
执行
-->
<script type="text/javascript" src="js/js文件.js"></script>
<!--位置1:head中的script标签中-->
<script type="text/javascript">
window.onload = function(){
alert("test");
}
</script>
</head>
<body>
<!--位置2:标签onclick属性中-->
<button onclick="alert('哈哈哈')">点我有惊喜</button>
<!--位置3:超链接href属性中-->
<a href="javascript:alert('hahaha')">点我</a>
</body>
</html>
- 为什么使用 window.onload?
window.onload() 方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。
因为 JavaScript 中的函数方法需要在 HTML 文档渲染完成后才可以使用,如果没有渲染完成,此时的 DOM 树是不完整的,这样在调用一些 JavaScript 代码时就可能报出"undefined"错误;由于代码是自上向下执行,如果不用window.onload(),js代码会在body中的代码执行之前执行,从而报错。
二、js的基本语法
1、js中严格区分大小写;
2、标识符
只能包括数字、字母、下划线( _ )或美元符号( $ )
3、数据类型
– 字符串型(String)单双引号皆可
– 数值型(Number)
– 布尔型(Boolean)
– null型(Null) 表示一个为空的对象,声明且赋值为null
– undefined型(Undefined)声明但未赋值
这5种之外的类型都称为Object,所以总的来看JavaScript中共有六种数据类型。
1、js中数字最大值var max = Number.MAX_VALUE;
大于0的最小值var min = Number.MIN_VALUE;
2、Infinity表示正无穷-,Infinity表示负无穷,它是Number类型的;
3、NaN是一个特殊的数字,使用typeof NaN返回Number;
4、如果js进行浮点运算,可能会得到一个不精确的结果。因为计算机会将浮点数先转换成二进制,然后再进行计算,但是不是所有的十进制小数都可以转换成二进制的。
例如var c = 0.1 + 0.2;
得到的结果为0.30000000000000004
5、NaN,即非数值(Not a Number)是一个特殊的数值,JS中
当对数值进行计算时没有结果返回,则返回NaN。
6、定义一个变量时都要用var
4、转义字符:‘\’
5、强制类型转换
转换为String
- 方式一(强制类型转换):
- 调用被转换数据的toString()方法
- 例子:
var a = 123;
a = a.toString();
- 注意:这个方法不适用于null和undefined
由于这两个类型的数据中没有方法,所以调用toString()时会报错
- 方式二(强制类型转换):
- 调用String()函数
- 例子:
var a = 123;
a = String(a);
- 原理:对于Number Boolean String都会调用他们的toString()方法来将其转换为字符串,
对于null值,直接转换为字符串"null"。对于undefined直接转换为字符串"undefined"
- 方式三(隐式的类型转换): *****
- 为任意的数据类型 +""
- 例子:
var a = true;
a = a + "";
- 原理:和String()函数一样
转换为Number
- 方式一(强制类型转换):
- 调用Number()函数
- 例子:
var s = “123”;
s = Number(s);
- 转换的情况:
1.字符串 --> 数字 (转换之后类型都是Number)
- 如果字符串是一个合法的数字,则直接转换为对应的数字
- 如果字符串是一个非法的数字,则转换为NaN
- 如果是一个空串或纯空格的字符串,则转换为0
2.布尔值 --> 数字
- true转换为1
- false转换为0
3.空值 --> 数字
- null转换为0
4.未定义 --> 数字
- undefined 转换为NaN
方式二(强制类型转换):
- 调用parseInt()或parseFloat()
- 这两个函数专门用来将一个字符串转换为数字的
- 对于非string类型的值,会先将其转换成string,然后在进行parseInt()操作
- parseInt()
- 可以将一个字符串中的有效的整数位提取出来,并转换为Number
- 例子:
var a = “123.456px”;
a = parseInt(a); //123
- 如果需要可以在parseInt()中指定一个第二个参数,来指定当前需要转换的数的进制,一般可用于字符串的转换,因为有的浏览器解析时进制有所不用。
- parseFloat()
- 可以将一个字符串中的有效的小数位提取出来,并转换为Number
- 例子:
var a = “123.456px”;
a = parseFloat(a); //123.456
- 方式三(隐式的类型转换):
- 任何值做 减乘除运算时,都会先转换成Number类型,所以可以通过-0,/1,*1来转为Number;
- 例子:
var a = “123”;
a = +a; // 在变量前加一个+,会转为Number类型
- 原理:和Number()函数一样
-
转换为布尔值
- 方式一(强制类型转换):
- 使用Boolean()函数
- 例子:
var s = “false”;
s = Boolean(s); //true
- 转换的情况
字符串 --> 布尔
- 除了空串其余全是true
数值 --> 布尔
- 除了0和NaN其余的全是true
null、undefined —> 布尔
- 都是false
对象 —> 布尔
- 都是true
- 方式二(隐式类型转换):
- 为任意的数据类型做两次非运算,即可将其转换为布尔值
- 例子:
var a = “hello”;
a = !!a; //true
6、其余进制的数字
十六进制:0x
八进制:0
二进制:0b
7、运算符
1、var result = typeof 变量:返回值是string;
2、算术运算符
- 除了加法以外,对非Number类型的值进行运算时,都会先转换为Number然后在做运算。
- 任何值和NaN做运算都得NaN。
- 而做加法运算时,如果是两个字符串进行相加,则会做拼串操作,将两个字符连接为一个字符串。
- 任何值和字符串做加法,都会先转换为字符串,然后再拼串
- 除法运算与java中不同,会保留小数部分。
-
3、一元运算符
- 一元运算符只需要一个操作数
- 一元的+
- 就是正号,不会对值产生任何影响,但是可以将一个非数字转换为数字
- 例子:
var a = true;
a = +a;
- 一元的-
- 就是负号,可以对一个数字进行符号位取反
- 例子:
var a = 10;
a = -a;
4、逻辑运算符
&&
- &&可以对符号两侧的值进行与运算
- 只有两端的值都为true时,才会返回true。只要有一个false就会返回false。
- 与是一个短路的与,如果第一个值是false,则不再检查第二个值
- 对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值
- 规则:跟短路操作一样,返回最后检查的那个值
1.如果第一个值为false,则返回第一个值
2.如果第一个值为true,则返回第二个值
||
- ||可以对符号两侧的值进行或运算
- 只有两端都是false时,才会返回false。只要有一个true,就会返回true。
- 或是一个短路的或,如果第一个值是true,则不再检查第二个值
- 对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值
- 规则: 与上边同理
1.如果第一个值为true,则返回第一个值
2.如果第一个值为false,则返回第二个值
5、关系运算符
- 如果比较的两个值是非数值,会将其转换为Number然后再比较。
` console.log(1 > true);//false
console.log(1 >= true);//true`
- 任何值和NaN比较都是false;
- 如果比较的两个值都是字符串,此时会按位比较字符串的Unicode编码,而不会转换为Number。
- 如果比较的是两个字符串型的数值,可能得不到预期的结果,此时一定要将字符串转型
console.log("122333" < +"5"); 加一个+号将string转成Number
6、相等运算符
===
- 全等,判断左右两个值是否全等,它和相等类似,只不过它不会进行自动的类型转换,
如果两个值的类型不同,则直接返回false
!==
- 不全等,和不等类似,但是它不会进行自动的类型转换,如果两个值的类型不同,它会直接返回true
特殊的值:
-
null和undefined
- 由于undefined衍生自null,所以null == undefined 会返回true。
但是 null === undefined 会返回false。 -
NaN
NaN不与任何值相等,包括它自身 NaN == NaN //false -
判断一个值是否是NaN
- 使用isNaN()函数
8、运算符优先级
优先级不需要记忆,如果不确定,使用()来改变优先级。
9、计时器
注意:在浏览器的后台才能看到时间
开启计时器
console.time("计时器名字");
结束计时
console.timeEnd("计时器名字");
10、用户输入
var str = prompt("please input:");
console.log(str);
三、对象
1、定义
对象是一种复合数据类型,在对象中可以保存多个不同数据类型的属性,对象的作用是统一管理多个数据。
对象是由属性和方法组成,其中方法是一种特殊的属性,其属性值是函数。
var obj = {
name:'张三',
age:12,
setName:function(name){
this.name=name
},
setAge:function(age){
this.age=age
}
}
2、 创建对象
- 方式一:
var obj = new Object();
- 方式二:
var obj= {
name:"李四",
age:22,
gender:"男"
};
==注意:最后一个属性后边不用加逗号。==
3、属性
-
读取对象中的属性
- 语法:(怎么存就怎么取)
对象.属性名
对象[“属性名”]
使用[ ]操作属性更加灵活, 可以传递一个变量;属性名中可以存在特殊字符
- 如果读取一个对象中没有的属性,它不会报错,而是返回一个undefined -
删除对象中的属性
- 语法:
delete 对象.属性名
delete 对象[“属性名”] -
使用in检查对象中是否含有指定属性
- 语法:“属性名” in 对象
- 如果在对象中含有该属性,则返回true
如果没有则返回false
4、枚举对象中的属性
var person = {
name:"张三",
age:12,
gender:"男"
};
for(var n in person){
console.log(n + " = " + person[n]);
}
四、函数
- 可以在函数内部定义其他函数,与java不同;
1、创建函数
-
形参只写变量名即可
函数声明 function 函数名([形参1,形参2...形参N]){ 语句... } - 函数表达式(将一个匿名函数赋值给一个变量) var 函数名 = function([形参1,形参2...形参N]){ 语句... };
2、实参
-
实参:实际参数
- 调用函数时,可以在()传递实参,传递的实参会赋值给对应的形参,
调用函数时JS解析器不会检查实参的类型和个数,可以传递任意数据类型的值。
如果实参的数量大于形参,多余实参将不会赋值,
如果实参的数量小于形参,则没有对应实参的形参将会赋值undefined
实参也可以是函数,对象
如果一个函数需要传入的参数过多时,可以将参数封装到一个对象中,将对象当作实参进行传递。 -
函数作为实参
function fun3(a){
a();
}
fun3(function(){alert("hahah")});
3、返回值
- 返回值可以是任意数据类型,可以是对象,函数;
4、立即执行函数
匿名函数加一个括号
无参版
(function(){
alert("hahah");
})();
有参版
(function(a,b){
alert(a+b);
})(1,2);
5、方法
- 函数作为对象的属性值称为方法。
var person = {
name:"张三", // 属性
age:23, // 属性
test:function(a,b){
alert(a+b);
} // 方法
};
person.test(1,3);
6、this
- this是函数的上下文对象,根据函数的调用方式不同会执向不同的对象
1.以函数的形式调用时,this是window
2.以方法的形式调用时,this是调用方法的对象
3.以构造函数的形式调用时,this是新建的那个对象
4.使用call和apply调用时,this是指定的那个对象
5.在全局作用域中this代表window
6,在事件响应函数中,事件是给谁绑定的this就代表谁
7、call()和apply()
- 这两个方法都是函数对象的方法需要通过函数对象来调用
- 通过两个方法可以直接调用函数,并且可以通过第一个实参来指定函数中this
- 不同的是call是直接传递函数的实参而apply需要将实参封装到一个数组中传递
function fun(a,b){
console.log(a+b);
}
var obj = {};
fun.call(obj,1,2);
fun.apply(obj,[1,2]);
8、回调函数
-
什么是回调函数?
定义但未手动调用且最终执行了的函数。 -
类型
dom事件回调函数、定时器回调函数、ajax回调函数、生命周期回调函数。
9、IIFE(立即调用函数表达式)
- 作用:隐藏实现、不会污染外部命名空间、编写js模块;
五、作用域
1、全局作用域
- 直接在script标签中编写的代码都运行在全局作用域中
- 全局作用域在打开页面时创建,在页面关闭时销毁。
- 全局作用域中有一个全局对象window,window对象由浏览器提供,可以在页面中直接使用,它代表的是整个的浏览器的窗口。
- 在全局作用域中创建的变量都会作为window对象的属性保存
- 在全局作用域中创建的函数都会作为window对象的方法保存
- 在全局作用域中创建的变量和函数可以在页面的任意位置访问。
- 在函数作用域中也可以访问到全局作用域的变量。
- 尽量不要在全局中创建变量
2、声明提前
- 变量的声明提前
使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值),
但是如果声明变量时不适用var关键字,则变量不会被声明提前 - 函数的声明提前
使用函数声明形式创建的函数 function 函数(){}
它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
3、函数作用域
- 在函数中也会改变全局变量的值(非传参)
var a = 30;
function fun(){
a = 10;
}
fun();
console.log(a);//10
- 在函数中不设置var声明的变量都会变成全局变量
function fun(){
b = 10; 相当于window.b = 10;
}
fun();
console.log(b);//10
六、构造函数
1、定义
- 构造函数是专门用来创建对象的函数
- 一个构造函数我们也可以称为一个类
- 通过一个构造函数创建的对象,我们称该对象时这个构造函数的实例
- 通过同一个构造函数创建的对象,我们称为一类对象
- 构造函数的定义与普通的函数相同,不同之处在于:
1、调用方式不同,
如果直接调用,它就是一个普通函数
如果使用new来调用,则它就是一个构造函数
2、构造函数名首字母要大写
2、执行流程
- 创建一个新的对象;
- 将新建对象作为函数的上下文对象,在构造函数中可以通过this来引用当前对象;
- 执行构造函数中的代码;
- 返回新建的对象;
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
var person = new Person("张三",22,"男");
3、instanceof
用来检查一个对象是否是一个类的实例
- 语法:对象 instanceof 构造函数
- 如果该对象时构造函数的实例,则返回true,否则返回false
- Object是所有对象的祖先,所以任何对象和Object做instanceof都会返回true
4、原型对象
- 创建一个函数以后,解析器都会默认在函数中添加一个属性prototype
prototype属性指向的是一个对象,这个对象我们称为原型对象。- 当函数作为构造函数使用,它所创建的对象中都会有一个隐含的属性执行该原型对象。
这个隐含的属性可以通过对象.__proto__来访问。 - 原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。
我们可以将对象中共有的属性和方法统一添加到原型对象中,
这样我们只需要添加一次,就可以使所有的对象都可以使用。 - 当我们去访问对象的一个属性或调用对象的一个方法时,它会先自身中寻找,
如果在自身中找到了,则直接使用。
如果没有找到,则去原型对象中寻找,如果找到了则使用,
如果没有找到,则去原型的原型中寻找,依此类推。直到找到Object的原型为止,Object的原型的原型为null,如果依然没有找到则返回undefined
- 当函数作为构造函数使用,它所创建的对象中都会有一个隐含的属性执行该原型对象。
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
向原型对象中添加属性
Person.prototype.test = "123";
向原型对象中添加方法
Person.prototype.sayHello = function(){
console.log(this.name + "hahhah");
}
使用对象调用原型对象
var p = new Person(("张三",12,"男");
p.__proto__.test = "234";
console.log(p.test);//234
console.log(p.__proto__ == Person.prototype); //true
5、检测对象中是否有某个属性
”属性名“ in 对象
对象中或原型中有这个属性,都会返回true;对象.hasOwnProperty("属性名")
只有对象中有这个属性时,才会返回true;
七、数组
1、创建数组
-
var arr = new Array();
-
var arr = [];
-
向数组中添加元素
-
语法;
数组对象[索引] = 值;
arr[0] = 123;
arr[1] = “hello”; -
向数组的最后添加元素:数组[数组.length] = 值;
-
创建数组时直接添加元素
-
语法:
var arr = [元素1,元素2…元素N]; -
例子:
var arr = [123,“hello”,true,null];
2、数组中的方法
- push()
- 用来向数组的末尾添加一个或多个元素,并返回数组新的长度
- 语法:数组.push(元素1,元素2,元素N) - pop()
- 用来删除数组的最后一个元素,并返回被删除的元素 - unshift()
- 向数组的前边添加一个或多个元素,并返回数组的新的长度 - shift()
- 删除数组的前边的一个元素,并返回被删除的元素 - slice()
- 可以从一个数组中截取指定的元素
- 该方法不会影响原数组,而是将截取到的内容封装为一个新的数组并返回
- 参数:
1.截取开始位置的索引(包括开始位置)
2.截取结束位置的索引(不包括结束位置)
- 第二个参数可以省略不写,如果不写则一直截取到最后
- 参数可以传递一个负值,如果是负值,则从后往前数 - splice()
- 可以用来删除数组中指定元素,并使用新的元素替换
该方法会将删除的元素封装到新数组中返回
- 参数:
1.删除开始位置的索引
2.删除的个数
3.三个以后,都是替换的元素,这些元素将会插入到开始位置索引的前边
3、遍历数组
使用forEach()方法来遍历数组(不兼容IE8)
数组.forEach(function(value , index , obj){});
forEach()方法需要一个回调函数作为参数,数组中有几个元素,回调函数就会被调用几次,每次调用时,都会将遍历到的信息以实参的形式传递进来,我们可以定义形参来获取这些信息。
value:正在遍历的元素
index:正在遍历元素的索引
obj:被遍历对象
八、字符串
1、方法
slice()
- 可以从一个字符串中截取指定的内容,并将截取到内容返回,不会影响原变量
- 参数:
第一个:截取开始的位置(包括开始)
第二个:截取结束的位置(不包括结束)
- 可以省略第二个参数,如果省略则一直截取到最后
- 可以传负数,如果是负数则从后往前数
substring()
- 和slice()基本一致,不同的是它不能接受负值作为参数,如果设置一个负值,则会自动修正为0,substring()中如果第二个参数小于第一个,自动调整位置
九、正则表达式
1、创建正则表达式
- 创建正则表达式
- var reg = new RegExp(“正则”,“匹配模式”);(此种方式一般用于变量拼接,记得转义字符)
- var reg = /正则表达式/匹配模式
2、语法
- 语法:
匹配模式:
i:忽略大小写
g:全局匹配模式(匹配所有符合条件的元素) - 设置匹配模式时,可以都不设置,也可以设置1个,也可以全设置,设置时没有顺序要求
/[a-z]/ig
正则语法
| 或
[] 或
[^ ] 除了
[a-z] 小写字母
[A-Z] 大写字母
[A-z] 任意字母
[0-9] 任意数字
- {n} 连续出现n次
var reg = /(ab){3}/;
console.log(reg.test("abababa"));
- {a,b} 连续出现a~b次
- {a,}出现a次及以上
var reg = /a{1,3}/;
console.log(reg.test("aaa"));
- ‘+’ 至少一个,相当于 {1,}
var reg = /a+b/;
console.log(reg.test("aaab"));
- 星号 * 0个或多个,相当于{0,}
var reg = /a*b{2}/;
console.log(reg.test("aaaabb"));
- ? 0个或1个,相当于{0,1}
var reg = /ca?b/;
console.log(reg.test("cb"));
- 指定开头结尾字母
/^a/以a开头
/a$/ 以a结尾
var reg = /^a[a-z]*b$/;
console.log(reg.test("avvvb"));
- 点表示任意字符
/./表示任意字符
var reg = /./;
- 转义字符 \
/\./表示字符串中含.
- 构造函数中的参数是字符串,所以 /./ 要写成new RegExp("\\.");
- \w 表示任意字母数字下划线
- \W 表示非字母数字下划线
- \d 表示任意的数字 [0-9]
- \D 表示非数字 [^0-9]
- \s 表示空格
- \S表示非空格
- \b 单词边界
- \B 除了单词边界
reg = /\bchild\b/; 表示匹配一个独立的单词child
3、方法
- 方法:
test()
- 可以用来检查一个字符串是否符合正则表达式
- 如果符合返回true,否则返回false
4、例子
var reg = /[A-z]/;
console.log(reg.test("aaaa")) ;//true
检查字符串中是否含有abc或adc或aec
var reg = /a[bde]c/;
console.log(reg.test("aeec")); false
[^]除了。。。
var reg = /[^0-9]/ 除了数字都可以
console.log(reg.test(123)); false
console.log(reg.test(true)); true
创建一个正则表达式,检测手机号
var reg = /^1[3-9][0-9]{9}$/;
去除字符串前后的空格,实现trim()
var str = " adm in ";
str = str.replace(/^\s*|\s*$/g,"");
console.log(str); adm in
5、字符串和正则表达式相关的方法
1、split()
- 可以根据指定内容将一个字符串拆分为一个数组
- 参数:
- 需要一个字符串作为参数,将会根据字符串去拆分数组
可以接收一个正则表达式,此时会根据正则表达式去拆分数组,不论是否设置g,都是全局匹配模式。
var s = "1a2b3c4d5e6f7";
s = s.split(/[A-z]/);
console.log(s); // 1,2,3,4,5,6,7
2、match()
- 可以将字符串中和正则表达式匹配的内容提取出来
- 参数:
- 正则表达式,可以根据该正则表达式将字符串中符合要求的内容提取出来
并且封装到一个数组中返回
3、replace() - 可以将字符串中指定内容替换为新的内容
- 参数:
- 第一个:被替换的内容,可以是一个正则表达式
- 第二个:替换的新内容
将s中的所有字母都替换成@
var s = "1a2b3c4D5e6F7";
s = s.replace(/[a-z]/ig,"@");
console.log(s); // 1@2@3@4@5@6@7
4、search()
- 可以根据正则表达式去字符串中查找指定的内容
- 参数:
正则表达式,将会根据该表达式查询内容,并且将第一个匹配到的内容的索引返回,如果没有匹配到任何内容,则返回-1。不论是否设置g,都不是全局匹配模式。
十、DOM–Document Object Model
1、定义
- 文档对象模型,通过DOM可以来任意来修改网页中各个内容
- 文档
- 文档指的是网页,一个网页就是一个文档
- 对象
- 对象指将网页中的每一个节点都转换为对象
转换完对象以后,就可以以一种纯面向对象的形式来操作网页了
- 对象指将网页中的每一个节点都转换为对象
- 模型
- 模型用来表示节点和节点之间的关系,方便操作页面。
- 模型可以看作一个家谱,模型的目的是可以通过一个节点找到它的兄弟节点,父节点乃至模型中的每一个节点。
- 节点(Node)
- 节点是构成网页的最基本的单元,网页中的每一个部分都可以称为是一个节点
- 虽然都是节点,但是节点的类型却是不同的
- 常用的节点
- 文档节点 (Document),代表整个网页
- 元素节点(Element),代表网页中的标签
- 属性节点(Attribute),代表标签中的属性
- 文本节点(Text),代表网页中的文本内容
- 文档
2、DOM查询
- 在网页中浏览器已经为我们提供了document对象,它代表的是整个网页,它是window对象的属性,可以在页面中直接使用。
- document查询方法:
- 根据元素的id属性查询一个元素节点对象:
- document.getElementById(“id属性值”);
- 根据元素的name属性值查询一组元素节点对象:
- document.getElementsByName(“name属性值”);//返回一个数组
- 根据标签名来查询一组元素节点对象,即使只返回1个对象,也会封装到数组中返回:
- document.getElementsByTagName(“标签名”); - 通过具体的元素节点来查询
1、 元素.getElementsByTagName()
通过标签名查询当前元素的指定后代元素(document查询的是整个页面中的元素)
查询整个页面中的id是city的元素
var city = document.getElementById("city");
查询city元素内的li标签
var li = city.getElementsByTagName("li");
2、 元素.childNodes
获取当前元素的所有子节点 ,会获取到空白的文本子节点
3、元素.children
获取当前元素的所有子元素,不包括空白节点。
4、元素.firstChild
获取当前元素的第一个子节点,会获取到空白的文本子节点
元素.firstElementChild
获取当前元素的第一个子元素,不包括空白节点
5、元素.lastChild
获取当前元素的最后一个子节点,会获取到空白的文本子节点
元素.lastElementChild
获取当前元素的最后一个子元素,不包括空白节点
6、元素.parentNode
获取当前元素的父元素
7、元素.previousSibling
获取当前元素的前一个兄弟节点,会获取到空白的文本子节点
元素.previousElementSibling
获取当前元素的前一个兄弟元素,不包括空白节点
8、 元素.nextSibling
获取当前元素的后一个兄弟节点,会获取到空白的文本子节点
9、获取body
var body = document.body;
10、获取html根标签
var html = document.documentElement;
11、获取页面中的所有元素,相当于document.getElementsByTagName("*");
document.all
12、根据元素的class属性值查询一组元素节点对象(IE8及以下不支持)
document.getElementsByClassName();
13、document.querySelector()
根据CSS选择器去页面中查询一个元素
如果匹配到的元素有多个,则它会返回查询到的第一个元素
14、document.querySelectorAll()
根据CSS选择器去页面中查询一组元素
会将匹配到所有元素封装到一个数组中返回,即使只匹配到一个
15、读取标签内部的文本内容
<h1>h1中的文本内容</h1>
元素.firstChild.nodeValue;这里的元素指的是h1节点,firstChild指的是其中的文本节点
3、事件
- 事件(Event)
- 事件指的是用户和浏览器之间的交互行为。比如:点击按钮、关闭窗口、鼠标移动。。。 - 我们可以为事件来绑定回调函数来响应事件。
- 绑定事件的方式:
1.可以在标签的事件属性中设置相应的JS代码
<button onclick="js代码。。。">按钮</button>
2.可以通过为对象的指定事件属性设置回调函数的形式来处理事件
<button id="btn">按钮</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
};
</script>
4、文档的加载
- 浏览器在加载一个页面时,是按照自上向下的顺序加载的,加载一行执行一行。
- 如果将js代码编写到页面的上边,当代码执行时,页面中的DOM对象还没有加载,此时将会无法正常获取到DOM对象,导致DOM操作失败。
- 解决方式一:
- 可以将js代码编写到body的下边
<body>
<button id="btn">按钮</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
};
</script>
</body>
- 解决方式二:
- 将js代码编写到window.onload = function(){}中
- window.onload 对应的回调函数会在整个页面加载完毕以后才执行,
所以可以确保代码执行时,DOM对象已经加载完毕了
<script>
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
};
};
</script>
5、元素的属性
-
读取元素的属性:
语法:元素.属性名
例子:ele.name
ele.id
ele.value
ele.className(class属性必须用className获取) -
修改元素的属性:
语法:元素.属性名 = 属性值 -
innerHTML
- 使用该属性可以获取或设置元素内部的HTML代码
6、图片切换练习
- 将图片src都存入数组中,利用下标来实现切换
- 总体思路:先获取对象,再操作对象的属性,内容。
7、innerText和innerHTML的区别
- 这两个属性并没有在DOM标准定义,但是大部分浏览器都支持这两个属性;
- 两个属性作用类似,都可以获取到标签内部的内容,不同是innerHTML会获取到html标签,而innerText会自动去除标签;
- 如果使用这两个属性来设置标签内部的内容时,没有任何区别的 ;
8、DOM增删改
- 可以根据标签名创建一个元素节点对象
document.createElement()
- 可以根据文本内容创建一个文本节点对象,一般不创建文本对象,直接设置标签的innerHtml属性,更加简便
document.createTextNode()
方法一:较复杂
var li = document.createElement("li");
var text = document.createTextNode("广州");
li.appendChild(text);
city.appendChild(li);
方法二:更简便
var li = document.createElement("li");
//此处直接设置li标签内部的文本内容
li.innerHTML = "广州";
city.appendChild(li);
- 向父节点中添加指定的子节点
父节点.appendChild(子节点)
- 将一个新的节点插入到旧节点的前边
父节点.insertBefore(新节点,旧节点)
- 使用一个新的节点去替换旧节点
父节点.replaceChild(新节点,旧节点)
- 删除指定的子节点
父节点.removeChild(子节点)
推荐方式:子节点.parentNode.removeChild(子节点)
9、补充:子元素和子节点
- 子元素指的是标签,而不包括普通的文本和空白;
- 子节点包括元素,文本和空白;
此时的输出是null,因为firstElementChild查询的是第一个子元素,元素节点的nodeValue是null
window.onload = function(){
var h1 = document.getElementById("234");
var p = h1.firstElementChild.nodeValue;
console.log(p);
}
<body>
<h1 id="234"><p>aaaa</p></h1>
</body>
此时编译出错,因为h1中不存在子元素节点,只有test文本节点,故h1.firstElementChild是null;
window.onload = function(){
var h1 = document.getElementById("234");
var p = h1.firstElementChild.nodeValue;
console.log(p);
}
<body>
<h1 id="234">test</h1>
</body>
10、添加删除记录练习
- 新添加的记录要重新添加单击事件;
- 注意获取的是一个对象还是一组对象;
- 给元素绑定单击事件时,在函数中要注意使用this来代替当前元素;
a[i].onclick = function(){
var tr = this.parentNode.parentNode;
var name = tr.firstElementChild.innerHTML;
if(confirm("确定要删除" + name + "吗?")){
tr.parentNode.removeChild(tr);
}
- for循环中的单击事件:for循环在页面加载完成之后立即执行,而响应函数在发生单击事件时才执行,那时候i的值已经是数组的长度了,所以在单击函数中用this而不能使用数组索引;
11、DOM操作内联样式
- 读取内联样式: 只有此种方式才能修改样式
语法:元素.style.样式名
- 例子:
元素.style.width
元素.style.height
- 注意:如果样式名中带有-,则需要将样式名修改为驼峰命名法将-去掉,然后-后的字母改大写
- 比如:background-color --> backgroundColor
border-width —> borderWidth
- 修改内联样式:
语法:元素.style.样式名 = 样式值
(带px的)
- 通过style修改和读取的样式都是内联样式,由于内联样式的优先级比较高,所以我们通过JS来修改的样式,往往会立即生效,但是如果样式中设置了!important,则内联样式将不会生效。background-color:yellow !important;
12、DOM操作当前样式
- IE8
语法:元素对象.currentChild.样式名;
通过该方法读取到样式都是只读的不能修改
- 正常浏览器
- 使用getComputedStyle()
- 这个方法是window对象的方法,可以返回一个对象,这个对象中保存着当前元素生效样式
- 参数:
1.要获取样式的元素对象
2.可以传递一个伪元素,一般传null
- 例子:
获取元素的宽度getComputedStyle(box , null)["width"];
- 通过该方法读取到样式都是只读的不能修改
var obj = getComputedStyle(元素对象,null);
obj.样式名;//返回值是有px的,一般用parseInt()来获取数值
- 处理兼容性问题通用做法
传入元素对象和样式,返回样式值,适用于一切浏览器
function getStyle(obj,name){
判断某个对象是否存在,如果存在调用此对象,不存在则调用另一种;
return window.getComputedStyle ? getComputedStyle(obj,null)[name] :
obj.currentStyle[name];
}
13、其他的样式相关的属性
注意:以下样式都是只读的,且是元素对象的属性,直接使用对象调用
clientHeight
- 元素的可见高度,指元素的内容区和内边距的高度
clientWidth
- 元素的可见宽度,指元素的内容区和内边距的宽度
offsetHeight
- 整个元素的高度,包括内容区、内边距、边框
offfsetWidth
- 整个元素的宽度,包括内容区、内边距、边框
offsetParent
- 当前元素的定位父元素(定位祖先元素是指position属性不是static的元素)
- 离他最近的开启了定位的祖先元素,如果所有的元素都没有开启定位,则返回body
offsetLeft
offsetTop
- 当前元素和定位父元素之间的偏移量
- offsetLeft水平偏移量 offsetTop垂直偏移量
scrollHeight
scrollWidth
- 父元素的属性
- 当子元素的高度或者宽度大于父元素时,在父元素的css样式中设置overflow:auto;然后使用scrollHeight、scrollWidth获取元素滚动区域的高度和宽度(即子元素的真实高度和宽度)
scrollTop
scrollLeft
- 父元素的属性
- 获取父元素垂直和水平滚动条滚动的距离
判断滚动条是否滚动到底(部分浏览器不适用)
垂直滚动条scrollHeight - scrollTop = clientHeight
水平滚动scrollWidth - scrollLeft = clientWidth
十一、事件
1、事件对象
- 当响应函数被调用时,浏览器每次都会将一个事件对象作为实参传递进响应函数中,这个事件对象中封装了当前事件的相关信息,比如:鼠标的坐标,键盘的按键,鼠标的按键,滚轮的方向。。
- 可以在响应函数中定义一个形参,来使用事件对象,但是在IE8以下浏览器中事件对象没有做完实参传递,而是作为window对象的属性保存
例子:
元素.事件 = function(event){
//解决事件对象的兼容问题
event = event || window.event;
//通过事件对象获取鼠标x、y轴坐标
var x = event.clientX;
var y = event.clientY;
};
2、练习–div随鼠标移动
- 将onmousemove事件绑定到document上而不是div,因为绑定到div上则鼠标只能在div中移动,导致div只能向右下方移动。
- event.clientX 返回的是一个数值,如果要给其他属性赋值,一定要 + “px”;
- 修改元素的样式只能通过
元素.style.样式名 = 值;
,修改 top、bottom、left 和 right 之前一定要设置position属性; - clientX和clientY 用于获取鼠标在当前的可见窗口的坐标;
- pageX和pageY可以获取鼠标相对于当前页面的坐标,但是这个两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用,使用clientX和clientY分别加上滚动条滚动的距离
window.onload = function(){
/*
* 使div可以跟随鼠标移动
*/
//获取box1
var box1 = document.getElementById("box1");
//绑定鼠标移动事件
document.onmousemove = function(event){
//解决兼容问题
event = event || window.event;
//获取滚动条滚动的距离
/*
* chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取
* 火狐等浏览器认为浏览器的滚动条是html的,
*/
var st = document.body.scrollTop || document.documentElement.scrollTop;
var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
//var st = document.documentElement.scrollTop;
//获取到鼠标的坐标
/*
* clientX和clientY
* 用于获取鼠标在当前的可见窗口的坐标
* div的偏移量,是相对于整个页面的
*
* pageX和pageY可以获取鼠标相对于当前页面的坐标
* 但是这个两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用
*/
var left = event.clientX;
var top = event.clientY;
//设置div的偏移量
box1.style.left = left + sl + "px";
box1.style.top = top + st + "px";
};
};
3、 事件的冒泡(Bubble)
- 事件的冒泡指的是事件向上传导,当后代元素上的事件被触发时,将会导致其祖先元素上的同类事件也会触发。
- 事件的冒泡大部分情况下都是有益的,如果需要取消冒泡,则需要使用事件对象来取消,可以将事件对象的cancelBubble设置为true,即可取消冒泡
元素.事件 = function(event){
event = event || window.event;
event.cancelBubble = true;//取消冒泡
};
4、事件的委派
- 委派是利用事件冒泡的特性,减少了事件绑定的次数,从而提高了效率;
- 如何做:将多个节点的事件绑定到共同祖先节点上,触发某一个节点事件时,会一直冒泡到共同的祖父节点,然后通过祖父节点的响应函数来处理事件;
- 注意事项:因为祖先节点中不仅有我们希望触发事件的节点,所有要通过事件对象event的target属性来进行筛选;
event.target
是触发事件的对象;
如果触发事件的对象是我们期望的元素则执行,否则不执行
if(event.target.className == "link"){
alert("我是ul的单击响应函数");
}
--------------------------------------------------------------------------
<ul id="ul" style="background-color:greenyellow;">
<li><a href="javascript:;" class="link">链接1</a></li>
<li><a href="javascript:;" class="link">链接2</a></li>
<li><a href="javascript:;" class="link">链接3</a></li>
</ul>
5、事件的绑定
方法一:仅适用于一个对象的一个事件绑定一个响应函数,如果要绑定多个响应函数,则前面的都会被覆盖,只有最后一个会执行;
obj.onclick = function(){
alert(this); this即obj
}
方法二:适用于一个对象的一个事件绑定多个响应函数
除IE8以外,其余浏览器可以使用
- 对象.addEventListener()
- 参数:
* 1.事件的字符串,不要on
* 2.回调函数,当事件触发时该函数会被调用
* 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
obj.addEventListener("click",function(){
alert(this); this即obj
},false);
IE8浏览器
- 对象.attachEvent()
- 参数:
* 1.事件的字符串,有on
* 2.回调函数
*
这个方法也可以同时为一个事件绑定多个处理函数,不同的是它是后绑定先执行,执行顺序和addEventListener()相反
obj.attachEvent("onclick",function(){
alert(this); 注意这里this是window
});
将两者结合起来,构造一个新的通用函数:
addEventListener()中的this,是绑定事件的对象;attachEvent()中的this,是window 。需要统一两个方法中的this
此处通过匿名函数将callback函数的调用权掌握在我们手中,让callback函数调用call方法指定回调函数中的this为绑定事件的对象。
如果直接将callback传递进去,则在attachEvent内部是通过window来调用的,而我们手动指定callback的调用函数后,在attachEvent中window调用的是匿名函数
参数:
* obj 要绑定事件的对象
* e 事件的字符串(不要on)
* callback 回调函数
function addEvent(obj,e,callback){
if(obj.addEventListener){
obj.addEventListener(e,callback,false);
}else{
div1.attachEvent("on" + e,function(){
callback.call(obj);
});
}
}
6、练习–拖拽
<script type="text/javascript">
此处注意别忘了
window.onload = function(){
//1、获取div1对象
var div1 = document.getElementById("div1");
//2、给div1绑定鼠标按下的事件
div1.onmousedown = function(e){
// 3、实现鼠标在哪里按下,拖拽的时候鼠标相对于div1的位置不变
// 计算鼠标相对于div1的坐标
var left = e.clientX - div1.offsetLeft;
var top = e.clientY - div1.offsetTop;
// 4、给document绑定onmousemove事件
document.onmousemove = function(e){
div1.style.left = e.clientX - left + "px";
div1.style.top = e.clientY - top + "px";
// 5、当松开鼠标左键时,div1不在随鼠标移动
document.onmouseup = function(){
document.onmousemove = null;
div1.onmouseup = null;
}
//防止页面全选时其余内容随div一起移动
return false;
}
}
}
</script>
7、滚轮事件
对象.onmousewheel = function(){}
- event的属性wheelDelta(谷歌)和detail(火狐)是判断鼠标滚动方向的指标,区别是:wheelDelta的值为正(120.240…)则是鼠标向上;为负(-120,-240)则是向下;detail与之相反。
练习–div随着滚轮滚动而变大变小
window.onload = function(){
//1、获取div1对象
var box1 = document.getElementById("box1");
box1.onmousewheel = function(e){
if(e.wheelDelta > 0){
// 设置box1的最小高度,防止滚没了
if(box1.clientHeight > 10)
// 此处的显示高度调用的时clientHeight属性
box1.style.height = box1.clientHeight - 10 + "px";
}else{
box1.style.height = box1.clientHeight + 10 + "px";
}
// 当鼠标滚轮向下滚动时,页面默认也会向下滚动,可以通过下面代码
// 关闭页面默认行为
return false;
}
}
8、键盘事件
事件:
- onkeydown 按下键位
- onkeyup 松开键位
event的属性:
- keyCode 按键的Unicode编码值
- ctrlKey 判断ctrl键是否被按下
- shiftKey 判断shift键是否被按下
- altKey 判断alt键是否被按下
例子:
在响应函数中添加return false
可以取消系统的默认行为
document.onkeydown = function(e){
ctrl和a同时被按下时,才会输出
if(e.keyCode == 65 && e.ctrlKey)
console.log(e.keyCode+"被按下了");
取消ctrl+a的默认全选功能
return false;
}
input1.onkeydown = function(e){
if(e.keyCode >= 97 && e.keyCode <= 105){
//如果输入的时0-9,则不显示
return false;
}
}
十二、BOM
1、定义
BOM是浏览器对象模型,是通过js来操作浏览器的。
2、对象
Window
- 代表的是整个浏览器的窗口,同时window也是网页中的全局对象
Navigator
- 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
Location
- 代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
History
- 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录
由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页
而且该操作只在当次访问时有效
Screen
- 代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息
这些BOM对象在浏览器中都是作为window对象的属性保存的,
可以通过window对象来使用,也可以直接使用
3、history
btn.onclick = function(){
/*
* length
* - 属性,可以获取到当成访问的链接数量
*/
//alert(history.length);
/*
* back()
* - 可以用来回退到上一个页面,作用和浏览器的回退按钮一样
*/
//history.back();
/*
* forward()
* - 可以跳转下一个页面,作用和浏览器的前进按钮一样
*/
//history.forward();
/*
* go()
* - 可以用来跳转到指定的页面
* - 它需要一个整数作为参数
* 1:表示向前跳转一个页面 相当于back()
* 2:表示向前跳转两个页面
* -1:表示向后跳转一个页面 相当于forward()
* -2:表示向后跳转两个页面
*/
history.go(1);
};
4、navigator
userAgent存放浏览器信息
var ua = navigator.userAgent;
5、location
btn.onclick = function(){
//如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
alert(location);
/*
* 如果直接将location属性修改为一个完整的路径,或相对路径
* 则我们页面会自动跳转到该路径,并且会生成相应的历史记录
*/
location = "http://www.baidu.com";
//location = "01.BOM.html";
/*
* assign()
* - 用来跳转到其他的页面,作用和直接修改location一样
*/
location.assign("http://www.baidu.com");
/*
* reload()
* - 用于重新加载当前页面,作用和刷新按钮一样
* - 如果在方法中传递一个true,作为参数,则会强制清空缓存刷新页面
*/
location.reload(true);
/*
* replace()
* - 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
* 不会生成历史记录,不能使用回退按钮回退
*/
location.replace("01.BOM.html");
};
6、Window 对象方法(定时器)
- setInterval() :可按照指定的周期(以毫秒计)来调用函数或计算表达式。
参数:
1、欲调用的函数
2、调用间隔时间
返回值:
返回一个Number类型的数据,这个数字用来作为定时器的唯一标识,可用作clearInterval()中的参数 - clearInterval()
clearInterval() 方法可取消由 setInterval()
参数:
方法中需要一个定时器的标识作为参数,这样将关闭标识对应的定时器 - 例子:
定时器实现图片切换
window.onload = function(){
var img = document.getElementById("img");
var btn = document.getElementById("btn");
var end = document.getElementById("end");
var i = 0, timer;
var pic = ["img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg","img/5.jpg"];
// fun实现图片切换
function fun(){
// 取模可以实现循环
img.src = pic[++i % pic.length];
}
btn.onclick = function(){
//为了避免出现多次点击开始创建多个定时器的情况,
//每次开启定时器之前先将前一个定时器关闭
clearInterval(timer);
timer = setInterval(fun,1000);
}
end.onclick = function(){
clearInterval(timer);
}
}
- setTimeout():延时调用一个函数不马上执行,而是隔一段时间以后在执行,而且只会执行一次
参数:与上面一样
返回值:与上面一样 - clearTimeout():与上面一样
- 延时调用和定时调用实际上是可以互相代替的,在开发中可以根据自己需要去选择
7、定时器的应用–move函数
/*
* 参数:
* -obj 要操作的目标元素
* -attr 要操作元素的属性
* -target 目标值
* -speed 速度
* -callback 回响函数
* */
function move(obj,attr,target,speed,callback){
//关闭上一个同类定时器,如果不关,每按一次按钮,将再次开启一个定时器,导致函数执行的速度加快;
clearInterval(obj.timer);
// 判断移动的方向来设置速度的正负
var current = getComputedStyle(obj,null)[attr];
current = parseInt(current);
if(current > target)
speed = -speed;
obj.timer = setInterval(function(){
// 这里不能使用上边的current,因为current不变,而元素的实际值一直在改变
var oldValue = getComputedStyle(obj,null)[attr];
// getComputedStyle()返回值中含有px,故要用parseInt()将数值分离出来
var newValue = parseInt(oldValue) + speed;
if(newValue > target && speed > 0 || newValue < target && speed <0)
newValue = target;
// 这里注意,obj.style.样式,此处的样式也是属性,故可以使用[""]访问
obj.style[attr] = newValue + "px";
if(newValue == target){
clearInterval(obj.timer);
//动画执行完毕,调用callback
callback();
}
},100);
}
8、重点练习–轮播图
完整代码
注意事项:
- 排查错误:由于ul的一个样式 left:0px; 没写,导致内置浏览器一直无法加载图片移动的动画效果,排查了好久都没有找到这个原因,下次在遇到这种问题就要将自己的代码和正确的代码一行一行对比;
- 内联样式赋值记得 +“px”;
- 设置定位后才能操作left、right、top、bottom属性;
- 向左浮动:设置li标签的样式 float:left;让li标签可以并列成一排,并且需要设置ul的宽度,ul的宽度应该等于所有图片的宽度之和。
- 超链接a标签也要设置样式 float:left;使导航栏浮于图片的上面;
- 自动切换实现首尾两张无缝切换;
- 自动切换和点击切换之间的关系;
9、对类(class)的操作
为了降低js与css的耦合度,同时也是为减少页面渲染次数(对内联样式进行一次修改都会重新渲染一次元素),一般修改css样式都是对元素class的修改。
我们可以通过修改元素的class属性来间接的修改样式这样一来,我们只需要修改一次,即可同时修改多个样式,浏览器只需要重新渲染页面一次,性能比较好,并且这种方式,可以使表现和行为进一步的分离。
- 增加类
- 判断是否含有某个类
- 删除指定类
- toggle类
//添加类
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 delClass(obj,cn){
var reg = new RegExp("\\b"+cn+"\\b");
obj.className = obj.className.replace(reg,"");
}
// toggle:有则删除,无则添加,相当于反选。
function toggleClass(obj,cn){
if(hasClass(obj,cn)){
delClass(obj,cn);
}else{
addClass(obj,cn);
}
}
10、练习–二级菜单
- 修改内联样式一定要加px;
- 本题的精髓之处:两极反转;
- 实现功能之后将内联样式设置为空;
- 设置辅助变量存放之前的div;(轮播图导航栏的选中效果可以参考此方法)
window.onload = function(){
var spans = document.querySelectorAll("span");
// 设置辅助变量存放之前操作的div
var openDiv = spans[0].parentNode;
for(var i=0;i<spans.length;i++){
spans[i].onclick = function(){
var curDiv = this.parentNode;
method(curDiv);
if(curDiv != openDiv && !hasClass(openDiv,"collapsed"))
method(openDiv);
openDiv = curDiv;
}
}
function method(div){
// 按一级菜单之前的高度
var oldHeight = div.clientHeight;
toggleClass(div,"collapsed");
// 按一级菜单之后的高度
var newHeight = div.clientHeight;
// 内联样式一定要加px
// 这里是本题的精髓所在:为了获取改变之后的值,可以先执行一遍
// 之前的函数,再将其高度改回来执行新加的方法
div.style.height = oldHeight + "px";
move(div,"height",newHeight,10,function(){
// 最后要清空内联样式,保证样式表样式不受影响
div.style.height = "";
})
}
}
十三、json
1、定义
json全称Javascript object Notation,本质上是一个字符串,这个字符串可以被任意的语言所识别,并且可以转换为任意语言中的对象,JSON在开发中主要用来在不同语言间进行数据交互。
JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号,其他的和JS语法一致
2、分类
json中有对象{}和数组[];
json允许的使用的值:字符串、数值、布尔值、null、对象、数组
3、创建json对象
var arr = '[1,2,3,"hello",true]';
var obj2 = '{"arr":[1,2,3]}';
4、解析json–JSON.parse()
var json = '{"name":"张三","age":18,"gender":"男"}';
var o = JSON.parse(json);
console.log(o.gender);
var arr = '[1,true,"哈啊哈",[1,2,3],{"name":"张三","age":18,"gender":"男"}]';
var obj = JSON.parse(arr);
console.log(obj[4].name);
5、js对象转换成json字符串 – JSON.stringify()
var obj = {name:"李四",age:23,gender:"男"};
var test = JSON.stringify(obj);
console.log(typeof test);// string
js高级
一、 函数高级
1、函数的prototype属性
- 每个函数都有一个prototype属性,它默认指向一个空的object实例对象(原型对象) ;(object除外)
- 原型对象中有一个属性constructor,它指向函数对象;
2、给原型对象添加属性
函数中所有的实例对象自动拥有原型中的属性;
// 1、创建函数
function fun(){
}
// 2、给原型对象添加属性test
fun.prototype.test=function(){
console.log("111");
}
// 3、创建对象
var f = new fun();
// 4、调用test
f.test();
3、显示原型和隐式原型
- 每个函数都有一个prototype,即显式原型,是在函数定义时自动添加的,默认值是空的object;
- 每个实例对象都有一个__proto__,即隐式原型,是在创建对象时自动添加的,默认值为构造函数的prototype值;
- 实例对象隐式原型的值是其构造函数显式原型的值;
fun.prototype==f.__proto__
- 程序员能直接操作显性原型的值,但是最好不要直接操作隐式元素的值;
4、原型链 (隐式原型链)
- 访问一个对象的属性时,先在自身的属性中查找,如果有,返回;如果没有,则沿着__proto__这条链向上查找,找到返回;如果没找到,则返回undefined;(如上边的fn.test3);
- 原型链的作用是查找对象的属性;
- Object的原型对象是原型链的尽头,其隐式原型__proto__是null;
- 所有的实例对象都有隐式原型属性,函数也不例外,函数是Function的实例对象
function foo(){}等同于var foo=new Function();
- 所有函数的隐式原型__proto__都是一样的,都是Function的显式原型;
Function=new Function();
- 所有的函数包括Function都是Function的实例,所以函数Function的显示原型等于其隐式原型,因为
Function=new Function();
- 实例对象可能存在多个原型对象;
5、原型链之属性问题
- 读取属性时会到原型链中查找;
- 设置对象的属性值时,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值;
- 方法一般定义在原型中,而属性一般通过构造函数定义在对象的本身(因为方法是对象共用的,而每个对象的属性值不同)
function fun(name,age){
this.name=name,
this.age=age
}
fun.prototype.test = function(){
console.log(this.name,this.age)
}
var f1 = new fun("张三",12)
f1.test()
var f2 = new fun("李四",15)
f2.test()
6、instanceof是如何判断的
A instanceof B,如果B函数的显式原型在A对象的(隐式)原型链上,则返回true,否则返回false;
7、练习题
- 1,undefined,2,3
8、变量提升和函数提升
- 变量声明提升
通过var定义的变量,在变量定义之前就可以访问,其值是undefined; - 函数声明提升
通过function定义的函数,在之前就可以直接调用,其值是函数本身;
f1(); // f1是通过var定义的,不是函数声明提升,而是变量声明提升,所以无法调用
console.log(f1); // undefined
var f1 = function(){
}
- 面试题
先执行变量提升,再执行函数提升
function a(){}
var a
console.log(typeof a) // function
先进行变量提升和函数提升,然后再给变量赋值
var c = 1;
function c(c){
console.log(c);
}
c(2); // Uncaught TypeError: c is not a function
9、作用域
-
js中没有块作用域,只有全局作用域和函数作用域;
-
一个代码片段中会产生n+1个作用域,n代表函数的个数,1是全局作用域;
-
作用域的作用是隔离变量;
-
作用域与执行上下文
-
练习
作用域只有函数作用域和全局作用域,在局部作用域中找不到f1,然后去全局作用域中找,此时全局作用域中只有obj一个变量,所有还是找不到,最终报错。
var obj = {
f1:function(){
console.log(f1)
}
}
console.log(obj.f1()); //f1 is not defined
10、闭包
- 内部函数调用外部函数的变量(函数)就会产生闭包,内部函数定义时就产生了闭包,;
- 闭包是嵌套的内部函数,包含被引用变量(函数)的对象;
function f1(){
var a=10
function f2(){
console.log(a)
}
}
f1()
- 外部函数调用的次数就是闭包产生的次数
function f1(){
对于f2来说,此时闭包就已经产生了,因为函数提升
var a=2
function f2(){
console.log(++a)
}
对于f3来说,闭包在执行完下一行代码时才产生
var f3 = function(){}
return f2
}
var f = f1() // 只调用了一次外部函数,所有只产生了一次闭包
f() //3
f()//4
f = null //包括闭包的函数变成垃圾对象时,闭包死亡
- 闭包的作用:延长局部变量的生命周期;函数外部可以操作函数内部的数据;
- 自定义js模块:具有特定功能的js文件;将所有的数据和函数都封装在一个函数的内部;只向外部暴露一个包含n个方法的对象;
(function(w){
var a=1
function f1(){
console.log(++a)
}
function f2(){
console.log(--a)
}
w.model = {
f1:f1,
f2:f2
}
})(window)
--------------------------
调用:
model.f1();
model.f2();
- 面试题
var name = "the window"
var obj1 = {
name : "the f",
getNameFun:function(){
return function(){
console.log(this.name)
} // 没有形成了闭包,此时that是window
}
}
obj1.getNameFun()() // the window
var name = "the window"
var obj = {
name : "the f",
getNameFun:function(){
var that = this
return function(){
console.log(that.name)
} // 形成了闭包,此时that是obj
}
}
obj.getNameFun()() // the f
11、内存泄漏和内存溢出
- 内存泄露会导致内存溢出,但是内存溢出不一定是由内存泄露引起的;
- 内存泄漏是因为占用的内存没有及时释放引起的;