js语言学习
1.基本概念:
1.js是区分大小写的
2.标识符命名规则:
第一个字符必须是一个字母、下划线(_)或一个美元符号($);
其他字符可以是字母、下划线、美元符号或数字。
按照惯例,ECMAScript 标识符采用驼峰大小写格式,也就是第一个字母小写,剩下的每个单词的 首字母大写
3.注释:
// 单行注释
多行注释:/*
*
*
*/
4.严格模式:
在严格模式下,一些未声明的变量和某些不安全的操作也会抛出错误
-
在整个脚本顶部添加代码如下:
"use strict";
-
也可以在函数内使用,是其函数在严格模式下执行:
function dosomething(){ "use strict"; //函数体 }
5.语句:
- 以分号结尾,但不是必须的。
- 多使用代码块
6.变量:
-
声明:
var a="hi"; //可以进行初始化 a=100; //有效,但不推荐使用(通过赋值来改变数据类型) var b,c; //也可以一条语句多次定义 let a; //与var不同,let声明的变量的范围时块作用域
-
注意:
-
在一个函数中用定义 var 来定义一个变量,那么他就是一个局部变量。也可以省略 var 从而创建一个全局变量。
function test(){ message = "hi"; //全局变量 }
在严格模式下,未经声明的变量会导致出现ReferenceError的错误
在严格模式下,不能定义名为 eval 或 arguments的变量,否则会导致语法错误
-
-
const 声明:
const a = 3.156 // const用于声明常量
7.数据类型:
1.typeof 操作符:
作用:检测给定变量的数据类型
语法: typeof + 变量名
返回值:"undefined"——如果这个值未定义;
"boolean"——如果这个值是布尔值;
"string"——如果这个值是字符串;
"number"——如果这个值是数值;
"object"——如果这个值是对象或 null;
"function"——如果这个值是函数。
2.undefined类型:
- 只有一个特殊值:
undefined
且未经初始化的变量都会默认为undefined(未定义)
3.Null 类型:
- 只有一个值:
null
表示为空对象指针,需要通过给变量赋值null
才可以与undefined
不同
4.Boolean类型:
有
true和false
两种字面值(区分大小写)虽然 Boolean 类型的字面值只有两个,但 ECMAScript 中所有类型的值都有与这两个 Boolean 值 等价的值。要将一个值转换为其对应的 Boolean 值,可以调用转型函数 Boolean()如下图所示
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | ""(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0和NaN(参见本章后面有关NaN的内容) |
Object | 任何对象 | null |
Undefined | 无 | undefined |
5.Number 类型:
- 对于整数来说:
- 对于八进制和十六进制的前面分别要加0或0x
- 对于浮点数值来说:
- 如果小数点后面没有数字,浏览器会自动转换为整数
- 对于极大或极小的数值,可以用e表示法(科学计数法)表示。e是不区分大小写的
- 浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数
- 永远不 要测试某个特定的浮点数值 即
a+b==0.3 //不要这样做
- 数值范围:5e-324~1.7976931348623157e+308(如果某次计算的 结果得到了一个超出 JavaScript 数值范围的值,那么这个数值将被自动转换成特殊的 Infinity 值)
- NaN (非数值):
- 任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaN
- ,NaN 与任何值都不相等,包括 NaN
- Number()函数的转换规则如下。
- 如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
- 如果是数字值,只是简单的传入和返回
- 如果是 null 值,返回 0
- 如果是 undefined,返回 NaN
- 如果是字符串,遵循下列规则:
- 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1" 会变成 1,"123"会变成 123,而"011"会变成 11(注意:前导的零被忽略了)
- 如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样,也会忽 略前导零)
- 如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整 数值
- 如果字符串是空的(不包含任何字符),则将其转换为 0
- 如果字符串中包含除上述格式之外的字符,则将其转换为 NaN
- 如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换 的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符 串值
- 由于 Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是 parseInt()函数。parseInt()函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字 符串前面的空格,直至找到第一个非空格字符。如果第一个字符不是数字字符或者负号,parseInt() 就会返回 NaN;也就是说,用 parseInt()转换空字符串会返回 NaN(Number()对空字符返回 0)。如 果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了 一个非数字字符。例如,"1234blue"会被转换为 1234,因为"blue"会被完全忽略。类似地,"22.5" 会被转换为 22,因为小数点并不是有效的数字字符。
6.string类型(字符串类型):
字符串可以由双 引号(")或单引号(')表示。不过,以双引号开头的字符串也必须以双引号结尾,而以单引号开头的字符串必须以单引号结尾。
-
转义序列:
字面量 含义 \n 换行 \t 制表 \b 空格 \r 回车 \f 进纸 \\
斜杠 \'
单引号('),在用单引号表示的字符串中使用。例如:'He said, 'hey.'' \"
双引号("),在用双引号表示的字符串中使用。例如:"He said, "hey."" \ xnn 以十六进制代码nn表示的一个字符(其中n为0~F)。例如,\x41表示"A" \ unnnn 以十六进制代码nnnn表示的一个Unicode字符(其中n为0~F)。例如,\u03a3表示希腊字符Σ -
转换为字符串:
- toString()方法
- String()
7.Object 类型:
ECMAScript 中的对象其实就是一组数据和功能的集合。
1.创建方法:
//第一种方式:
var a= new Object;
a.neme=lihua;
//第二种方式
var a= {name:lihua};
2.添加属性:
语法:
- 对象.属性名=属性值,例如:
obj.name=123;
- 对象["属性名"]=属性值,例如:
obj[name]=123;
3.查寻属性值:
语法:对象.属性;
3.更改属性值:
语法:对象.属性=新值;
4.删除属性:
语法:delete 对象.属性名
5.in运算符:
语法:"属性名" in 对象
作用:查询对象中是否含有该属性。如果有则为ture,没有则false。
注意事项:
1.对于对象的属性名一般不强制要求遵循标识符规范(但最好遵循方便可读)
2.如果要用到特殊的属性名一般采用添加属性的语法2
3.使用[]这种形式去操作属性更加灵活。
4.[]可以直接传递一个变量,这样变量值时多少就会读取那个属性
- 例如:
obi["b"]=546;
var c="b"
console.log(obj[c]);
6.js的对象的属性值,可以是任意数据类型,甚至可以是一个对象,还可以时函数
例如:
var obj=new Object();
var obj2=new Object();
obj.name=123;
obj.text=obj2;
7.枚举对象属性:
//for..in
let a={name:'lihua',age:18,}
for(let i in a){
console.log(i)
}
8.用工厂方式创建对象(批量生产对象)
function creatObjest(){
let obj=new Object;
for(let i=0;i<arguments.length;i++){
let attributes='attributes'+i;
obj[attributes]=arguments[i];
}
return obj;
}
let jj=creatObjest(1,2,3);
console.log(jj)
8.语句:
1.if :
if(条件){
//语句
}
2.do-while:
do{
//语句
}while(条件);
3.while:
while(条件){
//语句
}
4.for:
for(var a=0;a<10'a++){
//语句
}
5.for-in
- for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性
// 枚举对象属性
var b={
name:"lihua"
age:18
}
for(const a in abdns){
console.log(b);
}
如果 for-in 循环要迭代的变量是 null 或 undefined,则不执行循环体。
6.for-of:
- for…of循环遍历所有数据结构的统一的方法(但无法枚举对象)
var b=["dhjkah",1,"66"]
for(const a of b){
cobsole.log(a);
}
7.label:
- 使用 label 语句可以在代码中添加标签,以便将来使用
语法:label(可以任意起名字):语句
start: for (var i=0; i < count; i++) {
alert(i);
}
8.break和continue:
break 和 continue 语句用于在循环中精确地控制代码的执行。其中,break 语句会立即退出循环, 强制继续执行循环后面的语句。而 continue 语句虽然也是立即退出循环,但退出循环后会从循环的顶 部继续执行
-
break 和 continue 语句都可以与 label 语句联合使用,从而返回代码中特定的位置.
// break var a,b,c=0; outside:for(a=0;a<10;a++){ for(b=0;b<10;b++){ if(a==5&&b==5){ break outside; //跳出整个循环,c的最终结果是55 } c++; } } // continue var a,b,c=0; outside:for(a=0;a<10;a++){ for(b=0;b<10;b++){ if(a==9&&b==9){ continue outside; //跳出内部循环,c的值为95 } c++; } }
9.with:
- with 语句的作用是将代码的作用域设置到一个特定的对象中.
var a={name:"lihua",age:18};
var b=a.name;
var c=a.age;
// 等效为:
var a={name:"lihua",age:18};
with(a){
var b=name;
var c=age;
}
- 在严格模式下不允许使用with语句,否则将视为语法错误
- 由于大量使用 with 语句会导致性能下降,同时也会给调试代码造成困难,因此 在开发大型应用程序时,不建议使用 with 语句。
10.switch:
1.语法介绍:
var i=100;
switch(i){
case 1:
alert("hh");
break;
case 2:
alert("hi");
break;
case 100:
alert("oo");
break;
default:
alert("gg")
}
- 通过为每个 case 后面都添加一个 break 语句,就可以避免同时执行多个 case 代码的情况。假如确 实需要混合几种情形,不要忘了在代码中添加注释,说明你是有意省略了 break 关键字
- switch 语句中使用任何数据类型(在很多其他语言中只能使用数值),无论是字符串,还是对象都没有 问题。其次,每个 case 的值不一定是常量,可以是变量,甚至是表达式。
switch("hi oo"){
case 1:
alert("hh");
break;
case "hi "+"oo":
alert("hi");
break;
case 100:
alert("oo");
break;
}
- switch 语句在比较值时使用的是全等操作符,因此不会发生类型转换(例如, 字符串"10"不等于数值 10)。
9.函数:
1.声明:
var a=100,b=20;
// 用function声明函数
function doingsomething(c,d){
alert(c+d);
}
// 用函数名调用
doingsomething(a,b);
ECMAScript 中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过 return 语句后跟要返回的值来实现返回值
函数会在执行完 return 语句之后停止并立即退出。因此,位于 return 语句之后的任何代码 都永远不会执行
-
严格模式对函数有一些限制:
- 不能把函数命名为 eval 或 arguments;
- 不能把参数命名为 eval 或 arguments;
- 不能出现两个命名参数同名的情况。
-
rest 获取除已定义之外的参数
function a(x...rest){ //语句 }
- rest 前面一定要加...且一定要放在函数定义参数的最后。
2.参数:
特点:ECMAScript 函数不介意传递进 来多少个参数,也不在乎传进来参数是什么数据类型
-
原因: ECMAScript 中的参数在内部是用一个数组来表示的。函数接收 到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任 何元素,无所谓;如果包含多个元素,也没有问题。实际上,在函数体内可以通过 arguments 对象来 访问这个参数数组,从而获取传递给函数的每一个参数。
var a=100,b=20; function doingsomething(c,d){ alert(c+d);//c+d也可以写成arguments[0]+arguments[1] } doingsomething(a,b);
- 第一个参数是 arguments[0],第二个参数是 argumetns[1],以此类推
- 通过访问 arguments 对象的 length 属性可以获知有多少个参数传递给了函数。开发人员可以利用这一点让 函数能够接收任意个参数并分别实现适当的功能
- arguments 对象可以与命名参数一起使用
- 关于 arguments 的行为,还有一点比较有意思。那就是它的值永远与对应命名参数的值保持同步
- ECMAScript 中的所有参数传递的都是值,不可能通过引用传递参数。
3.没有重载:
- 原因:ECMAScirpt 函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可 能做到的
- 如果在 ECMAScript 中定义了两个名字相同的函数,则该名字只属于后定义的函数。
4.立即执行函数:
- 立即执行函数,立即被调用
- 立即执行函数只会调用一次
- 还可以传参数进行计算
(function(){
console.log(111);
})()
5.this
- 解析器在调用函数每次都会向函数内部传递一个隐含的参数
- 这个隐藏的参数就是this,this指向一个对象
- 这个对象我们称为函数执行的上下文对象
- 根据函数调用方式的不同,this会指向不同的对象
- 以函数的形式调用时,this永远都是window
- 以方法的形式调用时,this就是调用方法的那个对象
6.构造函数
-
构造函数就是一个普通的函数,创建方式和普通的函数没有区别,
不同的是构造函数首字母普遍大写
-
构造函数和普通函数的区别就是调用方式不同
普通方式是直接调用,构造函数需要使用关键字new调用
function Person(){ //语句 } let a=new Person() //调用构造函数
-
构造函数执行流程:
- 立刻创建一个新的对象
- 将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
- 逐行执行函数中代码
- 将新建的对象作为返回值返回
-
构造函数出现的问题
function Person(name,age){ this.name=name; this.age=age; this.sayName=function(){ alert('hello ,我是'+name); }; } let a=new Person('李华',18); a.sayName(); let b=new Person('小米',19) console.log(a.sayName==b.sayName); //false
-
因为构造函数每执行一次就会创建一个新的方法,也就是构造函数每执行一次会就会创建一个新的sayName方法,因此在执行10000次后,sayName方法10000次。而这是没有必要的。会造成内存空间的过渡使用
因此,我们可以将方法写到外面
function Person(name,age){ this.name=name; this.age=age; this.sayName=fun() } function fun(){ alert('hello ,我是'+name); };
-
2.变量,作用域和内存问题
1.基本类型和引用类型的值
CMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。基本数据类型:Undefined、Null、Boolean、Number 和 String。引用类型的值是保存在内存的对象,由于js不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。**在操作对象时,实际上是在操作对象的引用而不是实际的对象**。 为此,引用类型的值是按引用访问的。换句话说,就是对于基本数据类型来说,js的变量是直接储其真实值的,而对于引用类型来说,js的变量则存储的是对象的内存地址。
1.动态属性
我们只能给引用类型值动态的添加属性,而不能给基本类型的值添加
2.复制变量的值
对于基本类型来说,当一个变量向另一个变量复制基本类型时,这两个变量是独立的。
对于引用类型来说,当一个变量向另一个变量复制引用类型时,这两个变量都是指向同一个对象的,并不是独立的
// 基本类型
var a=100;
var b=a; //a和b是相互独立的,对于b的运算并不会影响a
// 引用类型
var a=new Objest
var b=a; //这里对于b的值来说,他就像一个实际的指针
b.name="lihua"
alert("a.name");// 此时显示 lihua
3.传递参数
ECMAScript 中所有函数的参数都是按**值**传递的.**把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样**.在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量。**可以把 ECMAScript 函数的参数想象成局部变量**
4.检测类型
typeof操作符:检测基本数据类型
-
instanceof操作符:检测引用数据类型
var a=new Object; console.log(a instanceof Object); //检测a是否是引用类型
2.执行环境及作用域
当代码在一个环境中执行时,会创建变量对象的一个**作用域链**(scope chain)。作用域链的用途,**是保证对执行环境有权访问的所有变量和函数的有序访问**。**作用域链的前端,始终都是当前执行的代码所在环境的变量对象**。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。 标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终**从作用域链的前端开始, 然后逐级地向后回溯**,直至找到标识符为止(如果找不到标识符,通常会导致错误发生。
例子:
var color = "blue";
function changeColor() {
var anotherColor = "red";
function swapColors() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、anotherColor 和 tempColor
}
// 这里可以访问 color 和 anotherColor,但不能访问 tempColor
swapColors();
}
// 这里只能访问 color
changeColor();
他的作用域链图:
内部环境可以通过作用域链访问所有的外部环境,但 外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性、有次序的。函数参数也被当作变量来对待,因此其访问规则与执行环境中的其他变量相同。
1.延长作用域链
- try-catch语句的catch
- with 语句
2.没有块级作用域
if(true){
var color ="red";
}
alert(color); //显示red,他并不会因为
- 声明变量:使用 var 声明的变量会自动被添加到最接近的环境中。如果初始化变量时没有使用 var 声明,该变量会自 动被添加到全局环境
- 查询标识符:从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符
3. 垃圾收集
- 标记清除:是目前最主流的垃圾算法
- 引用清楚:当代码出现循环引用时,该算法会导致问题。目前,JavaScript 引擎不在使用该算法
- 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效地回 收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用
3.基本引用类型
1.Date
1.定义:
-
Date.parse()
let a=new Date(Date.parse("7/7/2020")); // 月/日/年 let b=new Date(Date.parse("May 7,2020")); //“月名 日, 年 let c=new Date(Date.parse("Tue May 23 2019 00:00:00 GMT-0700"));/*周几 月名 日 年 时:分:秒 时区*/ let d=new Date("May 7,2020") //与变量d等价
-
Date.UTC()
let y2k = new Date(Date.UTC(2000, 0)); let allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
- Date.UTC()方法也返回日期的毫秒表示,但使用的是跟 Date.parse()不同的信息来生成这个值。 传给 Date.UTC()的参数是年、零起点月数(1 月是 0,2 月是 1,以此类推)、日(131)、时(023)、 分、秒和毫秒。这些参数中,只有前两个(年和月)是必需的。如果不提供日,那么默认为 1 日。其他 参数的默认值都是 0。
- Date.UTC()也会被 Date 构造函数隐式调用,但有一个区别:这种情况 下创建的是本地日期,不是 GMT 日期
-
Date.now():返回表示方法执行时日期和时间的毫秒数
// 起始时间 let start=Date.now; // 调用函数 doSomething(); // 结束时间 let stop=Date.now; result = stop - start;
2.继承方式
与其他类型一样,Date 类型重写了 toLocaleString()、toString()和 valueOf()方法。但与 其他类型不同,重写后这些方法的返回值不一样
3.日期格式化的方法
toDateString()显示日期中的周几、月、日、年(格式特定于实现);
toTimeString()显示日期中的时、分、秒和时区(格式特定于实现);
toLocaleDateString()显示日期中的周几、月、日、年(格式特定于实现和地区);
toLocaleTimeString()显示日期中的时、分、秒(格式特定于实现和地区);
toUTCString()显示完整的 UTC 日期(格式特定于实现)
4.日期/时间组件方法
方法的使用:
let a=new Date();
console.log(a.getDate());
2.RegExp
1.声明
let expression = /pattern/flags;
这个正则表达式的 pattern(模式)可以是任何简单或复杂的正则表达式,包括字符类、限定符、 分组、向前查找和反向引用。每个正则表达式可以带零个或多个 flags(标记),用于控制正则表达式 的行为
g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
m:多行模式,表示查找到一行文本末尾时会继续查找。
y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
u:Unicode 模式,启用 Unicode 匹配。
-
s:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)
// 匹配字符串中的所有"at" let pattern1 = /at/g; // 匹配第一个"bat"或"cat",忽略大小写 let pattern2 = /[bc]at/i; // 匹配所有以"at"结尾的三字符组合,忽略大小写 let pattern3 = /.at/gi;
与其他语言中的正则表达式类似,所有元字符在模式中也必须转义,且必须使用反斜杠
\
来转义-
任何使用字面量定义的正则表达式也可 以通过构造函数来创建
// 匹配第一个"bat"或"cat",忽略大小写 let a=/[bc]at/i // 第二中方法 let a=new RegExp("[bc]at","i");
- 注意,RegExp 构造函数的两个参数都是字符串。因为 RegExp 的模式参数是字符串,所以在某些情况下需要二次转义所有元字符都必须二次转 义,包括转义字符序列,如\n(\转义后的字符串是\,在正则表达式字符串中则要写成\\)
-
使用 RegExp 也可以基于已有的正则表达式实例,并可选择性地修改它们的标记
let a=new RegExp("[bc]at","i"); console.log(a) ///[bc]at/i let c=new RegExp(a,"g"); console.log(c); ///[bc]at/g
2.RegExp 实例属性
global:布尔值,表示是否设置了 g 标记。
ignoreCase:布尔值,表示是否设置了 i 标记。
unicode:布尔值,表示是否设置了 u 标记。
sticky:布尔值,表示是否设置了 y 标记。
lastIndex:整数,表示在源字符串中下一次搜索的开始位置,始终从 0 开始。
multiline:布尔值,表示是否设置了 m 标记。
dotAll:布尔值,表示是否设置了 s 标记。
source:正则表达式的字面量字符串(不是传给构造函数的模式字符串),没有开头和结尾的 斜杠。
flags:正则表达式的标记字符串。始终以字面量而非传入构造函数的字符串模式形式返回(没 有前后斜杠)。
-
简单的使用
let pattern1 = /\[bc\]at/i; console.log(pattern1.global); // false console.log(pattern1.ignoreCase); // true console.log(pattern1.multiline); // false console.log(pattern1.lastIndex); // 0 console.log(pattern1.source); // "\[bc\]at" console.log(pattern1.flags); // "i"
3.RegExp 实例方法
- RegExp 实例的主要方法是 exec(),主要用于配合捕获组使用。这个方法只接收一个参数,即要应 用模式的字符串。如果找到了匹配项,则返回包含第一个匹配信息的数组;如果没找到匹配项,则返回 null。index 是字符串中匹配模式的起始位置,input 是要查找的字符串。
let a=/[bc]at/i;
let b="nat bat cat";
let c=a.exec(b);
console.log(c);//["bat", index: 4, input: "nat bat cat", groups: undefined]
console.log(c.index) // 4
console.log(c[0]); //bat
console.log(c.input); //nat bat cat
-
如果在这个模式上设置了 g 标记,则每次调用 exec()都会在字符串中向前搜索下一个匹配项,如 下面的例子所示
let a=/[bc]at/g; let b="nat bat cat"; let c=a.exec(b); console.log(c);//["bat", index: 4, input: "nat bat cat", groups: undefined] console.log(c.index) // 4 console.log(c[0]); //bat console.log(c.input); //nat bat cat c = a.exec(b); console.log(c);//["cat", index: 8, input: "nat bat cat", groups: undefined] console.log(c.index)// 8 console.log(c[0]);//cat console.log(c.input);//nat bat cat
-
如果模式设置了粘附标记 y,则每次调用 exec()就只会在 lastIndex 的位置上寻找匹配项。粘附 标记覆盖全局标记
let text = "cat, bat, sat, fat"; let pattern = /.at/y; let matches = pattern.exec(text); console.log(matches.index); // 0 console.log(matches[0]); // cat console.log(pattern.lastIndex); // 3 // 以索引 3 对应的字符开头找不到匹配项,因此 exec()返回 null // exec()没找到匹配项,于是将 lastIndex 设置为 0 matches = pattern.exec(text); console.log(matches); // null console.log(pattern.lastIndex); // 0 // 向前设置 lastIndex 可以让粘附的模式通过 exec()找到下一个匹配项: pattern.lastIndex = 5; matches = pattern.exec(text); console.log(matches.index); // 5 console.log(matches[0]); // bat console.log(pattern.lastIndex); // 8
-
正则表达式的另一个方法是 test(),接收一个字符串参数。如果输入的文本与模式匹配,则参数 返回 true,否则返回 false
let a = /[bc]at/g; let b = "nat bat cat"; c = a.test(b); console.log(c); //true
4.RegExp 构造函数属性
RegExp 构造函数本身也有几个属性。(在其他语言中,这种属性被称为静态属性。)这些属性适用 于作用域中的所有正则表达式,而且会根据最后执行的正则表达式操作而变化。这些属性还有一个特点,就是可以通过两种不同的方式访问它们。换句话说,每个属性都有一个全名和一个简写。下表列出了 RegExp 构造函数的属性
例如:
let text = "this has been a short summer";
let pattern = /(.)hort/g;
if (pattern.test(text)) {
console.log(RegExp.input); // this has been a short summer
console.log(RegExp.leftContext); // this has been a
console.log(RegExp.rightContext); // summer
console.log(RegExp.lastMatch); // short
console.log(RegExp.lastParen); // s
}
- input 属性中包含原始的字符串。
- leftConext 属性包含原始字符串中"short"之前的内容
- rightContext 属性包含"short" 之后的内容。
- lastMatch 属性包含匹配整个正则表达式的上一个字符串,即"short"。
- lastParen 属性包含捕获组的上一次匹配,即"s"。
这些属性名也可以替换成简写形式,只不过要使用中括号语法来访问
let text = "this has been a short summer";
let pattern = /(.)hort/g;
/*
* 注意:Opera 不支持简写属性名
* IE 不支持多行匹配
*/
if (pattern.test(text)) {
console.log(RegExp.$_); // this has been a short summer
console.log(RegExp["$`"]); // this has been a
console.log(RegExp["$'"]); // summer
console.log(RegExp["$&"]); // short
console.log(RegExp["$+"]); // s
}
3.原始值包装类型
为了方便操作原始值,ECMAScript 提供了 3 种特殊的引用类型:Boolean、Number 和 String。
引用类型与原始值包装类型的主要区别在于对象的生命周期。在通过 new 实例化引用类型后,得到 的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期 间。这意味着不能在运行时给原始值添加属性和方法
1.Boolean
-
创建一个 Boolean 对象
let a= new Boolean(false);
-
Boolean 的实例会重写 valueOf()方法,返回一个原始值 true 或 false。toString()方法被调 用时也会被覆盖,返回字符串"true"或"false
let a= new Boolean(false); c=a.toString(); // false d=a.valueOf(); // false
-
注意:
let a= new Boolean(false); let b=a&&true; //b 此时是true
- 在这段代码中,我们创建一个值为 false 的 Boolean 对象。然后,在一个布尔表达式中通过&&操 作将这个对象与一个原始值 true 组合起来。在布尔算术中,false && true 等于 false。可是,这 个表达式是对 falseObject 对象而不是对它表示的值(false)求值。前面刚刚说过,所有对象在布 尔表达式中都会自动转换为 true,因此 falseObject 在这个表达式里实际上表示一个 true 值。那么 true && true 当然是 true。
2.Number
-
创建一个 Number 对象
let a=new Number();
-
方法:
Number 类型重写了 valueOf()、toLocaleString()和 toString()方 法。valueOf()方法返回 Number 对象表示的原始数值,另外两个方法返回数值字符串
-
toString() 方法可选地接收一个表示基数的参数,并返回相应基数形式的数值字符串
let a= new Number(10); console.log(a.toString(2)) //2进制 console.log(a.toString(8)) //8进制 console.log(a.toString(10))//10进制 console.log(a.toString(16))//16进制
-
toFixed()方法返回包含指定小数点位数的数值字符串
let a=new Number(10); console.log(a.toFixed(2)) //小数点后2位 console.log(a.toFixed(5)) //小数点后5位 console.log(a.toFixed(10))//小数点后10位
- toFixed()自动舍入的特点可以用于处理货币
- toFixed()方法可以表示有 0~20 个小数位的数值。某些浏览器可能支持更大的范 围,但这是通常被支持的范围
-
toExponential(),返回以科学记数法(也称为指数记数法)表示的数值字符串。
let a=new Number(100000); console.log(a.toExponential()) //1e+5
-
toPrecision()方法会根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法 形式。这个方法接收一个参数,表示结果中数字的总位数(不包含指数)
let a=new Number(99); console.log(a.toPrecision(1)); //1e+2 四舍五入 console.log(a.toPrecision(2)); //99 console.log(a.toPrecision(3)); //99.0
- toPrecision()方法可以表示带 1~21 个小数位的数值。某些浏览器可能支持更大 的范围,但这是通常被支持的范围
-
isInteger()方法,用于辨别一个数值是否保存为整数
console.log(Number.isInteger(10)); //true console.log(Number.isInteger(10.0)); //true console.log(Number.isInteger(10.01));//false
-
IEEE 754 数值格式有一个特殊的数值范围,在这个范围内二进制值可以表示一个整数值。这个数值 范围从 Number.MIN_SAFE_INTEGER(253 + 1)到 Number.MAX_SAFE_INTEGER(253 1)。对超出这 个范围的数值,即使尝试保存为整数,IEEE 754 编码格式也意味着二进制值可能会表示一个完全不同的 数值。为了鉴别整数是否在这个范围内,可以使用 Number.isSafeInteger()方法:
console.log(Number.isSafeInteger(-1 * (2 ** 53))); // false console.log(Number.isSafeInteger(-1 * (2 ** 53) + 1)); // true console.log(Number.isSafeInteger(2 ** 53)); // false console.log(Number.isSafeInteger((2 ** 53) - 1)); // true
3.String
- 创建一个 String 对象
let a=new String("hello World")
JavaScript 字符串由 16 位码元(code unit)组成。对多数字符来说,每 16 位码元对应一个字符
方法:
3个继承的方法 valueOf()、toLocaleString() 和 toString()都返回对象的原始字符串值
-
每个 String 对象都有一个 length 属性,表示字符串中字符的数量
let a=new String("hello World") console.log(a.length) //11
-
charAt()方法返回给定索引位置的字符,由传给方法的整数参数指定
let message = "abcde"; console.log(message.charAt(2)); // "c
-
使用 charCodeAt()方法可以查看指定码元的字符编码这个方法返回指定索引位置的码元值,索引以整数指定
let message = "abcde"; // Unicode "Latin small letter C"的编码是 U+0063 console.log(message.charCodeAt(2)); // 99
-
fromCharCode()方法用于根据给定的 UTF-16 码元创建字符串中的字符。这个方法可以接受任意 多个数值,并返回将所有数值对应的字符拼接起来的字符串
// Unicode "Latin small letter A"的编码是 U+0061 // Unicode "Latin small letter B"的编码是 U+0062 // Unicode "Latin small letter C"的编码是 U+0063 // Unicode "Latin small letter D"的编码是 U+0064 // Unicode "Latin small letter E"的编码是 U+0065 console.log(String.fromCharCode(0x61, 0x62, 0x63, 0x64, 0x65)); // "abcde" // 0x0061 === 97 // 0x0062 === 98 // 0x0063 === 99 // 0x0064 === 100 // 0x0065 === 101 console.log(String.fromCharCode(97, 98, 99, 100, 101));
-
字符串的操作方法:
-
concat(),用于将一个或多个字符串拼接成一个新字符串。更常用的方式是使用加号操作符(+)而且多数情况下,对于拼接多个字符串来说,使用加号更方便
let a="Hello" let b=a.concat(" World"); console.log(b) //Hello World let c=a.concat(" World","!"); //concat 可以链接多个字符 console.log(c); //Hello World!
-
3 个从字符串中提取子字符串的方法:slice()、substr()和 substring()。。这 3个方法都返回调用它们的字符串的一个子字符串,而且都接收一或两个参数。第一个参数表示子字符串开 始的位置,第二个参数表示子字符串结束的位置。对 slice()和 substring()而言,第二个参数是提取结束的位置(即该位置之前的字符会被提取出来)。对 substr()而言,第二个参数表示返回的子字符串数量。 任何情况下,省略第二个参数都意味着提取到字符串末尾。当某个参数是负值时,这 3 个方法的行为又有不同。比如,slice()方法将所有负值参数都当成字符串长度加上负参数值。 而 substr()方法将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0。 substring()方法会将所有负参数值都转换为 0
let a='hello ns' console.log(a.slice(3)) //lo ns console.log(a.substr(3)) //lo ns console.log(a.substring(3))//lo ns console.log(a.slice(1,4)) //ell console.log(a.substring(1,4)) //ell console.log(a.substr(1,4)) //ello // 负数情况 let stringValue = "hello world"; console.log(stringValue.slice(-3)); // "rld" console.log(stringValue.substring(-3)); // "hello world" console.log(stringValue.substr(-3)); // "rld" console.log(stringValue.slice(3, -4)); // "lo w" console.log(stringValue.substring(3, -4)); // "hel" console.log(stringValue.substr(3, -4)); // "" (empty string)
-
-
字符串位置方法:
-
有两个方法用于在字符串中定位子字符串:indexOf()和 lastIndexOf()。这两个方法从字符 串中搜索传入的字符串,并返回位置(如果没找到,则返回-1)。两者的区别在于,indexOf()方法 从字符串开头开始查找子字符串,而 lastIndexOf()方法从字符串末尾开始查找子字符串
let a='hello world' console.log(a.indexOf('l')) // 2 console.log(a.lastIndexOf('l')) // 9
- 这两个方法都可以接收可选的第二个参数,表示开始搜索的位置。这意味着,indexOf()会从这个 参数指定的位置开始向字符串末尾搜索,忽略该位置之前的字符;lastIndexOf()则会从这个参数指 定的位置开始向字符串开头搜索,忽略该位置之后直到字符串末尾的字符
let a='hello world' console.log(a.indexOf('o',2)) // 4 console.log(a.lastIndexOf('o',9)) //7
-
遍历字符串,寻找目标字符
let a='hahdehdhhasdhehhdhdehhdehehjjkhfdjejehher' let b=[] let c=a.indexOf('e') while (c>-1){ b.push(c) c=a.indexOf('e',c+1) } console.log(b) //[4, 13, 19, 23, 25, 34, 36, 39]
-
-
字符串包含方法
-
ECMAScript 6 增加了 3 个用于判断字符串中是否包含另一个字符串的方法:startsWith()、 endsWith()和 includes()。这些方法都会从字符串中搜索传入的字符串,并返回一个表示是否包含 的布尔值。它们的区别在于,startsWith()检查开始于索引0 的匹配项(即查询是否该字符串是否为首部),endsWith()检查开始于索引(string.length - substring.length)的匹配项(即查询该字符串是否为尾部),而 includes()检查整个字符串
let a='footbarbaz' console.log(a.startsWith('foo')) //true console.log(a.startsWith('bar')) //false console.log(a.endsWith('baz')) //true console.log(a.endsWith('bar')) //false console.log(a.includes('bar')) //true
startsWith()和 includes()方法接收可选的第二个参数,表示开始搜索的位置。如果传入第二 个参数,则意味着这两个方法会从指定位置向着字符串末尾搜索,忽略该位置之前的所有字符。
endsWith()方法接收可选的第二个参数,表示应该当作字符串末尾的位置。如果不提供这个参数, 那么默认就是字符串长度
-
-
trim()方法
-
ECMAScript 在所有字符串上都提供了 trim()方法。这个方法会创建字符串的一个副本,删除前、 后所有空格符,再返回结果
let a=' hello world ' console.log(a.trim()) //hello world console.log(a) // hello world trim()方法并不会改变原来的字符串
另外,trimLeft()和 trimRight()方法分别用于从字符串开始和末尾清理空格符
-
-
repeat()方法
-
ECMAScript 在所有字符串上都提供了 repeat()方法。这个方法接收一个整数参数,表示要将字 符串复制多少次,然后返回拼接所有副本后的结果
let a='哈哈' console.log(a.repeat(5)+'嗝')//哈哈哈哈哈哈哈哈哈哈嗝 console.log(a) //哈哈 repeat()方法也不会改变原来的字符串
-
-
padStart () 和padEnd() 方法
-
padStart()和 padEnd()方法会复制字符串,如果小于指定长度,则在相应一边填充字符,直至 满足长度条件。这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格
let a="hi" console.log(a.padStart(7,'kkk')) //kkkkkhi padStart()从首部填充字符串 console.log(a.padEnd(7,'kkk')) //hikkkkk padEnd()是从末尾填充字符串
- 可选的第二个参数并不限于一个字符。如果提供了多个字符的字符串,则会将其拼接并截断以匹配 指定长度。此外,如果长度小于或等于字符串长度,则会返回原始字符串
-
-
字符串迭代与解构:
// 迭代 let a='hello world' for(const c of a){ console.log(c) } // 解构 let message = "abcde"; console.log([...message]);
-
字符串大小写转换
-
toLowerCase()、toLocaleLowerCase()、toUpperCase()和toLocaleUpperCase()。toLowerCase()和toUpperCase()方法是原来就有的方法, 与 java.lang.String 中的方法同名。toLocaleLowerCase()和 toLocaleUpperCase()方法旨在基于 特定地区实现。在很多地区,地区特定的方法与通用的方法是一样的。但在少数语言中(如土耳其语), Unicode 大小写转换需应用特殊规则,要使用地区特定的方法才能实现正确转换
let a='Hello world' console.log(a.toLowerCase()) //小写 console.log(a.toLocaleLowerCase()) //小写 console.log(a.toUpperCase()) //大写 console.log(a.toLocaleUpperCase()) //大写
-
-
字符串匹配方法
-
第一个就是 match()方法,这个方法本质上跟 RegExp 对象的 exec()方法相同。match()方法接收一个参数,可以是一个正则表达式字 符串,也可以是一个 RegExp 对象。match()方法返回的数组第一个元素是与整个模式匹配的字符串,其余元素则是与表达式中的捕获组匹配的字符串(如果有的话)
let a='hello world'; let b= /.e/; let c=a.match(b); //let c=b.exec(a); console.log(c.index); console.log(c[0]) console.log(b.lastIndex)
-
另一个查找模式的字符串方法是 search()。这个方法唯一的参数与 match()方法一样:正则表达 式字符串或 RegExp 对象。这个方法返回模式第一个匹配的位置索引,如果没找到则返回1。search() 始终从字符串开头向后匹配模式
let a='cat,bat,oat'; let b=/bat/i; let c=a.search(b); console.log(c) //4
-
replace()方法。这个方法接收两个参数,第一个 参数可以是一个 RegExp 对象或一个字符串(这个字符串不会转换为正则表达式),第二个参数可以是 一个字符串或一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字 符串,第一个参数必须为正则表达式并且带全局标记。
let a='cat,bat,oat'; let b=/at/g let c=a.replace(b,'ta') console.log(c); //cta,bta,ota
- 第二个参数是字符串的情况下,有几个特殊的字符序列,可以用来插入正则表达式操作的值
-
```js
let a='cat,bat,oat';
let b=/(.at)/g //寻找以at为结尾的字符串
let c=a.replace(b,"ta ($1)")
console.log(c) //ta (cat),ta (bat),ta (oat)
```
-
localeCompare()方法(比较两个字符串)
let a='c' console.log(a.localeCompare('a')) // 1 console.log(a.localeCompare('c')) // 0 console.log(a.localeCompare('d')) //-1
4.单例内置对象
1.Global
介绍 :
- Global 对象是 ECMAScript 中最特别的对象,因为代码不会显式地访问它。ECMA-262 规定 Global 对象为一种兜底对象,它所针对的是不属于任何对象的属性和方法。事实上,不存在全局变量或全局函 数这种东西。在全局作用域中定义的变量和函数都会变成 Global 对象的属性
eval()方法
- 最后一个方法可能是整个 ECMAScript 语言中最强大的了,它就是 eval()。这个方法就是一个完 整的 ECMAScript 解释器,它接收一个参数,即一个要执行的 ECMAScript(JavaScript)字符串
window对象
- 虽然 ECMA-262 没有规定直接访问 Global 对象的方式,但浏览器将 window 对象实现为 Global 对象的代理。因此,所有全局作用域中声明的变量和函数都变成了 window 的属性
2.Math
Math对象属性
- Math 对象有一些属性,主要用于保存数学中的一些特殊值。下表列出了这些属性。
min()和max()方法
let a=[1,2,3,4,5,6,7,8,9];
console.log(Math.max(...a)) // 求数组的最大值
console.log(Math.min(...a)) // 求数组的最小值
舍入方法
-
于把小数值舍入为整数的 4 个方法:Math.ceil()、Math.floor()、Math.round() 和 Math.fround()
let a=25.9; console.log(Math.ceil(a)) //26 console.log(Math.floor(a)) //25 console.log(Math.round(a)) //26 console.log(Math.fround(a))//25.899999618530273
- Math.ceil()方法始终向上舍入为最接近的整数。
- Math.floor()方法始终向下舍入为最接近的整数。
- Math.round()方法执行四舍五入。
- Math.fround()方法返回数值最接近的单精度(32 位)浮点值表示
- 对于 25 和 26(不包含)之间的所有值,Math.ceil()都会返回 26,因为它始终向上舍入。 Math.round()只在数值大于等于 25.5 时返回 26,否则返回 25。最后,Math.floor()对所有 25 和 26(不包含)之间的值都返回 25
random()方法
-
Math.random()方法返回一个 0~1 范围内的随机数,其中包含 0 但不包含 1
// 返回固定区间的随机数 function selectFrom(minNumber,maxNumber){ let choice=maxNumber-minNumber+1; return Math.floor(Math.random()*choice+minNumber); } let snumber=selectFrom(0,10) //获得1-10区间的随机数 // 返回随机字符串 let a=['red','blue','yellow','grean'] function selectFrom(minNumber,maxNumber){ let choice=maxNumber-minNumber+1; return Math.floor(Math.random()*choice+minNumber); } let v=selectFrom(0,a.length-1); console.log(a[v]);
其他方法
5.集合引用类型
1.Object
- 对象的分类:
- 内建对象:
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
- 比如,Math,String,Number,Boolean ,Function,Object....
- 宿主对象
- 由js的运行环境提供的对象,目前来讲主要是由浏览器提供的对象
- 比如 BOM DOM
- 自定义对象
- 由自己创建的对象
- 内建对象:
- 对象之间是不相等的
2.Array
特点:数组中每个槽位可以存储任意类型的数据
-
创建数组:
// 第一种方式 let a=new Array('hhh','jjj','kkk'); // 第二种方式 let a=['hhh','jjj','kkk'] //数组字面量
-
Array 构造函数还有两个 ES6 新增的用于创建数组的静态方法:from()和 of()。from()用于将 类数组结构转换为数组实例,而 of()用于将一组参数转换为数组实例
// 字符串会被拆分为单字符数组 console.log(Array.from("Matt")); // ["M", "a", "t", "t"] // 可以使用 from()将集合和映射转换为一个新数组 const m = new Map().set(1, 2) .set(3, 4); const s = new Set().add(1) .add(2) .add(3) .add(4); console.log(Array.from(m)); // [[1, 2], [3, 4]] console.log(Array.from(s)); // [1, 2, 3, 4] // Array.from()对现有数组执行浅复制 const a1 = [1, 2, 3, 4]; const a2 = Array.from(a1); console.log(a1); // [1, 2, 3, 4] alert(a1 === a2); // fals
-
-
数组空位
-
使用数组字面量初始化数组时,可以使用一串逗号来创建空位(hole)。ECMAScript 会将逗号之间相应索引位置的值当成空位,ES6 规范重新定义了该如何处理这些空位
const a=[,,,,,] console.log(a.length)//5 console.log(a) //空*5
- ES6通常将这些空位当成存在的元素,只不过值为:
undefined
- ES6之前会忽略空位,但具体行为也会因人而异
- 在实践中尽量避免使用数空位,如果确实需要空位,则可以显式的使用undefined
- ES6通常将这些空位当成存在的元素,只不过值为:
-
-
数组索引
-
要取得或设置数组的值,需要使用中括号并提供相应值的数字索引
let a=['ss','dd','fff'] console.log(a[0]) //显示第一项 a[1]='kk' //修该第二项 a[3]='jj' //添加第四项 console.log(a.length) //检测数组长度 a.length=3 //通过length删除第四项 a.length=5 //扩大数组长度,未赋值的显示undefined a[a.length]='hhh' //通过length添加向数组末尾添加元素
- 数组最多可以包括4294967295个元素
-
-
检测数组
-
一个网页时,使用 instanceof 操作符即可
if(a instanceof Array){ //语句 }
-
多个网页是,使用 Array.isArray()方法
if (Array.isArray(a)){ //语句 }
-
-
迭代器方法
//数组的迭代 let a=['sss','ddd','fff']; console.log(Array.from(a.keys())); //key()迭代索引 console.log(Array.from(a.values()));//values()迭代数组元素 console.log(Array.from(a.entries()));//entries()迭代索引/值对 //数组的解构 let a=['sss','ddd','fff']; for (const [b,c] of a.entries()){ console.log(b); console.log(c); } //0 //sss //1 //ddd //2 //fff
-
数组的添加,删除(栈方法和队列方法):
// puch()可以尾部添加多个元素,其返回值是新的长度 let a=['sss','ddd','fff']; a.push('mmm','nnn') // unshift()在数组前面添加一个或多个属性,其返回值是新的长度 a.unshift('11') // pop()可以删除尾部的最后一个元素,并将删除的元素作为返回值返回 a.pop() //shift()可以删除数组第一个元素,并将删除的元素作为返回值返回 a.shift()
-
数组的遍历
let a=['sss','ddd','fff']; for(var i=0;i<a.length;i++){ console.log(a[i]); } //第二种方法 for(const c of a){ console.log(c) } //forEach()方法遍历 a.forEach(function(a){ console.log(a); });
- forEach()方法需要一个函数作为参数,该方法只在IE8以上的浏览器支持
- 像这种函数我们就称其为回调函数
- 数组中有几个元素函数就会执行几次,每次执行时函数就会将遍历的元素以实参的形式传递进来。因此,我们可以定义形参来读取这些内容
- 浏览器会在回调函数中传递三个参数
- 第一个参数,就是当前遍历的元素
- 第二个参数,就是当前遍历的元素的索引
- 第三个参数,就是正在遍历的数组
- forEach()方法需要一个函数作为参数,该方法只在IE8以上的浏览器支持
-
复制和填充
const zeroes = [0, 0, 0, 0, 0]; // 用 5 填充整个数组 zeroes.fill(5); console.log(zeroes); // [5, 5, 5, 5, 5] zeroes.fill(0); // 重置 // 用 6 填充索引大于等于 3 的元素 zeroes.fill(6, 3); console.log(zeroes); // [0, 0, 0, 6, 6] zeroes.fill(0); // 重置 // 用 7 填充索引大于等于 1 且小于 3 的元素 zeroes.fill(7, 1, 3); console.log(zeroes); // [0, 7, 7, 0, 0]; zeroes.fill(0); // 重置 // 用 8 填充索引大于等于 1 且小于 4 的元素 // (-4 + zeroes.length = 1) // (-1 + zeroes.length = 4) zeroes.fill(8, -4, -1); console.log(zeroes); // [0, 8, 8, 8, 0]; // fill()静默忽略超出数组边界、零长度及方向相反的索引范围: const zeroes = [0, 0, 0, 0, 0]; // 索引过低,忽略 zeroes.fill(1, -10, -6); console.log(zeroes); // [0, 0, 0, 0, 0] // 索引过高,忽略 zeroes.fill(1, 10, 15); console.log(zeroes); // [0, 0, 0, 0, 0] // 索引反向,忽略 zeroes.fill(2, 4, 2); console.log(zeroes); // [0, 0, 0, 0, 0] // 索引部分可用,填充可用部分 zeroes.fill(4, 3, 10) console.log(zeroes); // [0, 0, 0, 4, 4] // fill()不同,copyWithin()会按照指定范围浅复制数组中的部分内容,然后将它们插入到指 // 定索引开始的位置。开始索引和结束索引则与 fill()使用同样的计算方法 let ints, reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; reset(); // 从 ints 中复制索引 0 开始的内容,插入到索引 5 开始的位置 // 在源索引或目标索引到达数组边界时停止 ints.copyWithin(5); console.log(ints); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] reset(); // 从 ints 中复制索引 5 开始的内容,插入到索引 0 开始的位置 ints.copyWithin(0, 5); console.log(ints); // [5, 6, 7, 8, 9, 5, 6, 7, 8, 9] reset(); // 从 ints 中复制索引 0 开始到索引 3 结束的内容 // 插入到索引 4 开始的位置 ints.copyWithin(4, 0, 3); alert(ints); // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9] reset(); // JavaScript 引擎在插值前会完整复制范围内的值 // 因此复制期间不存在重写的风险 ints.copyWithin(2, 0, 6); alert(ints); // [0, 1, 0, 1, 2, 3, 4, 5, 8, 9] reset(); // 支持负索引值,与 fill()相对于数组末尾计算正向索引的过程是一样的 ints.copyWithin(-4, -7, -3); alert(ints); // [0, 1, 2, 3, 4, 5, 3, 4, 5, 6] copyWithin()静默忽略超出数组边界、零长度及方向相反的索引范围: let ints, reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; reset(); // 索引过低,忽略 ints.copyWithin(1, -15, -12); alert(ints); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; reset() // 索引过高,忽略 ints.copyWithin(1, 12, 15); alert(ints); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; reset(); // 索引反向,忽略 ints.copyWithin(2, 4, 2); alert(ints); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; reset(); // 索引部分可用,复制、填充可用部分 ints.copyWithin(4, 7, 10) alert(ints); // [0, 1, 2, 3, 7, 8, 9, 7, 8, 9];
-
转换方法
toLocaleString()、toString()和 valueOf()方法。其中,valueOf() 返回的还是数组本身。而 toString()返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的 字符串。也就是说,对数组的每个值都会调用其 toString()方法,以得到最终的字符串
-
如果想使 用不同的分隔符,则可以使用 join()方法。join()方法接收一个参数,即字符串分隔符,返回包含所 有项的字符串
let a=[1,2,3,4,5,6]; console.log(a.join('!')) //1!2!3!4!5!6
如果数组中某一项是 null 或 undefined,则在 join()、toLocaleString()、 toString()和 valueOf()返回的结果中会以空字符串表示。
-
slice()和splice()
-
silce()
- 该方法可以用来截取指定数组
- 该方法不会改变元素数组,而是将截取到的元素封装到一个新的数组中返回
- 参数:
- 截取开始位置的索引,包含开始索引
- 截取结束的位置索引,不包含结束索引
- 第二个参数可以不写,此时会截取从索引往后的所以元素
- 索引可以传递一个负值,则从后往前截取
-
splice()
可以用来删除,替换,可以插入数组中的指定元素
使用splice()会影响到原数组,会将指定元素从原数组中删除并将被删除的元素作为返回值
-
参数
- 第一个表示开始位置的索引
- 第二个表示删除的数量
- 第三个及以后。。可以传递一些新的元素,这些元素将会自动插入到开始位置索引前面
- 插入元素将第二参数变为零即可
let a=['sss','ddd','fff','hhh','qqq']; let b=a.slice(0,2); //["sss", "ddd"] console.log(b); let c=a.slice(0,-2) console.log(c)//["sss", "ddd", "fff"] a.splice(0,2); console.log(a);// ["fff", "hhh", "qqq"] a.splice(0,2,'ooo','ppp'); console.log(a)// ["ooo", "ppp", "qqq"] a.splice(1,0,'lll','uuu'); console.log(a)// ["ooo", "lll", "uuu", "ppp", "qqq"]
-
数组查重练习:
//数组的去重 let arr=[1,2,3,2,1,3,4,2,5]; for(let i=0;i<arr.length;i++){ for(let is=i;i<arr.length;i++){ if(arr[i]==arr[is]){ arr.splice(is,1); } } } console.log(arr)
-
-
其他方法:
-
concat():
可以连接两个或多个数组,并将新数组返回
不会对原数组产生影响
-
reverse()
- 该方法用于反转数组(前面的去后面,后面的去前面)
- 该方法会直接修改数组
-
sort()
可以对数组中的元素进行排序
会影响数组,默认按照Unicode排序
-
对于纯数字的数组进行排序的时候,会出现错误。因此我们需要在sort()添加一个回调函数来指定排序规则
- 回调函数需要定义两个参数,
- 浏览器将分别使用数组中的元素作为实参去调用回调函数
- 使用那个元素调用不确定,但是第一个参数一定在第二个的前面
- 浏览器会根据回调函数的返回值来决定元素的位置
- 如果返回值大于0,则元素会交换位置
- 如果返回值小于0,则元素位置不会发生改变
- 如果返回值等于零,则元素位置不变
// concat() 使用 let a=['ss','dd','ff','gg']; let b=['yy','qq']; let c=a.concat(b) console.log(c) //["ss", "dd", "ff", "gg", "yy", "qq"] // reverse() let a=['ss','dd','ff','gg']; a.reverse(); console.log(a);// ["gg", "ff", "dd", "ss"] // sort()纯数字的数组排序 let a=[1,11,12,13,25,9,8,6] //升序排列 a.sort(function(b,c){ return b-c; }) console.log(a); //[1, 6, 8, 9, 11, 12, 13, 25] // 降序排序 a.sort(function(b,c){ return c-b; }) console.log(a); //[25, 13, 12, 11, 9, 8, 6, 1]
-
-
数组的练习:
数组练习 var per1={ name:'孙悟空', age:18 }; var per2={ name:'猪八戒', age:28 }; var per3={ name:'红孩儿', age:8 }; var per4={ name:'二郎神', age:38 }; var per5={ name:'沙和尚', age:48 }; let perarr=[per1,per2,per3,per4,per5]; function getAdult(arr){ let newper=[]; for(let i=0;i<arr.length;i++){ if(arr[i].age>=18){ newper.push(arr[i]); } } return newper; } let newPer=getAdult(perarr); for(let i=0;i<newPer.length;i++){ console.log(newPer[i].name) }
4.DOM
1.介绍:
- 文档对象模型(DOM,Document Object Model)是 HTML 和 XML 文档的编程接口。DOM 表示 由多层节点构成的文档,通过它开发者可以添加、删除和修改页面的各个部分
2.Node类型(节点)
定义:DOM1 级定义了一个 Node 接口,该接口将由 DOM 中的所有节点类型实现。这个 Node 接口在 JavaScript 中是作为 Node 类型实现的
-
每个节点都有一个 nodeType 属性,用于表明节点的类型。节点类型由在 Node 类型中定义的下列 12 个数值常量来表示,任何节点类型必居其一:
- Node.ELEMENT_NODE(1);
- Node.ATTRIBUTE_NODE(2);
- Node.TEXT_NODE(3);
- Node.CDATA_SECTION_NODE(4);
- Node.ENTITY_REFERENCE_NODE(5);
- Node.ENTITY_NODE(6);
- Node.PROCESSING_INSTRUCTION_NODE(7);
- Node.COMMENT_NODE(8)
- Node.DOCUMENT_NODE(9);
- Node.DOCUMENT_TYPE_NODE(10);
- Node.DOCUMENT_FRAGMENT_NODE(11);
- Node.NOTATION_NODE(12)
-
节点关系:
节点间的各种关系可以用传统的家族关系来描 述,相当于把文档树比喻成家谱。在 HTML 中,可以将元素看成是元素的子元素;相应 地,也就可以将元素看成是元素的父元素。而元素,则可以看成是元素 的同胞元素,因为它们都是同一个父元素的直接子元素
每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象。NodeList 是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。
-
访问保存在 NodeList 中的节点——可以通过方括号,也可以使用 item() 方法
var firstChild = someNode.childNodes[0]; var secondChild = someNode.childNodes.item(1); var count = someNode.childNodes.length;
-
操作节点:
- appendChiid():向childNode列表的末尾插入一个节点
- insertBefore():把节点放在 childNodes 列表中某个特定的位置上,而不是放在末尾
- 这个方法接受两个参数:要插入的节点和作为参照的节点
- 插入节点后,被插 入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回
- 如果参照节点是 null,则 insertBefore()与 appendChild()执行相同的操作
- removeChild():移除节点
- replaceChild():替换节点
- replaceChild()方法接受的两个参数是:要插入的节点和要替换的节点
-
其他方法:
- cloneNode():创建调用这个方法的节点 的一个完全相同的副本
- cloneNode()方法接受一个布尔值参数,表示是否执行深复制。在参数为 true 的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为 false 的情况下,执行浅复制, 即只复制节点本身。复制后返回的节点副本属于文档所有,但并没有为它指定父节点。因此,这个节点 副本就成为了一个“孤儿”,除非通过 appendChild()、insertBefore()或 replaceChild()将它添加到文档中
- cloneNode():创建调用这个方法的节点 的一个完全相同的副本
3.Document类型(文档类型)
-
介绍:JavaScript 通过 Document 类型表示文档。在浏览器中,document 对象是HTMLDocunmet (继承自Document 类型)的一个实例,表示整个 HTML 页面。而且document 对象是 window 对象的一个 属性,因此可以将其作为全局对象来访问
-
特征:
- nodeType 的值为 9;
- nodeName 的值为"#document";
- nodeValue 的值为 null;
- parentNode 的值为 null;
- ownerDocument 的值为 null; 其子节点可能是一个 DocumentType(最多一个),Element(最多一个)、ProcessingInstruction 或 Comment。
子节点:Document 节点的子节点可以是 DocumentType、Element、ProcessingInstruction 或 Comment,但还有两个内置的访问其子节点的快捷方式。第一个就是 documentElement 属性,该属性始终指向 HTML 页面中的元素。另一个就是通过 childNodes 列表访问文档元素, 但通过 documentElement 属性则能更快捷、更直接地访问该元素
-
-
文档信息:
let a=document.title //获取文档标题 document.title='Js学习' //修改文档标题 let b=document.URL //获取URL let c=document.domain //获取域名 let d=document.referrer//获取来源页面的URL
-
查找元素
-
getElementById():接收一个参数:要取得的一个元素的 ID
例如:
<div id="myDiv">15555</div>
let a=document.getElementById('myDiv')
-
getElementsByTagName():这个方法接受一个参数,即要 取得一组元素的标签名
例如:
<img src="" alt="">
let b=document.getElementsByTagName('img');
-
getElementsByName():获取一组元素的name
<img src="" alt="",name="hhh">
let c=document.getElementsByName('hhh')
- getElemetsBtTagname()还可以获取当前节点的指定标签名后代节点
<ul id="ul"> <li class=""></li> <li class=""></li> <li class=""></li> </ul>
window.onload=function(){ let a=document.getElementById("ul"); let b=a.getElementsByTagName('li'); //获取name为ul下的所有li标签 }
-
childNodes属性
- childNodes属性会获取包括文本节点在内的所有节点
- 根据DOM标签间空白也会当作文本节点
- 注意:在IE8及一下的浏览器中,不会将空白当作文本节点
<ul id="ul"> <li class=""></li> <li class=""></li> <li class=""></li> </ul>
let a=document.getElementById("ul"); let c=a.childNodes; console.log(c.length); //7 因为li之间的空白区域浏览器当作了文本节点
-
children属性:
- 会获取当前元素的子元素
<ul id="ul"> <li class=""></li> <li class=""></li> <li class=""></li> </ul>
let a=document.getElementById("ul"); let d=a.children; console.log(d.length) //3
-
firstChild属性
- 可以获取到当前元素的第一个子节点(包括空白文本节点)
-
firstElementChild属性
- 获取到当前元素的第一个子元素
- 不支持IE8及一下的浏览器
-
lastchild属性
- 获取当前元素的最后一个子节点(包括空白文本节点)
-
parentNode属性
- 获取父节点
<ul id="ul"> <li id="li">111</li> <li>22</li> <li>33</li> <li>44</li> </ul>
window.onload = function () { let a = document.getElementById('li'); let b = a.parentNode; console.log(b.innerText) //innerText 是显示文本内容 } //innerHTML 是显示HTML内容,会将标签也显示出来
-
previousSibling属性
- 获得当前节点的前一个兄弟节点(也会获取空白的文本)
- previousElementSibling
- 获取前一个兄弟元素
- 但是IE8及一下的浏览器不使用
-
nextsiblinng属性
- 获得当前节点的下一个兄弟节点
-
boby属性
- 获取bobybiaoq
-
documentElement属性
- 获取html根标签
-
all属性
- 获取页面中的所有元素
- 与getElementsTagName("*")相等
-
getElementsClassName('')
- 获取带有相同class属性的一组元素对象
- 该方法不支持IE8及以下的浏览器
-
querySelector()
-
需要一个选择器的字符串作为参数,可以根据一个CSS选择器来查询元素节点对象
document.querySelector('.box1 div'); //获得class属性为box1内部的div
- IE8也支持
使用该方法总会返回唯一一个元素,如果满足条件的元素有多个,那么它只会返回第一个
-
-
querSelectorAll()
- 该方法与querySeletorAll()用法一样,但它会将符合条件的所有元素封装到一个数组中返回
- 即使符合条件的只有一个,它也会返回一个数组
-
-
DOM的增删改
-
document.createElement()
- 创建一个标签节点
- 他需要一个标签名作为参数,将会根据该标签名创建元素节点对象,并将创建好的对象作为返回值返回
document.createElement('h1') // // 创建一个div标签
-
document.createTextNode();
- 创建一个文本节点
- 需要一个文本内容作为参数,将会根据该内容创建文本节点,并将新的节点作为返回值返回
let b=document.createTextNode('我是一个h1标签');
-
appendChild()
- 向一个父节点添加一个新的子节点
- 用法:父节点.appendChild(子节点)
a.appendChild(b);
-
insertBefore()
可以在指定的子节点前插入新的子节点
-
语法
- 父节点.insertBefore(新节点,子节点)
c.insertBefore(a,d);
-
replaceChild()
可以使用指定子节点替换已有的子节点
-
语法
- 父节点.replaceChild(新节点,子节点)
c.replaceChild(a,d)
-
removeChild()
删除一个节点
-
语法
- 父节点.removeChild(子节点)
c.removeChild(d) //简便方法 d.parentNode.removeChild(d)
-
-
使用DOM操作CSS
-
修改元素样式
语法:元素.style.样式名=样式值
/// 将box的高变为300px box.style.height="300px"
- 注意:如果CSS的样式名中含有
-
这种名称在JS中是不合法的比如 background-color
需要将这种样式名修改为驼峰命名法,去掉-
,然后将-
后的字母大写 - js改变的是内联样式优先级比较高,但如果css中添加了
!important
则无法进行修改样式
- 注意:如果CSS的样式名中含有
-
读取元素样式
- 语法:元素.style.样式名
// 读取内联样式 var btn=box.style.width;
- 语法:元素.currentStyle.样式名
// 读取当前元素正在显示的样式,只有IE浏览器支持 box.currrntStyle.widet
- 语法:getComputerStyle()方法
// 需要两个参数 // 第一个:要获得样式元素 // 第二个:可以传递一个伪元素,一般都传null // 该方法会返回一个对象,对象中封装了当前元素对应的样式 var obj=getComputedStyle(box1,null).width;
-
-
DOM 练习:
-
切换图片演示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> window.onload = function () { let photoArray = ["../static/gansu.jpg", "../static/jiangsu.jpg", "../static/qinghai.jpg", "../static/sichuan.jpg", "../static/xinjiang.jpg", "../static/zhufeng.jpg"]; let imgs = document.getElementsByName('img')[0]; let up = document.getElementById('up'); let lower = document.getElementById('lower'); let i = 0; up.onclick = function () { i--; if (i < 0) { i = 5; } imgs.src = photoArray[i]; } lower.onclick = function () { i++; if (i > 5) { i = 0; } imgs.src = photoArray[i]; } }; </script> <style> * { padding: 0; margin: 0; } .box { width: 500px; margin: 20px auto; } .box>img{ width: 500px; height: 500px; } </style> </head> <body> <div class="box"> <img src="../static/gansu.jpg" alt="" name="img"> <button id="up">上一张</button> <button id="lower">下一张</button> </div> </body> </html>
-
全选练习
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> window.onload = function () { let checkedAllbtn = document.getElementById('checkedAllbtn'); let checkedNobtn = document.getElementById('checkedNobtn'); let checkedRevBtn = document.getElementById('checkedRevBtn'); let sendBtn = document.getElementById('sendBtn'); let allIput = document.getElementById('allIput'); let items = document.getElementsByName('items'); // 全选 checkedAllbtn.onclick = function () { for (let i = 0; i < items.length; i++) { items[i].checked = true; } allIput.checked = true; }; // 全不选 checkedNobtn.onclick = function () { for (let i = 0; i < items.length; i++) { items[i].checked = false; } allIput.checked = false; }; // 反选 checkedRevBtn.onclick = function () { for (let i = 0; i < items.length; i++) { // if(items[i].checked==true){ // items[i].checked=false; // }else{ // items[i].checked=true; // } items[i].checked = !items[i].checked } } // 提交 sendBtn.onclick = function () { for (let i = 0; i < items.length; i++) { if (items[i].checked) { alert(items[i].value); } } } // 多选框的全选 allIput.onclick = function () { for (let i = 0; i < items.length; i++) { items[i].checked = allIput.checked } } // 检查 for (let i = 0; i < items.length; i++) { items[i].onclick = function () { allIput.checked=true; for (let j = 0; j < items.length; j++) { if (!items[j].checked) { allIput.checked = false; } } } } } </script> </head> <body> <form action=""> 你爱好的运动是?<input type="checkbox" id="allIput">全选/不全选<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><button id="checkedAllbtn" type="button">全选</button><button type="button" id="checkedNobtn">全不选</button><button type="button" id="checkedRevBtn">反选</button><button type="button" id="sendBtn">提交</button> </form> </body> </html>
- checked属性用于检查是否被选中
- onlick事件:单击事件
-
5.面向对象程序设计
1.理解对象
-
使用对象字面量创建对象
var obj={ name='xiaoming', age=18, sex='man' }
-
属性类型
-
数据属性
- [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特 性,或者能否把属性修改为访问器属性。
- [[Enumerable]]:表示能否通过 for-in 循环返回属性。
- [[Writable]]:表示能否修改属性的值。
- [[Value]]:包含这个属性的数据值。
- 要修改属性默认的特性,必须使用 ECMAScript 5 的 Object.defineProperty()方法。这个方法 接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属 性必须是:configurable、enumerable、writable 和 value。设置其中的一或多个值,可以修改 对应的特性值。
-
访问器属性
访问器属性不包含数据值;它们包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。 在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。
- [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特 性,或者能否把属性修改为数据属性。
- [[Enumerable]]:表示能否通过 for-in 循环返回属性。
- [[Get]]:在读取属性时调用的函数。
- [[Set]]:在写入属性时调用的函数。
- 访问器属性不能直接定义,必须使用 Object.defineProperty()来定义
-
2.创建对象
-
工厂模式
function createPerson(name,age,job){ var obj=new Object; obj.name=name; obj.age=age; obj.job=job; return obj; } // 工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
-
构造函数模式
function createPerson (name,age,job) { this.name=name, this.age=age, this.job=job } // 使用new来调用 var a=new createPerson('xiaoming',18,job); // 以这种方式创建函数,会导致不同的作用域链和标识符解析。占用大量的资源
-
原型模式
原型对象(prototype)
- 我们创建的每一个函数,解析器都会向函数添加一个属性prototype。这个属性对应一个对象,这个对象就是我们所谓的原型对象
- 如果函数作为普通函数调用prototype没有任何作用。当函数以构造函数的形式调用时,它所创建的对象都会有一个隐含属性,指向该函数的原型对象,我们可以通过
__prptp__
来访问该属性 - 原型对象就可以当作一个公共区域,所有同一个类的实例都可以访问这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
- 当我们访问对象的一个属性和方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
- 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
-
组合使用构造函数模式和原型模式
// 创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实 // 例属性,而原型模式用于定义方法和共享的属性。 function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby", "Court"]; } Person.prototype = { constructor : Person, sayName : function(){ alert(this.name); } }
-
动态原型模式
使用动态原型模式时,不能使用对象字面量重写原型
寄生构造函数模式
-
稳妥构造函数模式
-
稳妥对象
没有公共属性,而且其方法也不引用 this 的对象
一新创建对象的 实例方法不引用 this;二不使用 new 操作符调用构造函数
function Person(name, age, job){ //创建要返回的对象 var o = new Object(); //可以在这里定义私有变量和函数 //添加方法 o.sayName = function(){ alert(name); }; //返回对象 return o; } var friend = Person("Nicholas", 29, "Software Engineer");
-
3.继承
-
继承的两种方式:接口继承(只继承方法签名)和实现继承(继承实际的方法)
目前js只支持实现继承,而且其实现继承主要是依靠原型链来实现的
原型链:利用原型让一个引用类型继承另一个引用类型的属性和方法