【JavaScript】JS从入门到深入(复习查漏向
pre
精细得学过一遍JS后才发现,原来之前CTF中有些nodejs的题目以及一些游戏题的payload
就变得很好理解了。
基础知识
ECMAScript标准 -- ES标准
编写位置
-
外联文件
<script src="引入的文件位置"></script>
-
内联文件
<script type="text/javascript">
js代码
</script> -
内嵌代码(结构与行为耦合,不使用)
<input type="button" onclick="alert('弹出')"></input>
<a href="javascript:alert('弹出');"></a>
基本语法
- 严格区分大小写
- 语句分号结尾
- 没有添加分号时浏览器自动添加,但是消耗资源并且可能添加出错
字面量和变量
- 字面量即为常量
标识符
- 所有可以自定义的变量都叫做标识符,并且遵循以下规范
- 只能以字母数字,下划线,$构成
- 不能以数字开头
- 不能使用ES的关键字和保留字
- 标识符以unicode编码表示,因此可以使用UTF-8的所有内容
基本数据类型
string
-
number
- 可以表示整数与浮点数
- 2进制浮点数以分数表示,不准确
- NaN与Infinity是数值的字面量,表示非数与无穷
-
boolean
- 只有两个值:
true false
- 只有两个值:
-
null
//表示一个空对象
var a = null;
console.log(typeof a);
//结果为object -
undefined
//已经声明的变量未赋值则成为undefined
var a;
console.log(typeof a);
//结果为undefined
强制类型转换
-
string
-
两种办法:
a.toString() 或者 String()
- toString只能用于对象,因此null和undefined无法调用
- String()对于Number, String, Boolean来说会调用底层的toString()方法,对于null和undefined会直接进行转换
-
-
number
-
三种方法:
Number()、parseInt()、parseFloat()
-
Number():
- 对于字符串来说如果只包含数字,直接转换成数字,如果包含非数字转换成NaN,如果是""则转换成0,如果是" 字符串 "会自动去除前后空格再判断
- 对于boolean值,true转换成1,false转换成0
- 对于null,转换成0
- 对于undefined,转换成NaN
-
parseInt():
- 首先将所有内容转换成字符串再开始解析。
- 从左到右依次解析,需要非整数直接舍去,第一位非整数返回NaN
-
parseFloat():
- 与parseInt()相似,只是遇到第一位小数点不会忽略会转换成小数,其余与之相同
-
-
-
boolean
-
Boolean()
- 对于数字:只有0跟NaN会转换成false
- 对于字符串:只有""会转换成false
- 对于null和undefined,只会转换成false
-
进制
16进制在数字前加
0x
8进制在数字前加
0
2进制在数字前加
0b
某些浏览器无法解析2进制如IE浏览器,同时也不常用
运算符
运算符有以下种类:
typeof,+,-,*,/,%
所有的运算符都不改变原始变量而是返回进行运算后的结果,并且NaN与任何值进行运算结果都为NaN
-
typeof
//typeof返回一个变量或者字面量的类型,返回值为string
var a = typeof 2;
console.log(a);
console.log(typeof a);
//结果为:number与string -
+
- 数字的加法运算
-
遇到非number的值,会将其转换成number
- 遇到string的值,会转换成string然后进行接串操作,可应用于长字符串的换行与隐性string类型转换
-
其余运算符进行相应数学运算并且在遇到非number值时,会全部转换成number值后再进行运算操作,此特性可用于隐式number类型转换,但还有更简单的方法
var a = "123";
console.log(a / 1);
console.log(typeof (a / 1));
// 结果为123和number类型 -
一元运算符
-
正号
+
和负号-
-
两者能够进行相应的数学运算同时在遇到非number的值时会将其强制转换成number值再进行运算,此特性可用于隐式number类型转换
var a = "123";
console.log(+a);
console.log(typeof +a);
//结果为123和number类型
-
-
-
自增与自减
-
++
、--
同正负号,非number的值时会将其强制转换成number值再进行运算。
-
-
逻辑运算符
包括
!
,&&
,||
三种运算符-
!
:两次取非会得到原值的布尔值,可以利用这个特性进行隐式布尔值转换
var a = "123";
console.log("a = " + !!a);
//结果为true,与Boolean(a)相同&&
:两个值都为true结果才为true-
||
:两个值都为false结果才为false- 在JS中
&&
与||
都是属于短路操作,即当一个值满足要求时才会继续执行第二个操作,第一个值不满足要求时不执行第二个操作 - 当参数不是boolean值时先会将参数转换成boolean值后再按照以上规则输出原值
- 在JS中
//&&:
//当第一个值为true时,返回第二个值
//当第一个值为false时,返回第一个值
console.log("123" && "456");
//结果为"456"
console.log(NaN && "111");
//结果为NaN
//||:
//当第一个值为false时,返回第二个值
//当第一个值为true时,返回第一个值
console.log(NaN || "111");
//结果为"111"
console.log("123" || "456");
//结果为"123"
//即返回决定语句真假的值,如&&时,第一个值为true,则第二个值真正决定整个语句真假,
// 如||时,第一个值为false,则第第二个值真正决定整个语句真假 -
-
赋值运算符
-
有以下几种:
// =, +=, -=, /=, *=
var a += 3; 等价于 var a = a + 3;
-
-
关系运算符
- 有以下几种:
<, >, <=, >=
//有一方为number值时,将非number值转换成number值再进行比较
//NaN与任何值进行任何比较结果都为false, 包括NaN本身
console.log(NaN >= NaN);
//结果为false
//当两方都为string时,按位比较字符编码,因此在两者都为string类型值为数字时进行比较,结果可能不符合预期,可应用于英文名字的排序
console.log("11" > "2");
//结果为false - 有以下几种:
-
unicode编码
-
在js中使用时在编码前加
\u
对编码进行转义输出
console.log("\u0031");
//结果为1,编码为16进制 -
在HTML中使用时以 &#编码; 的格式输出
0
<!-- 结果为1,编码为10进制 -->
-
-
相等运算符
-
包括
==, !=, ===, !==
-
==, !=
两者类型相同时判断是否相等,类型不同时进行类型转换再判断是否相等,转换成哪种类型无法确定
-
由于undefined衍生于null,因此两者相等
console.log(undefined == null) //true
-
NaN与任何值进行运算结果都为false,包括自己
console.log(NaN == NaN) //false
-
===, !==
除不进行类型转换外,规则与
==
,!==
类似当两者类型不同时,
===
直接返回false,!==
直接返回true-
NaN的规则在此处同样适用
console.log(NaN === NaN) //false
-
undefined与null在这种运算符下,才会不相等
console.log(undefined === null) //false
-
-
-
三元运算符
-
语法格式为
(表达式)?(语句1):(语句2)
-
-
逗号运算符
- 用来分割不同语句,可以同时声明多个变量
-
运算符优先级
- 按照优先级表进行先后运算,可以使用()改变优先级
代码块
-
将多个语句用
{}
包含起来,这一堆语句称为代码块,它只具有分组的作用,没有其他用途{
var a = 1;
console.log(a);
}
console.log(a);
//结果为1 /n 1
条件语句
-
条件判断语句
if(表达式){
语句...
}else if{
语句...
}else{
语句...
} -
条件分支语句
switch(表达式){
case 值1:
语句...
break;
case 值2:
语句...
break;
default:
语句...
break;
}
循环
使代码能在某种条件下不断执行的语句
-
while
循环-
while
var i = 0; //1.初始化变量
while(i < 10){ //2.当不满足条件时退出循环
语句...
i++; //3.更新变量
} -
do while
do{
语句...
}while(表达式)
-
-
for
for(初始化变量; 条件表达式; 更新变量){
语句
} label
:在循环语句的前一行使用label语句用来标识某一个循环-
两者都可增加参数,参数是循环的标识名,可以跳出所指定的循环
good:
for(var i=1; i<10; i++){
console.log(i);
for(var j=1; j<10; j++){
break good;
}
}
//结果只有一个1
bad:
for(var i=1; i<10; i++){
console.log(i);
for(var j=1; j<10; j++){
if(i==2){
continue bad;
}
}
}
//结果为1,3,4,5,6,7,8,9
程序效率
使用
console.time("字符串标志")
来标记一个计时器-
使用
console.timeEnd("字符串标志")
来结束某个计时器并打印出计时器经过的时间
console.time("a");
console.timeEnd("a");
//结果是名为a的计时器经过的时间,单位是ms,只能用在浏览器中
对象-Object
-
对象属于复合数据类型,有三种,分别是:
- 内建对象
- 由ES标准中内建的对象,在任何的ES实现中都可以使用,如
Math, String, Boolean, Number, Function, Object...
- 由ES标准中内建的对象,在任何的ES实现中都可以使用,如
- 宿主对象
- 由js运行的环境所提供的对象,一般指浏览器,如
DOM, BOM...
- 由js运行的环境所提供的对象,一般指浏览器,如
- 自定义对象
- 由开发人员自定义的对象
- 内建对象
-
创建对象的基础方法
- new所调用的函数是一个构造函数
constructor()
,构造函数是专门用来创建对象的函数 - 使用typeof语句会返回object
var obj = new Object();
console.log(typeof obj); //"object" - new所调用的函数是一个构造函数
-
增加属性
-
对象.属性名 = 属性值;
obj.name = "111";
属性值可以是任何数据类型,包括null,undefined,object,当是object时可以无限嵌套
var obj2 = new Object();
obj2.name = "333";
obj.test = obj2; -
-
修改属性
-
对象.属性名 = 属性值;
obj.name = "222";
-
-
查询属性
-
对象.属性名
console.log(obj.name); //222
-
当对象的属性为另一个对象时.重复使用来获取对象的对象的属性值
console.log(obj.test.name); //333
-
-
删除属性
-
delete
对象.属性delete obj.name;
console.log(obj.name); //undefined
当查询对象的某个属性不存在时,会返回
undefined
-
-
使用中括号
- 当属性名没有遵循标识符规范时需要使用[]来增删查改相应属性,属性名可以是变量或者字符串
对象[属性名] = 属性值
obj["123"] = 345; //字符串
var test = "123";
console.log(obj[test]); //变量
//结果为345 - 当属性名没有遵循标识符规范时需要使用[]来增删查改相应属性,属性名可以是变量或者字符串
-
in
用来查询某个对象是否有相应属性名,属性名必须是字符串或者是变量,有则返回
true
,没有返回false
-
属性名 in 对象
console.log("123" in obj); \\true
-
-
对象字面量
可以使用对象字面量来新建对象,效果与new Object()相同
-
{属性名: 属性值, 属性名: 属性值...};
var obj = {name: "a", age: "16", gender: "男"};
属性名可以使用引号包起来,但是一般不使用,当属性名不遵循标识符规范时,需要使用引号包起来,最后一个属性写完后不加逗号
函数
函数也是对象,它具有普通对象具有的所有功能
-
新建函数对象:
var func = new Function("需要执行的代码块");
//在构造函数中可以加入字符串参数代码使得调用函数时可以直接执行
var func = new Function("console.log(111)");
func();
//结果为111 -
函数声明:
function foo(param1,param2, param3...) {
语句...
} -
函数表达式:
var func = function([param1,param2, param3...]) {
语句...
} -
形参与实参
当实参数量大于形参时,多出来的实参会被忽略
当实参数量小于形参时,未赋值的形参会是undefined类型
-
实参可以是任意数据类型包括对象与函数,当实参数量过多时,可以考虑将部分实参封装成一个对象传入
将函数当做实参传入另一个函数:
function func1(){
console.log("a");
return "1";
}
function func2(a){
console.log(a);
}
func2(func1); //结果为func1对象本身,结果为func1函数的内容
func2(func1()); //结果为func1的函数返回值,结果为1
-
返回值
-
return
return [返回值];
function test(a, b){
return a+b;
}
var result = test(1, 2);
console.log(result);
//结果为3 当return后不加参数时,相当于函数返回undefined
函数中不使用return时,也相当于返回undefined
-
返回值可以是任意类型,包括对象和函数
function func1(){
function func2(){
console.log("func2");
}
return func2;
}
var a = func1();
console.log(a);
//结果为func2函数本身的内容
console.log(a()); //与console.log(func1()());相同
//结果为"func2"
-
-
立即执行函数
(function([形参1, 形参2...]) {
语句...
})([实参1, 实参2...])-
当写成以下形式时,js会将{}部分当成代码块,无法识别函数声明
function([形参1, 形参2...]){
语句...
}([实参1, 实参2...])
-
-
方法
-
调用对象中的函数,被称为调用这个对象的方法
var obj = new Object();
obj.name = "111";
obj.callName = function(){
console.log(obj.name);
}
obj.callName();
//结果为"111"
-
作用域
-
全局作用域
- 直接写在script标签中的代码都属于全局作用域,它在打开页面时创建,在关闭页面时销毁 全局作用域中所有的变量可以在页面的任意部分被访问到
var a = 1;
function func1(){
console.log(a);
}
//结果为1- 全局作用域中所有声明的变量其实是被创建成window对象的属性
var a = 1;
console.log(window.a);
//结果为1-
变量的提前声明
当使用var来声明或者声明并赋值变量时,无论声明位置在何处,声明本身这个语句会在当前script标签中的最顶端被执行
console.log(a);
a = 1;
//报错,a未被声明
console.log(a);
var a = 1;
//结果为undefined而不是报错,因为var a;这条语句已经在代码最顶端被执行过了-
函数的提前声明
无论函数在何处被声明,函数声明本身会在任何代码前被执行
func1();
function func1(){
console.log("1");
}
//结果为"1"但是对于函数表达式来说,由于使用var来声明函数,因此只符合变量提前声明的特性
func1();
var func1 = function(){
console.log("1");
}
//结果报错,undefined不是一个函数
-
函数作用域
函数作用域在函数执行时创建,在执行完毕后销毁,在函数作用域内部与全局作用域相似
当在函数中使用变量时会先向当前作用域查找,没有则向上一级作用域查找,直到全局作用域,如果全局作用域中没有此变量时报错
var a = 1;
function func1(){
function func2(){
console.log(a);
}
func2();
}
func1();
//结果为1在函数作用域中可以访问到全局作用域的变量,反之不成立
function func1(){
var a = 1;
}
console.log(a);
//结果为报错,a未定义在函数作用域中变量声明提前与函数声明提前同样适用(当函数有形参时相当于在函数内部声明了变量)
function func1(){
console.log(a);
var a = 1;
}
func1();
//结果为undefined
function func1(){
var a = 1;
func2();
function func2(){
console.log(a);
}
}
//结果为1
this
-
当调用函数时,解析器会隐式传入一个参数
this
,它是一个对象- 当以函数的形式调用时,
this
永远是全局作用域window
- 当以对象的方法调用时,
this
是调用这个方法的对象 - 当以构造函数调用时,
this
就是新创建的对象
- 当以函数的形式调用时,
-
作用:
var name = 1, obj1 = {name: 2, sayName: func}, obj2 = {name:3, sayName: func};
function func(){
console.log(this.name);
};
func();
obj1.sayName();
obj2.sayName();
//结果为1, 2, 3
//可以使用this来使方法/函数内的值发生变化
遍历枚举对象属性
-
语法:
for(var 声明变量 in 对象){
语句...
}
for(var i in obj){
console.log(i); //i为obj对象的属性名
console.log(obj[i]); //obj[i]为obj对象的属性值
}
创建对象的高级方法
-
还有几种方法被用来方便地创建对象
可以使用instanceof来检测一个变量是谁的实例
-
工厂方法
function createPerson(name, age){
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
function createDog(name, age){
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
var person = createPerson("aaa", 16);
var dog = createDog("bbb", 18);
console.log(person instanceof createPerson);
console.log(dog instanceof createDog);
console.log(dog instanceof Object);
//结果都为false false true缺点:无法得知所创建的是一个什么对象,所以出现了构造函数来解决这个问题
-
构造函数
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
}
}
function Dog(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
}
}
var person1 = new Person("aaa", 16);
var person1 = new Person("ccc", 14);
var dog = new Dog("bbb", 18);
console.log(person1 instanceof Person);
console.log(dog instanceof Dog);
//结果分别为true true构造函数与普通函数在使用上的区别就是是否使用了
new
,构造函数又被称为类,对类作new
操作等到的结果被称为实例-
构造函数的执行流程:
- 立即新建1个对象
- 将构造函数的
this
值赋值为新创建的对象 - 依次执行构造函数内的代码
- 将新建的对象返回
-
构造函数改进:
按照上述代码编写会在给对象创建方法时重复创建函数,当实例化类次数增加时会浪费大量内存,因此需要将重复创建的方法函数变成只创建一次
console.log(person1.sayName == person2.sayName);
//结果为false,证明的确重复创建了函数可以将方法声明在全局作用域中
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = func;
}
function func(){
console.log(this.name);
}
var person1 = new Person("aaa", 16);
var person2 = new Person("bbb", 18);
console.log(person1.sayName == person2.sayName);
//结果为true,证明是同一个函数但是这种办法会污染全局命名空间并且不够安全,有可能会被其他函数覆盖, 想要解决这个问题需要引出一个概念---原型对象
-
原型对象
- 每一个类都可以有一个原型对象
prototype
,它是一个对象,并且这个类的实例会有一个原型属性__proto__
,它的值是这个实例的类的原型对象地址 - 因此修改类的原型对象的属性也会改变这个类的实例的原型属性所指向的那个原型对象
- 可以利用原型的特性为类开辟出一个新的公共空间让这个类的每一个实例都可以使用这个公共空间的值或者方法而不会污染全局命名空间
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype = function(){
console.log(this.name);
}
var person1 = new Person("a",12);
console.log(person1.__proto__ == Person.prototype);
//结果为true
-
所有对象都有原型属性
__proto__
,由于原型对象也是对象,因此也具有原型属性__proto__
console.log(Person.prototype.__proto__);
//结果为object -
Object的实例的原型没有原型
var a = new Object();
console.log(a.__proto__.__proto__);
//结果为null -
所有对象都是Object对象的实例,包括原型对象,因此原型的回溯最多到Object实例的原型为止,也就是原型对象的原型为止
实例中变量查找顺序:
- 先在被实例化的类中的变量之间查找,如果找到则输出,否则进入它的原型对象
- 在类中的原型对象中的变量之间查找,如果找到则输出,否则进入它的原型对象
- 在原型对象的原型中的变量之间查找,如果找到则输出,否则输出
undefined
使用
in
语句来查找属性是否属于某个对象时会向它的原型中查找如果不想查找原型中的属性,使用
hasOwnProperty
方法function Person(){}
Person.prototype.a = 1;
var person = new Person();
person.b = 1;
console.log("a" in person);
console.log(person.hasOwnProperty("a"));
console.log(person.hasOwnProperty("b"));
//结果为true, false, true -
当在页面中打印一个对象时,实际上输出的是这个对象的valueOf方法的返回值,因此可以通过修改对象的valueOf方法来修改打印对象时的结果
function Person(name){
this.name = name;
}
Person.prototype.valueOf = function(){
return "name = " + this.name;
};
var person = new Person("a");
console.log(person);
结果为name = "a" //在实际测试中,结果与浏览器相关ValueOf()方法
垃圾回收
- 当创建对象之后对所有这个对象的变量赋值为null时,这个对象就永远无法被操作,这个对象就称为垃圾
- js拥有自动的垃圾回收机制,不需要也不能手动地回收垃圾,能做的只有将不再使用的对象赋值为null
数组
-
数组也是一个对象,与对象的区别在于数组只能通过索引来查找值,并且存储效率要比普通对象更高,所以具有所有对象具有的特性
创建数组
var arr = new Array();
arr具有三个对象属性,
constructor
(构造函数的引用),length
(数组长度),prototype
(原型对象的引用)可以直接以索引的形式向数组最后一位添加内容
数组[数组.length] = 值;
可以通过修改数组长度来删除一些数据
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
arr.length = 3;
console.log(arr[3]);
//结果为undefined当访问数组中不存在的数据时,会返回
undefined
而不是报错可以使用数组字面量方便地创建数组
//语法:[]
var arr = [];在数组字面量中可以直接加入参数来给数组赋值
var arr = [0, 1, 2, 3];
console.log(arr);
//结果为0,1,2,3同样也能向数组类添加参数来直接给数组赋值
var arr1 = new Array(0, 1, 2, 3);
console.log(arr1);
//结果为0,1,2,3但是当参数只有一个时,结果会有所不同
var arr = [10]; //创建一个第一个值为10的数组
var arr1 = new Array(10); //创建一个长度为10的数组
console.log(arr);
console.log(arr1);
//结果分别为10和,,,,,,,,,数组常用方法
push()
:向数组最后添加一个或多个元素并将数组长度返回pop()
:删除数组最后一个元素并将该元素返回unshift()
:向数组开头添加一个或多个元素并将数组长度返回shift()
:删除数组开头的元素并将该元素返回-
forEach()
- 按顺序遍历整个数组
- 支持IE8以上或者其他的浏览器
- 数组.forEach(function(value, index, arr){});*
它会在回调函数中以实参的形式传递3个参数:
- 当前循环中的元素
- 当前循环中的索引
- 调用forEach函数的数组
-
slice()
从一个数组中截取特定范围的元素并将这些元素以数组的形式返回,不改变原数组
数组.slice(start, end);
第一个参数是截取开始的索引,返回数组会包括开始索引的元素
-
第二个参数是截取结束的索引,返回数组不会包括结束索引的元素
var arr = [0,1,2,3,4,5];
var arr1 = arr.slice(0,4);
console.log(arr1);
//结果为0,1,2,3 -
参数可以是负值,如果为负就是从后往前计数
var arr = [0,1,2,3,4,5];
var arr1 = arr.slice(-3,-1);
console.log(arr1);
//结果为3,4
-
splice()
删除或者添加元素,直接改变原数组,返回值为删除的元素
数组.splice(start, number[,元素1, 元素2...]);
第一个参数为从哪个索引开始删除元素
第二个参数为删除几个元素
-
从第三个参数开始的参数都是是在第一个参数的索引之前添加这些元素
var arr = [0,1,2,3,4,5];
arr.splice(0,1,7,8,9);
console.log(arr);
//结果为7,8,9,1,2,3,4,5
-
concat()
可以将两个或者多个数组连接成一个数组
不会改变原数组
-
数组.concat(任意数据类型[,任意数据类型...]);
var arr = [1,2,3,4];
var result = arr.concat([5,6,7,8],1,"a", false, null, undefined, {});
console.log(result);
//结果为1,2,3,4,5,6,7,8,1,"a",false,null,undefined,{}
-
join()
将数组中的元素转换成字符串, 可以添加参数指定元素之间的连接符, 无参数时默认为逗号, 不会改变原数组
-
数组.join([字符串]);
var arr = [1,2,3,4];
var result = arr.join(" ");
console.log(result);
//结果为"1 2 3 4"
-
reverse()
-
调换数组中元素的排列顺序
会修改原数组,并且修改后的数组与返回值相同
-
语法:
数组.reverse();
var arr = [1,2,3,4];
var result = arr.reverse()
console.log(result);
console.log(arr);
//结果都为4,3,2,1
-
-
sort()
给数组中的元素排序,默认以unicode编码顺序排列,因此直接对数组中的数字排序会产生预料外的结果
可以传递一个回调函数作为
sort
的参数,回调函数中有两个形参分别表示数组中一前一后的两个元素,具体是哪两个元素需要根据循环确认函数的返回值决定是否交换这个两个元素,当返回值大于0时交换,小于0时不交换,等于0时认为两个值相等不交换
会直接修改原数组的元素,与方法的返回值相同
-
语法:
数组.sort([回调函数]);
var arr = [5,3,6,767,34,2];
arr.sort();
console.log(arr);
//结果为2,3,34,5,6,767
arr.sort(function(a, b){
return a-b;
});
console.log(arr);
//结果为2,3,5,6,34,767
函数对象
-
call
和apply
函数对象都具有这两个方法,可以向这两个方法中的第一个参数传入一个对象用来修改这个方法的
this
对象-
如果函数对象需要形参
call
方法中第二个参数开始依次输入要传递给函数对象的实参将需要传递的实参封装成一个数组作为
apply
的第二个参数将实参传递给函数对象 -
语法:
函数.call(对象[,参数1...]);
函数.apply(对象[,数组]);
var obj = {};
function a(a){
console.log("a = " + a);
console.log(this);
}
a(1);
a.call(obj, 1);
a.apply(obj, [1]);
//结果为
// window,1
// object,1
// object,1
-
arguments
- 在调用函数时,浏览器还会隐式传递一个参数
arguments
,它是一个类数组对象,不是数组对象 - 使用索引来查询调用函数时传入的参数
- 拥有
length
属性来表示传入参数的数量 - 拥有
callee
属性表示当前指向的函数引用,可以用来编写递归函数
function a(){
console.log(arguments.length);
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments.callee);
}
a(1,2);
//结果为2,1,2,a函数本身 - 在调用函数时,浏览器还会隐式传递一个参数
global对象
ECMAScript中非常特别的对象,理论上存在但是又无法获取
不属于其他任何对象的属性或者对象都是这个对象的属性和方法
也就是说所有在全局作用域中定义的属性与对象可以说都是这个对象的属性和方法
ECMAScript没有指出如何访问
global
对象,但是浏览器会将这个对象当作window
的一部分加以实现-
常用方法:
-
encodeURL()
用来将整个url编码成浏览器能够识别的字符串,即将一些特殊字符进行编码,如:空格->%20,url中合法特殊字符不会被编码
-
encodeURLComponent()
用来将某一段url编码成浏览器能够识别的字符串,url中合法特殊字符也会被编码
-
decodeURL()
encodeURL
的反向操作,规则与之相同 -
decodeURLComponent()
encodeURLComponent
的反向操作,规则与之相同
-
Date对象
- 用来操作与时间有关的对象
var date = new Date(); //实例化Date对象的值就是执行这行代码时的时间
var date = new Date("12/11/2016 0:0:0"); //当输入参数时以参数对应的含义输出时间,按照mm/dd/yyyy h:m:s的格式输入
-
常用方法:
-
getDate()
获取时间的日
-
getDay()
获取时间的星期,值为0-6,从周日计算
-
getMonth()
获取时间的月份,值为0-11,从1月计算
-
getFullYear()
获取时间的年份
-
getTime()
获取时间的时间戳,为格林尼治标准时间1970/1/1 0:0:0开始到特定世界为止经过的毫秒
-
now()
执行这行代码时的时间戳,可用来计算一段代码的性能
-
Math对象
Math对象与其他内建对象不同,它不是构造函数而是一个工具类,不需要实例化,直接使用
-
语法:
Math.方法();
-
常用属性:
E 自然对数
PI 圆周率
-
常用方法:
-
ceil()
:向上取整 -
floor()
:向下取整 -
round()
:四舍五入 -
random()
:获取0-1之间的随机数 -
max()
:获取多个数中的最大值 -
min()
:获取多个数中的最小值 -
sqrt()
:对某个数开根号 -
pow(x, y)
:求x的y次幂
-
包装类
-
js提供了3个包装类将3种基本数据类型转换成基本数据类型对象,但是在日常开发中尽量不要使用这种方式,因为在转换后进行比较时会产生预期外的结果
-
String:将基本数据类型string转换成string对象
var str = new String("a");
console.log(typeof str);
//结果为object -
Number:将基本数据类型number转换成number对象
var num = new Number(1);
console.log(typeof num);
//结果为object -
Boolean:将基本数据类型boolean转换成boolean对象
var bool = new Boolean(true);
console.log(typeof bool);
//结果为object
-
-
当对这三种基本数据类型操作包装类中的方法或者属性时,浏览器会临时创建一个基本数据类型对象再调用这些方法,然后再将其转换成基本数据类型
var a = 1;
a.toString();
console.log(typeof a);
//结果为string //执行这两行代码时不会报错
//因为实际在对临时创建的基本数据类型对象进行属性赋值操作
//语句执行完毕后临时对象就被销毁,因此第二次执行时结果为undefined a.name = "a";
console.log(a.name);
//结果为undefined
String对象
-
string的底层是用字符数组进行表示的,因此许多数组可以使用的方法在字符串中同样可以使用
var str = "abcdef";
console.log(str[0]);
//结果为"a" -
常用属性:
length 字符串的长度
-
常用方法:(全都不改变原字符串)
charAt()
:返回指定位置的字符,与用索引表示相同charCodeAt()
:返回指定位置的字符unicode编码fromCharCode()
:返回指定unicode编码对应的字符concat()
:连接多个字符串,与使用加号+连接字符串相同-
indexOf()
:返回指定字符在字符串中第一次出现的索引,当没有时返回-1-
第一个参数:需要查找的字符
第二个参数:从第几个索引开始进行查找
-
-
lastIndexOf()
:与indexOf相似,但是它返回的是字符在字符串中最后一次出现的索引,没有时返回-1- 参数同indexOf()
toUpperCase()
:将所有字符转化成大写toLowerCase()
:将所有字符转化成大写-
slice()
:截取指定范围内的字符串,与数组中的slice相似var str = "abcdef";
var result = str.slice(0,-2);
console.log(result);
//结果为"abcd" -
subString()
:与slice相似,不同在于参数为负数时默认输入是0,当第一个参数大于第二个参数时会交换两个参数的位置var str = "abcdef";
var result = str.subString(1, -3);
//结果为"a" -
subStr()
:同样为截取一段字符串,与前两个方法的区别在于参数不同,这个方法不是ES标准,不推荐使用-
第一个参数:索引开始处,包括这个索引
第二个参数:需要截取的字符数量
-
-
split()
:与数组的join方法相反。将字符串以特定方式转换成数组- 第一个参数:将字符串以哪个字符进行拆分充当新数组的元素
当参数为空字符串时,将每个字符都拆分成一个元素存入新数组
var str = "abtcdtef";
var result = str.split("t");
console.log(result);
结果为ab,cd,ef- 第二个参数:决定返回的数组最长长度
正则表达式对象
-
匹配字符串
-
匹配模式
"i" ----忽略大小写
"g" ----全局匹配
var reg = new RegExp("正则表达式", "匹配模式");
-
-
方法:
-
test()
:测试指定字符串是否满足正则的匹配要求,满足返回true,否则返回false
-
-
正则表达式字面量
- var reg = /正则表达式/匹配模式;*
- 使用字面量更方便,使用构造函数更灵活,因为可以使用变量
-
正则表达式语法:
-
|
:或/a|b/.test("ac"); //true
-
[ ]
:与|
含义相同/[ab]/.test("bc"); //true
.
:表示任意字符\
:表示转义,将特殊符号转化成字符*
:表示0个或多个字符+
:表示1个或多个字符^
:表示开头的某个字符$
:表示结尾的某个字符\w
:表示任意字母数字及_
\W
:除了任意字母数字及_
\d
:表示任意数字\D
:除了任意数字\s
:表示空格\S
:除了空格\b
:表示单词分隔符\B
:除了单词分隔符-
{}
:限制字符出现的次数/^a{3,5}$/.test("aaaaaa"); //false
-
()
:将几个字符当做整体/^(ab){2,3}$/.test("abababab"); //false
-
-
常用语法:
[a-z]
小写字母[A-Z]
大写字母[A-z]
英文字母[0-9]
数字 -
可以使用正则的字符串方法:
-
split()
:将字符串以正则表达式作为间断符号拆分成数组var str = "1a2s3d4f5g6h7jk8";
console.log(str.split(/[1-9]/));
//结果为a,s,d,f,g,h,jk正则不设置匹配模式为g也会全局拆分
-
search()
:查询正则表达式中的字符位置,不存在则返回-1,与indexOf相似var str = "1a2s3d4f5g6h7jk8";
console.log(str.search(/[a-z]/));
//结果为1正则设置匹配模式设置为g也不会全局匹配
-
match()
:返回满足正则表达式匹配的字符var str = "1a2s3d4f5g6h7jk8";
console.log(str.match(/[a-z]/));
//结果为a如果需要返回全局匹配的结果需要设置匹配模式为g,返回为数组
console.log(str.match(/[a-z]/g));
结果为a,s,d,f,g,h,j,k -
replace()
:将正则表达式匹配到的字符串用新字符串代替-
第一个参数:需要被替换的原字符串,可以用正则表达式
第二个参数:需要替换的新字符串,可以是空串
var str = "1a2s3d4f5g6h7jk8";
console.log(str.replace(/[a-z]/, "!"));
//结果为"1!2s3d4f5g6h7jk8"
如果需要返回全局匹配的结果需要设置匹配模式为g
console.log(str.replace(/[a-z]/g, "!"));
//结果为"1!2!3!4!5!6!7!!8" -
-
DOM简介
DOM全称document object model
-
文档:整个HTML文件就是一个文档
文档加载自上向下,一般给window绑定onload时间
window.onload = function{
···
} //确保网页节点已加载完毕 对象:HTML文件中的每个节点都在JS中是一个对象
-
模型:JS使用模型来表示各个对象之间的关系(DOM树
-
JS中有宿主对象document,它是window对象的属性,也就是文档对象本身
DOM中的对象又称为节点对象,共有4种常用节点分别为:
nodeName nodeType nodeValue 文档节点 #document 9 null 元素节点 标签名 1 null 属性节点 属性名 2 属性值 文本节点 #text 3 文本内容
document对象
-
常用属性:
body:该属性封装的是body元素对象的引用
documentElement:属性值为HTML元素对象(HTMLCollection
-
all:属性值为当前页面中的所有元素节点的数组
这个属性值本身为
undefined
,它的typeof
值也为undefined
URL:获取当前页面的url
domain:获取当前页面的域名部分
referer:获取是哪个页面链接跳转到当前页面,没有则返回空字符串
-
常用方法:
这些方法对于普通的DOM对象同样适用,只是DOM范围为普通DOM对象内部元素而非全局元素
-
getElementById()
- 通过ID值获取对应的节点
- IE8中不区分大小写
- IE7中会匹配表单元素的name值
-
getElementsByTagName()
- 通过标签名获取一组节点
- 返回值是一个
HTMLCollection
,即使只获取到一个节点时,也封装成HTMLCollection
返回
-
getElementsByName()
- 通过
name
的值获取一组节点 - 返回值是一个
nodelist
,与数组相似,可以使用forEach
方法,即使只获取到一个节点时,也封装成nodelist
返回
- 通过
-
getElementsByClassName()
- 通过
class
属性获取一组节点 - 返回值是一个
HTMLCollection
,即使只获取到一个节点时,也封装成HTMLCollection
返回 - 仅支持IE8以上
- 通过
-
querySlector()
- 通过CSS选择器返回一个节点,当能匹配多个节点时,返回满足匹配的第一个节点 仅支持IE7以上
-
querySlectorAll()
- 通过CSS选择器返回一组节点
- 返回值是一个
nodelist
,与数组相似,可以使用forEach
方法,即使只获取到一个节点时,也封装成nodelist
返回 - 仅支持IE7以上
HTMLCollection 支持通过索引或者字符串来查找需要的节点,在后台则分别使用它的
item()
与namedItem()
方法来获取NodeList 与
HTMLCollection
类似的一个node集合两者的值都是动态的,每次去取这些值的属性都会进行一次文档查询,因此需要尽量减少直接访问
-
事件
JS可以通过给事件绑定响应函数来使事件触发时执行相应的响应函数,响应函数会在执行事件时才会被执行,因此响应函数内部使用的变量可能会与预期不一致
var div = document.getElementByTagName("test");
for(var i = 0; i < div.length; i++){
div[i].onclick = function(){
console.log(i);
}
}
//结果永远会是div的长度的值
元素节点
元素节点拥有一个方法和属性来获取它们内部的节点,除了元素的class
属性以外,所有的属性都可以以元素节点对象属性的方式获取,class
的值需要用className
属性来获取,因为class
是js中的保留字
-
常用方法:
getElementById()
:通过ID值获取当前元素节点内部对应的节点-
getElementsByTagName()
:用来获取当前元素节点内部的特定标签的元素节点返回值是一个
HTMLCollection
,与数组相似,不能使用forEach
方法,即使只获取到一个节点时,也封装成HTMLCollection
返回 -
getElementsByName()
:通过name的值获取当前元素节点内部的一组节点返回值是一个
nodelist
,与数组相似,可以使用forEach
方法,即使只获取到一个节点时,也封装成nodelist
返回 -
getElementsByClassName()
:通过class
属性获取当前元素节点内部的一组节点返回值是一个
HTMLCollection
,与数组相似,不能使用forEach
方法,即使只获取到一个节点时,也封装成HTMLCollection
返回仅支持IE8以上
-
querySlector()
:通过CSS选择器返回当前元素节点内部的一个节点,当能匹配多个节点时,返回满足匹配的第一个节点仅支持IE7以上
-
querySlectorAll()
:通过CSS选择器返回当前元素节点内部的一组节点返回值是一个
nodelist
,与数组相似,可以使用forEach
方法,即使只获取到一个节点时,也封装成nodelist
返回仅支持IE7以上
hasChildNodes()
:返回当前节点内部是否拥有1个或多个子节点
-
常用属性:
innerHTML:获取当前元素节点中的HTML代码
innerText:获取当前元素节点中的文本
-
childNodes:获取当前元素节点中所有的子节点并以数组形式返回,按照ES标准如果当前元素节点中有空格时也会被包括在内
IE8及以下浏览器没有实现这一标准,因此只会获取到内部的元素节点
children:获取当前元素节点中的所有子元素节点
firstChild:获取当前元素节点中的第一个子节点
firstElementChild:获取当前元素节点中的第一个子元素节点, 仅支持IE8以上
lastChild:获取当前元素节点中的最后一个子节点
lastElementChild:获取当前元素节点中的最后一个子元素节点, 仅支持IE8以上
parentNode:获取当前元素节点的父节点
previousSibling:获取当前元素节点的前一个兄弟节点
previousElementSibling:获取当前元素节点的前一个兄弟元素节点, 仅支持IE8以上
nextSibling:获取当前元素节点的后一个兄弟节点
nextElementSibling:获取当前元素节点的后一个兄弟元素节点, 仅支持IE8以上
当响应函数给某个节点绑定时,这个响应函数中的
this
就是这个节点
DOM的增删改
-
常用方法:
-
createElement()
:新建一个元素节点,参数是元素节点的标签名- document.createElement("标签名");
-
createTextNode()
:新建一个文本节点,参数是文本节点的内容- document.createTextNode("文本内容");
-
appendChild()
:向一个父节点中添加一个子节点- 父节点.appendChild(子节点);
-
insertBefore()
:向一个子节点前添加一个新的节点- 父节点.insertBefore(新节点, 原节点);
-
removeChild()
:移除一个子节点- 父节点.removeChild(子节点);
-
replaceChild()
:将原节点替换成新节点- 父节点.replaceChild(新节点, 原节点);
-
cloneNode()
:返回值是一个节点的拷贝, 接受一个布尔值作为参数, true则为深度拷贝, false为浅拷贝- 节点.cloneNode(boolean)
-
normalize()
:返回一个经过一定处理后的节点, 这个过程会合并调用此方法的节点中的相邻文本节点并删除空白的文本节点 -
splitText(offset)
:将一个文本节点按照偏移量参数分割成两个兄弟节点, 返回值是后一个文本节点, 此方法只可被用于文本节点
-
-
由于许多方法都要通过父节点调用对应的方法来操作节点,因此可使用以下代码来对节点进行直接操作而不需要获取它的父节点
子节点.parentNode.removeChild(子节点);
-
对DOM的增删改操作可以用父节点的
innerHTML
的字符串操作来代替,由于是整体修改所以这个父节点包括它的子节点绑定的函数都会失效代码1:
<html>
<head>
</head>
<body>
<div>
<input type="checkbox" id="checkallbox"/>AAAAA
</div>
</body>
</html>
<script>
var input = document.createElement("input");
var checkallbox = document.getElementById("checkallbox");
input.type="checkbox";
checkallbox.parentNode.insertBefore(input, checkallbox);
</script>代码2
<html>
<head>
</head>
<body>
<div>
<input type="checkbox" id="checkallbox"/>AAAAA
</div>
</body>
</html>
<script>
var div = document.getElementsByTagName("div")[0];
div.innerHTML = "<input type='checkbox'/>" + div.innerHTML;
</script>两部分代码功能基本相同,唯一区别是如果input标签绑定了响应函数,在代码2中会失效
DOM的遍历
-
document.createNodeIterator(root, whatToShow, filter, entityReferenceExpansion)
返回值是一个
NodeIterator
对象参数一: 指定开始遍历的根节点,只能遍历body标签中的节点,其他标签会被跳过
-
参数二: 标识要访问标签元素的哪些节点,它是一个数字代码,语义化信息保存在
NodeFilter
类型中NodeFilter.SHOW_ALL 显示所有节点
NodeFilter.SHOW_ELEMENT 显示元素节点
NodeFilter.SHOW_ATTRIBUTE 显示属性节点
NodeFilter.SHOW_TEXT 显示文本节点
NodeFilter.SHOW_DOCUMENT 显示文档节点
NodeFilter.SHOW_COMMENT 显示注释节点 -
参数三: 是一个
NodeFilter
对象,或者一个返回接受或者拒绝特定标签的函数-
NodeFilter
对象是一个只有acceptNode
方法的对象,该方法是一个迭代回调函数,有一个node参数,迭代器中有几个节点则会被执行几次 - 返回值应是
NodeFilter.FILTER_ACCEPT
或者NodeFilter.FILTER_SKIP
- 通过返回值来判断是否能够访问当前回调函数中的标签元素
var filter = {
acceptNode: function(node){
return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
}
}- 这个参数也可以是一个与
acceptNode
方法相似的函数
function acceptNode(node){
return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
} -
参数四: 标识是否要扩展实体引用,在html中没有意义
NodeIterator
有两个方法nextNode()
与previousNode()
来访问迭代器中的节点刚创建好的迭代器一开始是指向一个标识根节点的指针,第一次调用
nextNode
会指向第一个子节点当越界时返回值为
null
支持IE9+和其他浏览器
-
document.createTreeWalker(root, whatToShow, filter, entityReferenceExpansion)
返回一个
TreeWalker
对象可以实现在经过过滤的root节点中任意跳跃,非常灵活
参数与上一个函数一致,唯一有区别的在于第三个参数的
Nodefilter
函数增加一个有效的返回值NodeFilter.FILTER_REJECT
此时迭代器会跳过这个节点及其后代元素而不是像
NodeFilter.FILTER_SKIP
那样单纯跳过当前节点,仍然进行深度遍历在
createNodeIterator
的第三个参数中返回NodeFilter.FILTER_REJECT
作用与NodeFilter.FILTER_SKIP
相同-
相较于
NodeIterator
对象,TreeWalker
对象多出一些重要方法:parentNode()
firstChild()
lastChild()
nextSibling()
previousSibling()
通过这些方法可以实现在
TreeWalker
对象中任意跳转到目标元素 W3C标准DOM2,但是IE不支持
-
DOM范围
可以通过范围来选择文档中的一个区域而不必考虑节点的界限(选择在后台完成,对用户是不可见的)
-
范围创建语句:document.createRange()
返回值为range对象
-
以下属性可以获取到当前范围在文档中的位置信息
startContainer:包含范围起点的节点,即起点的父节点
-
startOffset:范围起点在
startContainer
中的偏移量如果起点是文本节点,注释节点,cdata节点则值是范围起点节点距离
startContainer
需要跳过的字符串如果起点是元素节点,则值是范围起点节点在
startContainer
中的子节点索引 endContainer:包含范围终点的节点,即终点的父节点
-
endOffset:范围终点在
startContainer
中的位置值计算规则与
startOffset
相同, 表示索引时通常是起始位置加1 commonAncestorContainer:起点节点与终点节点共同的最近的那个祖先节点
-
通过以下方法可以进行选择范围操作
selectNode()
:选中传入参数的那个节点及内部节点selectNodeContents()
:选中传入参数的那个节点的内部节点-
setStartBefore(refnode)
:将范围起点设置为refnode之前,refnode就成为了范围选区的第一个节点startContainer
变成refnode的父节点,startOffset
的值变成refnode在父节点中的索引 -
setStartAfter(refnode)
将范围起点设置为refnode之后,refnode就成为了范围选区外的节点,它的下一个节点是范围选区内第一个节点
startContainer
变成refnode的父节点,startOffset
的值变成refnode在父节点中的索引加1 -
setEndBefore(refnode)
将范围终点设置为refnode之前,refnode就成为了范围选区外的节点,它的上一个节点是范围选区内最后一个节点
startContainer
变成refnode的父节点,endOffset
的值变成refnode在父节点中的索引 -
setEndAfter(refnode)
将范围终点设置为refnode之后,refnode就成为了范围选区 内的最后一个节点
startContainer
变成refnode的父节点,endOffset
的值变成refnode在父节点中的索引加1 -
setStart()
传入两个参数,第一个参数是参照节点,第二个参数是偏移量
参照节点会被当做
startContainer
,偏移量会变成startOffset
-
setEnd()
传入两个参数,第一个参数是参照节点,第二个参数是偏移量
参照节点会被当做
endContainer
,偏移量会变成endOffset
ps: 当改变范围起点到范围终点之后时, 范围终点会自动变成起点的偏移值, 同理改变范围终点到范围起点时, 范围起点也会自动变成终点的偏移值
-
创建范围之后可以使用以下方法对选中内容进行操作
-
deleteContents()
将选中的内容从文档中删除
-
extractContents()
将选中的内容从文档中提取出来并作为返回值返回
-
cloneContents()
拷贝一份选中的内容并作为返回值返回
-
insertNode()
将一个节点插入到范围的最开始处
-
surroundContents()
将节点移动到范围之外,刚好包裹此范围,并且删除节点内原有的内容
-
collapse()
可以将选中的范围进行折叠,使范围起点与终点都指向同一个位置
传入一个布尔值作参数,true表示折叠到原范围的起点,false表示折叠到原范围的终点
-
compareBoundaryPoints()
-
传入两个参数
第一个参数是需要比较哪两个点的一个常量,值可以是
Range.START_TO_START
,Range.START_TO_END,Range.END_TO_START
,Range.END_TO_END
第二个参数是需要比较的范围,如果调用这个方法的范围与传入的范围的需要比较的点是前者在前则返回-1,相同返回0,前者在后则返回1
-
-
detach()
在使用完范围后最好使用此方法来使范围从文档中分离,然后再删除引用,方便垃圾回收机制清理
-
IE8及以下的文本范围
-
创建文本范围
在
input
,button
,textarea
,body
等几个元素可以使用createTextRange
来创建文本节点 -
选取文本范围
-
findText()
传入一个字符串参数,如果找到了对应的范围则返回值为true否则为false同时让范围包围这段文本
-
moveToElementText()
传入一个DOM节点,让范围包含这个节点的文本信息与标签信息,与selectNode作用类似
-
move()
将范围折叠到指定位置
-
moveStart()
将范围的起点移动到指定位置
-
moveEnd()
将范围的终点移动到指定位置
-
expand()
将部分文本的范围变成完整文本的范围
-
这些方法都传入两个参数
第一个参数是移动单位
第二个参数是移动单位的数量
-
移动单位可以是以下字符串
character:逐个字符移动
word:逐个单词移动
sentence: 逐个句子(一系列以叹号问号句号结尾的字符)移动
textedit:移动到当前选区开始或结束的位置
-
-
修改范围内的内容
有
text
属性与pasteHTML()
方法前者改变文本,后者可以包括标签
-
折叠范围
与其他浏览器相同使用
collapse()
来折叠范围但是没有
collapsed
属性来判断是否折叠,但是可以使用boundingWidth
属性来判断范围宽度是否为0 -
比较范围
-
compareEndPoints()
用法与作用同
compareBoundaryPoints
类似第一个参数是字符串,表示需要比较哪两个点如:
StartToEnd
等格式第二个参数是待比较的范围
-
-
复制范围
-
duplicate()
作用与
cloneContents()
相同
-
操作样式
在css的属性中如果有用 - 来连接的情况,在style需要使用驼峰命名法来修改属性名从而设置或者读取对应的样式
- 获取节点样式的属性或方法
-
style
- 节点对象.style.属性值
通过这个属性能够修改和读取到节点的内联样式,当节点没有内联样式时获取到的是空字符串
如果在其他地方的css样式中设置了
!important
,那么通过js操作这个属性会失效 -
currentStyle
此属性只能在IE浏览器中使用并且是只读的,当未给某个节点设置长度值时会返回auto
- 节点对象.currentStyle.属性值
-
getComputedStyle()
此方法是
window
的方法,可以直接使用,而且也是只读的在获取width属性时当未设置具体样式的情况下,会返回节点对象实际呈现的结果而不是auto
- getComputedStyle(节点对象, 伪元素(常设置为null))[样式名]
此方法支持IE8以上以及其他浏览器
-
获取节点对象相关位置的常用属性:
clientHeight
:获取元素的视图高度,包括元素的内容高度与内边距高度,返回值是一个数字,只读, 在根标签的此属性就是指代视口大小,与此规则无关clientwidth
:获取元素的视图宽度,包括元素的内容宽度与内边距宽度,返回值是一个数字,只读, 在根标签的此属性就是指代视口大小,与此规则无关offsetHeight
:获取元素的真实高度,包括元素的内容高度,内边距高度与边框高度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读,在IE11以下浏览器中的根标签的此属性就是指代视口大小,与此规则无关offsetWidth
:获取元素的真实宽度,包括元素的内容宽度,内边距宽度与边框宽度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读,在IE11以下浏览器中的根标签的此属性就是指代视口大小,与此规则无关-
offsetParent
:获取当前元素的定位父元素,即设置了position
的最近父元素,当所有父元素都没有设置时,返回body
元素, 但是在除了火狐的浏览器中当position
设置为fixed
,返回null
在IE7包括IE7时,
position
为absolute
与relative
时返回html
,body
与html
间的margin
清除后可看做body
. 在IE7以下时当祖先元素开启hasLayout
返回最近开启的元素hasLayout相关的内容还是比较多的,现在只需有个概念,在进阶内容中会详细讲述
offsetTop
:获取当前元素相对于定位父元素的上侧偏移量(相对于offsetParent
的内边距),即使父元素自身有偏移量也不改变这个值的大小,返回值是一个数字,只读offsetLeft
:获取当前元素相对于定位父元素的左侧偏移量(相对于offsetParent
的内边距),即使父元素自身有偏移量也不改变这个值的大小,返回值是一个数字,只读scrollHeight
:获取当前元素的真实高度,包括元素的内容高度与内边距高度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读scrollWidth
:获取当前元素的真实宽度,包括元素的内容宽度与内边距宽度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读scrollTop
:获取当前元素的右侧滚动条滚动的像素,返回值是一个数字,只读scrollLeft
:获取当前元素的下侧滚动条滚动的像素,返回值是一个数字,只读
scrollHeight - scrollTop = clientHeight
可以证明滚动条滚动到最底端-
getBoundingClientRect()
这是DOM中唯一能够直接获取节点相对于视图位置的方法,且兼容性相当的好,需要熟练掌握,此处有个小案例来帮助学习这个方法
获取一个元素四个角的相对位置与高宽且这些值是基于border-box的,也就是说返回的width, height属性都包括了节点的content, padding, border的高宽
在IE7及以下没有
width
与height
属性获取节点的绝对位置可以直接让相对位置加上滚动的像素来得到
BOM
-
Window
:代表浏览器窗口并且保存浏览器的全局对象window.open
当弹窗被浏览器内置工具屏蔽时会返回null
,被工具屏蔽会报错 -
Navigator
:代表浏览器信息由于历史原因大部分属性没有意义,只剩下
userAgent
可以判断浏览器类型IE11的
userAgent
中没有IE信息必须使用"ActiveXObject" in window
来进行判断edge浏览器仍然可以使用
userAgent
中有无edge字符串来判断 -
Location
:代表浏览器地址栏信息如果直接打印
location
,则能获取到当前网址栏的信息修改
location
属性为一个完整路径或相对路径则页面会直接跳转assign()
:直接跳转到某个页面,与直接修改location
一样reload()
:用于重新加载当前页面,与刷新按钮一样,传递true
作为参数时会强制清空缓存replace()
:与assign
类似但是它不会生成历史记录,无法回退
-
History
:代表历史记录,只能前进后退length
:当次访问的历史次数,关闭浏览器时清零back()
:回到上一个页面forward()
:前往下一个页面go()
:使用整数作为参数来指定需要跳转到的页面
Screen
:代表用户当前屏幕
这些属性都保存在window
中,可以直接使用
绑定事件的简单介绍
给一个节点绑定响应函数有两种方法, 这两种方法分别被写进W3C的DOM1与DOM2的规范中
window.onclick = function(){} //DOM1
document.addEventListener('click', function(){}) //DOM2
事件对象
当给某个元素对象绑定响应函数后,浏览器在执行这个响应函数后会向这个函数自动传递一个实参,该实参封装了与此事件有关的任何数据
-
可以给响应函数添加形参来调用这个事件对象
var div = document.getElementByTagName("div")[0];
div.onclick = function(event){} -
IE与chrome浏览器也会将这个实参保存在
window.event
中,可以用来兼容IE8及以下浏览器var div = document.getElementByTagName("div")[0];
div.onclick = function(event){
event = event || window.event;
} -
浏览器的滚动条被认为是
documentElement
的scrollTop
和scrollLeft
的值因此可以使用一下代码来兼容三种浏览器
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft; -
常用属性:
clientX
返回触发此事件时鼠标在视图中的X坐标clientY
:返回触发此事件时鼠标在视图中的Y坐标pageX
:返回触发此事件时鼠标在触发此事件的元素中的X坐标,仅支持IE8以上及其他浏览器pageY
:返回触发此事件时鼠标在触发此事件的元素中的Y坐标,仅支持IE8以上及其他浏览器
IE浏览器的浏览器默认行为不能使用return false
来阻止某些浏览器默认行为如文字拖拽 在IE浏览器中可以设置obj.setCapture
来让所有的操作都被设置的obj捕获,其他对象就不会执行任何响应函数
同样可以设置document.releaseCapture
来取消事件捕获,这个可以与其他浏览器的在响应函数中return false
一起使用来达到取消浏览器默认行为的作用
return false
与event.returnValue=false
作用相同
对于其他默认行为由于IE不支持event.preventDefault
,因此可以使用一下代码做到兼容所有浏览器
event.preventDefault && event.preventDefault();
return false;
当事件由addEventListener
绑定时,不能使用return false
取消默认行为而需要event.preventDefault
,对于不支持此方法的IE,使用event.returnValue=false
事件冒泡
- 当某个元素的事件触发时,相同的事件会一层层向这个元素的父元素传递,如果不希望这个元素向外进行事件冒泡有两种方法来取消冒泡
- 是否传递是根据dom树结构来决定而不是页面上是否包裹,只要是父元素,不管是否与子元素重叠都会将子元素的事件冒泡给父元素
-
event.cancelBubble=true
不属于W3C标准,但是更方便,新版本的chrome与firefox都已经支持
-
event.stopPropogation()
W3C标准,但是IE不支持
事件委派
- 当在给节点添加新节点并且需要让这个新节点与其他兄弟节点有同样的响应函数时可以使用事件委派的功能
- 当事件触发时响应函数的形参属性
event.target
会指定实际触发此函数的节点 - 将响应函数绑定到父元素上,并且使用响应函数的形参的属性进行节点判断可以完成新增子节点不需要重新绑定响应函数的功能
<html>
<head>
<script>
window.onload = function(){
var ul = document.getElementByTagName("ul")[0];
ul[i].onclick = function(event){
//当需要添加具有相同响应函数的新节点时,可以直接指定class=a,则事件会自动触发
if(event.target.className == "a"){
···
}
};
}
</script>
</head>
<body>
<ul>
<li><a class="a" href="javascript:;">1</a></li>
<li><a class="a" href="javascript:;">2</a></li>
<li><a class="a" href="javascript:;">3</a></li>
</ul>
</body>
</html>
事件绑定
- 当对同一个节点的事件重复绑定响应函数时后绑定的函数会覆盖前绑定的函数导致前绑定的函数不会被执行
a.onclick = function(){
console.log(1);
};
a.onclick = function(){
console.log(2);
};
//结果为2
使用addEventListener
来为节点添加监听函数,响应函数可以绑定多次,并且会按顺序执行,支持IE8以上或者其他的浏览器,响应函数内部的this
是节点对象
-
解绑使用:removeEventListener
-
参数:
事件名,不带on
响应函数
布尔值,决定事件是否在捕获阶段执行,默认为
false
,在冒泡阶段执行 对象.addEventListener("xx", 响应函数, false/true)*
-
想要兼容IE8及以下浏览器时使用attachEvent
,同样可以绑定多次,但是顺序为后绑定先执行,响应函数内部的this
是window
-
解绑使用
detatchEvent
-
参数:
事件名,带on
响应函数
-
语法:
对象.addEventListener("", 响应函数)
-
-
可以定义一个
bind
函数来兼容两者-
参数:
需要绑定响应函数的节点对象
事件名,不带on
响应函数
function bind(obj, eventStr, func){
obj.addEventListener ? obj.addEventListener(eventStr, func) : obj.attachEvent("on" + eventStr, function(){func.call(obj)});
} -
事件传播
浏览器在实现时对于事件传播微软与网景有不同的理解方式
--微软认为事件由子元素向父元素传播
--网景认为事件由父元素向子元素传播
W3C标准实现时参考两种方法给出了事件执行的阶段:
-
捕获阶段
事件先从父元素向子元素传递
-
目标阶段
捕获阶段完成后事件在目标阶段执行
-
冒泡阶段
然后事件再从子元素向父元素传递
当需要设置某个事件在捕获阶段执行时,将addEventListener()
的第三个参数设置为true
即可,IE8及以下浏览器没有实现捕获阶段所以没有办法设置
需要兼容的事件
-
onmousewheel
当鼠标滚轮滑动时触发此事件,事件结果由
event.wheelDelta
返回向上滚时返回120,向下滚时返回-120,可以只关注正负,同时不被firefox支持想在firefox中监听此事件需要使用
addEventListener("DOMMouseScroll", func)
来监听鼠标滚轮的操作,事件结果由event.detail
返回,向上滚动时返回-3,向下滚动时返回3当浏览器中有滚动条时鼠标滚动操作会默认滚动滚动条,在IE与chrome中可以使用
return false
来取消默认行为,firefox需要使用preventDefault
来取消obj.onmousewheel = function(event){
event = event || window.event;
if(event.wheelDelta > 0 || event.detail <0){
//向上滚动
}else{
//向下滚动
}
};
test.addEventListener && test.addEventListener("DOMMouseScroll", test.onmousewheel, false);ps: DOM3标准中定义了wheelEvent来兼容所有浏览器, 适用于chrome31+, firefox17+, IE9+
-
键盘事件
只有可以获取焦点的事件或者让
document
绑定键盘事件才可以触发-
onkeydown
当一直按着时,事件会被连续触发,当连续触发的时候,第一次和第二次间隔会稍微长一些后面的才会快速触发,为了防止误操作
在文本框键入字母属于文本框的默认行为
- 事件属性:
- event.altKey
- event.ctrlKey
- event.shiftKey
当这三个键被按下时它们的值会被赋值为true否则为false
- 事件属性:
mouseenter 鼠标移入
mouseleave 鼠标移出
mouseover 鼠标移入
mouseout 鼠标移出
以上四个事件触发机制: 当鼠标移动至绑定监听器的元素或者子元素时就会被触发
区别: 前两者不会冒泡后两者会
- contextmenu 上下文菜单事件,可以通过阻止默认行为来自定义上下文菜单
- beforeunload 通常在切换页面时触发
- DOMContextLoad 在DOM树渲染完成后触发,不管CSS,JS文件是否渲染完毕
-
事件模拟
可以运行在普通浏览器, 还包括IE10及以上
API:
-
document.createEvent(eventname)
- 传入一个字符串当做参数,这个字符串在DOM2与DOM3标准中有不同的形式,DOM3中将复数变成单数,建议不要再使用DOM2的标准
- UIEvents 一般化的UI事件,鼠标与键盘事件都继承自此事件,在DOM3中是UIEvent
- MouseEvents 鼠标事件,在DOM3中是MouseEvent
- MutationEvents 一般化的DOM变动事件,在DOM3中是MutationEvent
- HTMLEvents 一般化的HTML事件,没有对应的DOM3事件
在DOM2中没有键盘事件,但是在DOM3中实现了
KeyboardEvent
返回值是一个对应的
event
对象,根据不同的事件子类有不同的初始化方法以
MouseEvent
为例,初始化方法为initMouseEvent
,传入参数与事件类型有关,详细内容需要参考mdn文档在DOM3中还定义了自定义事件
CustomEvent
,返回的对象通过initCustomEvent
初始化 - 传入一个字符串当做参数,这个字符串在DOM2与DOM3标准中有不同的形式,DOM3中将复数变成单数,建议不要再使用DOM2的标准
-
element.dispatchEvent(event)
传入一个事件对象
用来触发事件对象定义的事件
运行在IE9及以下
API:
-
document.createEventObject()
没有参数 返回值是一个
event
对象,event
的所有属性与方法都需要自定义,没有预设参数 element.fireEvent(eventname, event)
第一个参数是事件名,如onclick
等 第二个参数是自定义的event
对象
DOM4标准中已经将各个事件类型定义成构造函数, 通过直接实例化即可得到相应的事件对象
表单脚本
-
表单对应的是
HTMLFormElement
类型,继承自HTMLElement
,并且有一些额外的属性和方法acceptCharset
: 服务器能够处理的字符集,等价于HTML中的accpet-charset
特性action
:接受请求的url,等同于表单的actionelements
:表单中所有控件的集合(HTMLCollection
)enctype
: 请求的编码类型,等同于HTML中的enctype
length
:表单中控件的数量method
:等价于HTML中的方法,通常是get或postname
:表单的名称reset()
:将所有表单域重置为默认值submit()
:提交表单target
:用于发送请求和接收相应的窗口名称,等价于HTML中的target
可以通过常规的DOM操作来获取表单元素,也可以通过document.forms
来获取一个页面中所有表单的HTMLCollection
-
提交表单
当表单提交时会触发submit事件
-
重置表单
让表单重置时会触发reset事件,在体验上最好不要主动触发重置事件,会严重影响用户体验,必要时使用回退到上一个页面代替
-
表单字段
可以通过常规的DOM操作来获取表单内控件,也可以使用表单内属性elements返回一个表单控件的集合
这个集合是一个
HTMLFormControlsCollection
,它继承自HTMLCollection
并重新封装了namedItem
方法当通过控件的
name
来访问时,如document.forms[0].elements['color']
, 它的返回值是一个NodeList
也可以通过访问表单的属性来访问,如
document.forms[0]['color']
,但这是向后兼容的方式,最好不要使用 -
表单控件的共有属性
-
除了
fieldset
以外所有表单控件都公用一组属性disabled 布尔值,表示当前控件是否被禁用
form 表示指向当前表单的指针
name 表示当前控件的名称
readOnly 布尔值,表示是否只读
tabIndex 表示tab键切换的序号
type 表示控件类型,在
input
中就是type
指定的类型,在button
中默认是submit
,在单选列表中是select-one
,在多选列表中是select-mltiple
value 表示将会提交给服务器的值
-
-
表单控件的共有方法
-
每个表单控件都拥有两个方法
focus 使当前控件获取焦点
blur 使当前控件失去焦点
当对隐藏的控件调用这些方法时会抛出错误
-
-
表单控件的共有事件
-
除了支持鼠标,键盘,更改,HTML事件外所有控件都支持三个事件
change 对于
input
与textarea
来说,失去焦点且值改变时触发,对select
来说,切换就触发blur 与change事件的先后顺序不定,不能提前假定某个事件一定先触发
focus 获得焦点时触发
-
文本框脚本
在表单中有两种文本框
text
与textarea
,两者特性大致上是相同的,但是仍然有些重要的区别text
可以设置maxlength
来指定文本框最大能够输入的字符数量,size指定能够显示的最大字符数量即文本框大小,value
指定文本初始值textarea
的文本初始值只能在<textarea></textarea>
之间设定,文本框大小通过rows
和cols
来设置,不能设置最多能接受的字符数量-
对于这两种文本框都最好使用
value
值来设定文本内容而不要使用标准DOM方法:用
setAttribute
设置input
的value
获取第一个子节点修改textarea
的value
两个文本框都支持
select
方法,可以用来全选文本相对应的两个文本框都会触发
select
事件,除了IE8及以下的浏览器会在选中并释放鼠标触发,IE在选中时就触发HTML5中还支持部分选中文本的api:
setSelectionRange(start, end)
接收两个参数表示偏移量在IE8及以下想要部分选中需要使用文本范围的技术
-
剪切板操作
-
clipboardData对象
在IE中是
window
属性,其他浏览器中是event
的属性并且只有触发剪切板相关事件才能访问 -
剪切板事件
beforecopy
copy
beforepaste
paste
beforecut
cut
其中before相关的事件在IE中只要显示了文本相关的上下文菜单都会被触发,在其他浏览器中是在copy,paste,cut等事件触发前触发
-
剪切板方法
-
setData()
第一个参数在普通浏览器中是MIME类型但在IE是text或URL
第二个参数是想要复制进剪切板的内容
-
getData()
第一个参数在普通浏览器中是MIME类型但在IE是
text
或URL
,但是对普通浏览器使用text
也会被识别成text/plain
-
clearData()
清除剪切板中的数据
-
-
选择框脚本
-
通过
select
元素创建的是选择框,除了表单字段中列举的属性和方法它还具有以下属性和方法:add(new, ref)
向控件中插入new,位置在ref之前multiple
布尔值,表示表单是否允许多选options
控件中所有option
的HTMLCollection
remove
移除给定位置的选项selectedIndex
可读写的number类型,基于0的选中项的索引,没有选中项则为-1,对于支持多选的只保留第一个选中项的索引,被赋值是指定项被选中其他项会取消选中size
选择框中可见的行数,与等价于HTML中的size
属性 -
每个
option
都有以下属性:index
当前选项在option
中的索引label
当前选项的label
selected
可读写布尔值,当前选项是否被选中,对单选text
文本节点的内容value
value
值
JSON
全称为javascript object notation
JSON是一个特定格式的字符串,几乎所有编程语言都能识别
能够转换成每个编程语言的对象,主要用于数据交互
JSON与js对象字面量格式相同但是属性和值必须加引号
-
JSON分类:
对象
数组
-
JSON中可以使用的值:
数字
字符串(当JSON没有使用对象自面量格式而是简单字符串格式时不能使用)
布尔值
null
对象
数组
JSON.parse("1") //1
JSON.parse("true") //true
JSON.parse("null") //null
JSON.parse("{}") //{}
JSON.parse("[]") //[] -
JSON ---> js对象
JSON.parse()
使用
JSON
对象作为参数,返回Javascript对象- 第一个参数是JSON字符串
- 第二个参数是还原函数,有两个形参分别是key跟value,对于每个key,函数返回值就是最终结果的每个键值对中的值
兼容IE7及以下使用eval来代替不能使用的JSON.parse(),或者引入JSON2库
eval()
如果执行的字符串中有
{}
,则会被当做代码块,如果不希望被当做代码块被解析,在{}前后使用()
由于效率与安全问题,尽量不要使用 -
js对象 ---> JSON
JSON.stringify()
使用Javascript对象作为参数,返回
JSON
- 第一个参数是一个
JSON
对象 - 第二个参数是个过滤数组或者函数,函数的两个形参是key, value, 对于每个key,函数返回值就是最终键值对的值
- 第三个参数是个数字,表示缩进的空格数
- 第一个参数是一个
-
toJSON()
每个对象都可以创建
toJSON
方法,在对这个对象使用JSON.stringify
会先调用这个方法获取的返回值再对此进行操作 -
JSON.stringify
的处理流程如果要真正弄清楚如何将JS对象转化成指定的JSON字符串需要了解
JSON.stringify
的处理流程- 如果第一个参数有
toJSON
方法就先调用,否则不调用 - 将toJSON的返回值或者第一个参数当做下一步的输入值
- 如果有第二个参数就用来过滤上一步的输出值,如果没有就将结果当做下一步的输入值
- 如果有第三个参数则按照这个值格式化上一步的输出值没有直接将最后的值返回
- 如果第一个参数有
错误处理机制
try-catch语句
try{
}catch(err){
}finally{
}
finally
子语句是可选的,且必定执行,无论catch
语句有没有执行
当有finally
存在时,try
与catch
中的return
会失效
-
错误类型
-
Error
基本错误类型,其他错误类型都继承自该类型
-
EvalError
当没有把eval当做函数调用时会抛出
EvalError
错误 -
RangeError
当超出数组范围或者值不合法时会抛出
RangeError
-
ReferrenceError
当对象找不到时会抛出
ReferenceError
-
SyntaxError
当eval中执行的代码有语法错误时会抛出
SyntaxError
,如果在外部有语法错误会直接停止执行一般不会抛出此错误 -
TypeError
当实际变量类型与预期不一致时会抛出
TypeError
, 如让一个新创建的普通对象调用数组中的forEach
方法时 -
URLError
当使用
decodeURL
和encodeURL
中的url格式错误时会抛出URLError
-
-
与
try-catch
相配合的还有throw
操作符当遇到
throw
操作符时代码会停止运行,只有当try-catch
捕获到时才会继续运行 抛出错误类型的实例时能够更加真实的模拟浏览器错误
自定义错误
通过原型链继承可以自定义错误类型,只要继承自error
的对象都会被浏览器当做错误对象处理
当自定义错误时需要为新错误类型指定name
与message
属性
try {
var udError = new Error();
udError.name = "undefined Error";
udError.message = "throw undefined Error";
throw udError;
} catch(e) {
console.log(e) //undefined Error: throw undefined Error
}
参考链接:感谢dalao的笔记