JavaScript基础
JavaScript
概况
起源
? JavaScript诞生于1995年,它的出现主要是用于处理网页中的
前端验证。
? 所谓的前端验证,就是指检查用户输入的内容是否符合一定的
规则。
? 比如:用户名的长度,密码的长度,邮箱的格式等。
简史
? JavaScript是由网景公司发明,起初命名为LiveScript,后来由
于SUN公司的介入更名为了JavaScript。
? 1996年微软公司在其最新的IE3浏览器中引入了自己对
JavaScript的实现JScript。
? 于是在市面上存在两个版本的JavaScript,一个网景公司的
JavaScript和微软的JScript。
? 为了确保不同的浏览器上运行的JavaScript标准一致,所以几
个公司共同定制了JS的标准名命名为ECMAScript。
? ECMAScript是一个标准,而这个标准需要由各个厂商去实现。
? 不同的浏览器厂商对该标准会有不同的实现。
实现
? 我们已经知道ECMAScript是JavaScript标准,所以一般情况下
这两个词我们认为是一个意思。
? 但是实际上JavaScript的含义却要更大一些。
? 一个完整的JavaScript实现应该由以下三个部分构成:
特点
- JS的特点
- 解释型语言
- 类似于 C 和 Java 的语法结构
- 动态语言
- 基于原型的面向对象
解释型语言
- JavaScript是一门解释型语言,所谓解释型值语言不需要被编
译为机器码在执行,而是直接执行。 - 由于少了编译这一步骤,所以解释型语言开发起来尤为轻松,
但是解释型语言运行较慢也是它的劣势。 - 不过解释型语言中使用了JIT技术,使得运行速度得以改善。
类似于 C 和 Java 的语法结构
- JavaScript的语法结构与C和Java很像,向for、if、while等语
句和Java的基本上是一模一样的。 - 所以有过C和Java基础的同学学习起来会轻松很多。
- 不过JavaScript和与Java的关系也仅仅是看起来像而已。
动态语言
- JavaScript是一门动态语言,所谓的动态语言可以暂时理解为
在语言中的一切内容都是不确定的。比如一个变量,这一时刻
是个整型,下一时刻可能会变成字符串了。当然这个问题我们
以后再谈。 - 不过在补充一句动态语言相比静态语言性能上要差一些,不过
由于JavaScript中应用的JIT技术,所以JS可能是运行速度最快
的动态语言了。
基于原型的面向对象
- JavaScript是一门面向对象的语言。
- Java也是一门面向对象的语言,但是与Java不同JavaScript是
基于原型的面向对象。
编写位置
- 我们目前学习的JS全都是客户端的JS,也就是说全都是需要在
浏览器中运行的,所以我们我们的JS代码全都需要在网页中编
写。 - 我们的JS代码需要编写到
script标签中。 - 我们一般将script标签写到head中。(和style标签有点像)
- 属性:
- type:默认值text/javascript可以不写,不写也是这个值。
- src:当需要引入一个外部的js文件时,使用该属性指向文件的地址。
例如:
注意:
- JavaScript是严格区分大小写的,也就是abc和Abc会被解析器
认为是两个不同的东西。 - 所以在编写上边的HelloWorld时,一定要注意区分大小写。
注释
- 注释中的内容不会被解析器解析执行,但是会在源码中显示,我们一般会使用注释对程序中的内容进行解释。
- JS中的注释和Java的的一致,分为两种:
- 单行注释:
//注释内容 - 多行注释:
/*注释内容*/
- 单行注释:
标识符
标识符定义
-
所谓标识符,就是指变量、函数、属性的名字,或函数的参数。
-
标识符可以是按照下列格式规则组合起来的一或多个字符:
- – 第一个字符必须是一个字母、下划线( _ )或一个美元符号( $ )
- 其他字符可以是字母、下划线、美元符号或数字。
-
按照惯例,ECMAScript 标识符采用驼峰命名法。
-
但是要注意的是JavaScript中的标识符不能是关键字和保留字
符。
关键字和保留字符
关键字
保留字符
其他不建议使用的标识符
变量
- 变量的作用是给某一个值或对象标注名称。
- 比如我们的程序中有一个值123,这个值我们是需要反复使用的,这个时候
我们最好将123这个值赋值给一个变量,然后通过变量去使用123这个值 - 变量的声明:
- 使用var关键字声明一个变量。
- var a;
- 变量的赋值:
- 使用=为变量赋值。例:a=123;
- 声明和赋值同时进行: var a = 123;
- 使用var关键字声明一个变量。
数据类型
六种数据类型
- 数据类型决定了一个数据的特征,比如:123和”123”,直观上看这两个
数据都是123,但实际上前者是一个数字,而后者是一个字符串。 - 对于不同的数据类型我们在进行操作时会有很大的不同。
- JavaScript中一共有6种基本数据类型:
- 字符串型(String)
- 数值型(Number)
- 布尔型(Boolean)
- null型(Null)
- undefined型(Undefined)
- 这5种之外的类型都称为Object,其中Object为引用数据类型。
String
-
String用于表示一个字符序列,即字符串。
-
字符串需要使用 ’或“ 括起来。
-
转义字符:
-
将其他数值转换为字符串有三种方式:toString()、String()、拼串。
-
String字符串格式
-
在JS中字符串需要使用引号引起来 -
使用双引号或单引号都可以,但是不要混着用 -
引号不能嵌套,双引号不能放双引号,单引号不能放单引号
-
Number
- Number 类型用来表示整数和浮点数,最常用的功能就是用来
表示10进制的整数和浮点数。 - Number表示的数字大小是有限的,范围是:
- ± 1.7976931348623157e+308
- 如果超过了这个范围,则会返回± Infinity。
- NaN,即非数值(Not a Number)是一个特殊的数值(属于一种特殊的Number类型),JS中当对数值进行计算时没有结果返回,则返回NaN,例如
typeof "abc"*"efg"--->NaN。使用typeof检查一个NaN也会返回number,typeof NaN -->number
Boolean(布尔型)
-
布尔型也被称为逻辑值类型或者真假值类型。
-
布尔型只能够取真(true)和假(false)两种数值。除此以外,
其他的值都不被支持。 -
其他的数据类型也可以通过Boolean()函数转换为布尔类型。
-
转换规则:
Undefined
-
Undefined 类型只有一个值,即特殊的 undefined 。
-
在使用 var 声明变量但未对其加以初始化时,这个变量的值就
是 undefined。例如:var b ; console.log(typeof b); //undefined -
需要注意的是typeof对没有初始化和没有声明的变量都会返回
undefined。
Null
-
Null 类型的值只有一个,这个特殊的值是null 。
-
从语义上看null表示的是一个空的对象。所以使用typeof检查
null会返回一个Object。var a = null; console.log(typeof a); //Object -
undefined值实际上是由null值衍生出来的,所以如果比较
undefined和null是否相等,会返回true;
typeof运算符
- 使用typeof操作符可以用来检查一个变量的数据类型。
- 使用方式:typeof 数据,例如 typeof 123。
- 返回结果:
- typeof 数值 返回 number
- typeof 字符串 返回 string
- typeof 布尔型 返回 boolean
- typeof undefined 返回 undefined
- typeof null 返回 object
/*
* 在JS中所有的数值都是Number类型,
* 包括整数和浮点数(小数)
*
* JS中可以表示的数字的最大值
* Number.MAX_VALUE
* 1.7976931348623157e+308
*
* Number.MIN_VALUE 大于0的最小值
* 5e-324
*
* 如果使用Number表示的数字超过了最大值,则会返回一个
* Infinity 表示正无穷
* -Infinity 表示负无穷
* 使用typeof检查Infinity也会返回number
* NaN 是一个特殊的数字,表示Not A Number
* 使用typeof检查一个NaN也会返回number
*/
/*
可以使用一个运算符 typeof
来检查一个变量的类型
语法:typeof 变量
检查字符串时,会返回string
检查数值时,会返回number
* */
/*
* 在JS中整数的运算基本可以保证精确
*/
/*
* 如果使用JS进行浮点运算,可能得到一个不精确的结果
* 所以千万不要使用JS进行对精确度要求比较高的运算
*/
强制类型转换
强制类型转化成String
定义:指将一个数据类型强制转换为其他的数据类型,类型转换主要指,将其他的数据类型,转换为String 、Number、Boolean
方式一:调用被转换数据类型的toString()方法
var a = 12;
a.toString();
console.log(a); //a的值不变,还是Number类型的12
//该方法不会影响到原变量,它会将转换的结果返回
a = a.toString();
console.log(a); //此时的a为String类型的12
//但是注意:null和undefined这两个值没有toString()方法,如果调用他们的方法,会报错
a = null;
a = a.toString(); //报错
a = undefined;
console.log(a); //报错
方式二: 调用String()函数,并将被转换的数据作为参数传递给函数
- 对于Number和Boolean实际上就是调用的toString()方法
- 对于null和undefined,就不会调用toString()方法,它会将 null 直接转换为 "null",将 undefined 直接转换为 "undefined"
var a = 123;
a = 123;
//调用String()函数,来将a转换为字符串
a = String(a);
console.log(typeof a);//string
a = null;
console.log(typeof a);//Object
a = String(a);
console.log(typeof a);//string
a = undefined;
console.log(typeof a);//undefined
a = String(a);
console.log(typeof a);//string
方式三(隐式的类型转换):
为任意的数据类型 +""
例子:
var a = true;
a = a + "";
强制类型转换成Number
转换方式一:
使用Number()函数
- 字符串 --> 数字
- 1.如果是纯数字的字符串,则直接将其转换为数字
- 2.如果字符串中有非数字的内容,则转换为NaN
- 3.如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
- 布尔 --> 数字
- true 转成 1
- false 转成 0
- null --> 数字 0
- undefined --> 数字 NaN
转换方式二:
这种方式专门用来对付字符串
- parseInt() 把一个字符串转换为一个整数
- parseFloat() 把一个字符串转换为一个浮点数
如果对非String使用parseInt()或parseFloat(),它会先将其转换为String然后在操作 parseInt()
a = true;
a = parseInt(a);
console.log(typeof a) //Number
console.log(a) //"true"字符串 ---》 Number 结果:NaN
可以将一个字符串中的有效的整数位提取出来,并转换为Number
例子:
var a = "123.456px";
a = parseInt(a); //123
方式三(隐式的类型转换):
使用一元的+来进行隐式的类型转换
例子:
var a = "123";
a = +a;
转换为布尔值
方式一(强制类型转换):
使用Boolean()函数
例子:
var s = "false";
s = Boolean(s); //true
转换的情况
-
字符串 > 布尔
除了空串其余全是truea = ""; //空串 a = Boolean(a); console.log(a) //false a = " "; //这不是空串,这是包含空格的字符串 a = Boolean(a); console.log(a) //true -
数值 > 布尔
除了0和NaN其余的全是truevar a = 123; //true a = -123; //true a = 0; //false a = Infinity; //true a = NaN; //false //调用Boolean()函数来将a转换为布尔值 a = Boolean(a); -
null、undefined > 布尔
都是falsea = null; //false a = Boolean(a); a = undefined; //false a = Boolean(a); -
对象 > 布尔
都是true
方式二(隐式类型转换):
为任意的数据类型做两次非运算,即可将其转换为布尔值
例子:
var a = "hello";
a = !!a; //true
练习
其他进制的数字
-
在js中,如果需要表示16进制的数字,则需要以0x开头
//十六进制 a = 0x10; console.log(a) //16 -
如果需要表示8进制的数字,则需要以0开头
a = 070; a = parseInt(a); console.log(a); //八进制:56 十进制:70 //向"070"这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析 a = "070"; console.log(a) //IE8 输出56 Chrome输出70 -
如果要要表示2进制的数字,则需要以0b开头,但是不是所有的浏览器都支持
//二进制数字 a = 0b10; console.log(a) //2
运算符
运算符也叫操作符,通过运算符可以对一个或多个值进行运算,并获取运算结果
typeof运算符
typeof就是运算符,可以来获得一个值的类型 它会将该值的类型以字符串的形式返回
var a = 123;
var result = typeof a; //从java知识方面来理解:String result = “Number”
console.log(typeof result); //string
console.log(result); //Number
算数运算符
+?对两个值进行加法运算并返回结果
-?对两个值进行减法运算并返回结果
*?对两个值进行乘法运算并返回结果
*?/?对两个值进行除法运算并返回结果
*?%?对两个值进行取余运算并返回结果
对非Number类型的值进行运算时,都会先转换为Number然后在做运算。
特殊1:任何值和NaN做运算都得NaN
特殊2:任何的值和字符串做加法运算,都会先转换为字符串,然后再和字符串做拼串的操作
练习:
result = a + 1;
result = 456 + 789;
result = true + 1; //2
result = true + false; //1
result = 2 + null; //2
result = 2 + NaN; //NaN
result = 123 + "1"; //1234
result = true + "hello"; //truehello
//任何值和字符串相加都会转换为字符串,并做拼串操作
/*
* 我们可以利用这一特点,来将一个任意的数据类型转换为String
* 我们只需要为任意的数据类型 + 一个 "" 即可将其转换为String
* 这是一种隐式的类型转换,由浏览器自动完成,实际上它也是调用String()函数
*/
var c = 123;
c = c + ""; //转成字符串 123
result = 1 + 2 + "3"; //运算从左到右,33
result = "1" + 2 + 3; //123
result = 100 - 5;
result = 100 - true;
result = 100 - "1"; //字符串p拼接只针对加法运算,99
result = 2 * 2;
result = 2 * "8";
result = 2 * undefined; //undefined 转Number类型-->NaN,即2*NaN---》NaN
result = 2 * null; //null转Number类型---》0,即2*0--》0
一元运算符
正负号
一元运算符,只需要一个操作数
- 正号+
- 正号+不会对数字产生任何影响
- 对于非Number类型的值,它会将先转换为Number,然后在运算,可以对一个其他的数据类型使用+,来将其转换为number,它的原理和Number()函数一样
- 负号
- 负号可以对数字进行负号的取反
自增
自增可以使变量在原值的基础上自增1
自增使用 ++
自增可以使用 前++(++a)后++(a++)
无论是++a 还是 a++都会立即使原变量自增1(这句话我个人不是很赞同,我的理解:++a,先自增后运算;a++:先运算后自增)
不同的是++a和a++的值是不同的,
++a的值是变量的新值(自增后的值)
a++的值是变量的原值(自增前的值)
自减
自减可以使变量在原值的基础上自减1
自减使用
自减可以使用 前(a)后(a)
无论是a 还是 a都会立即使原变量自减1(这句话我个人不是很赞同,我的理解:--a,先自减后运算;a++:先运算后自减)
不同的是a和a的值是不同的,
a的值是变量的新值(自减后的值)
a的值是变量的原值(自减前的值)
var num = 10;
console.log(--num); //9
var a = 1;
//使a自增1
//a++;
//++a;
console.log(a++); //1
console.log("++a = " + ++a); //3
var c = 10;
//第一次c++,是在10的基础上自增
console.log(c++); //10
//第二次c++,是在11的基础上自增
c++;
console.log(c); //11
var d = 20;
//20 + 22 + 22
var result = d++ + ++d + d ;
console.log(result); //20+22+22
逻辑运算符
!
非运算符可以应用于任意值,无论值是什么类型,这个运
算符都会返回一个布尔值。
非运算可以对一个布尔值进行取反,true变false false边true
如果对一个值进行两次取反,它不会变化
如果对非布尔值进行元素,则会将其转换为布尔值,然后再取反,所以我们可以利用该特点,来将一个其他的数据类型转换为布尔值
可以为一个任意数据类型取两次反,来将其转换为布尔值,原理和Boolean()函数一样
var flag = flase;
flag = !flag;
console.log(flag);//true
var a = "abc";
a = !!a;
console.log(a);//true
console.log(typeof a) //boolean
&&
&&可以对符号两侧的值进行与运算
只有两端的值都为true时,才会返回true。只要有一个false就会返回false。
"与"是一个短路的与,如果第一个值是false,则不再检查第二个值
对布尔值做运算时,如果两个值都为true则返回true,否则返回false
对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值
规则:
1.如果第一个值为false,则返回第一个值
2.如果第一个值为true,则返回第二个值
||
||可以对符号两侧的值进行或运算
只有两端都是false时,才会返回false。只要有一个true,就会返回true。
或是一个短路的或,如果第一个值是true,则不再检查第二个值
对布尔值进行运算时,如果两个值都为false则返回false,否则返回true。
对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值
规则:
1.如果第一个值为true,则返回第一个值
2.如果第一个值为false,则返回第二个值
练习:
赋值运算符
= 可以将符号右侧的值赋值给左侧变量
+=
a += 5 //相当于 a = a+5
-=
a -= 5 //相当于 a = a-5
*=
a *= 5 //相当于 a = a*5
/=
a /= 5 //相当于 a = a/5
%=
a %= 5 //相当于 a = a%5
关系运算符
关系运算符用来比较两个值之间的大小关系的
=
<
<=
关系运算符的规则和数学中一致,用来比较两个值之间的关系,
如果关系成立则返回true,关系不成立则返回false。
如果比较的两个值,其中有个值是是非数值(String、boolean、undefined),会将其转换为Number然后再比较。
如果比较的两个值都是字符串,此时会比较字符串的Unicode编码,而不会转换为Number。注意:
任何值和NaN做任何比较都是false
两边都是字符串,比较的是Unicode码,比较字符编码时是一位一位进行比较
? 例如: "abc" 和 “def" 比较,首先是”a"和“d"比较
编码
☠
⚀
相等运算符
、!=、=、!==
相等,判断左右两个值是否相等,如果相等返回true,如果不等返回false
相等会自动对两个值进行类型转换,如果对不同的类型进行比较,会将其转换为相同的类型然后再比较,转换后相等它也会返回true,但是,【null、undefined、NaN】做相等运算符操作时,并没有自动转型;但是如果做关系运算符操作时,null,undefined会被Number()强制转换成数字类型;
console.log(null == 0); //相等运算符操作,false
console.log(null >= 0 ) //关系运算符操作,null自动转型为number类型,null-->0,结果为true
!=
不等,判断左右两个值是否不等,如果不等则返回true,如果相等则返回false
不等也会做自动的类型转换。
===
全等,判断左右两个值是否全等,它和相等类似,只不过它不会进行自动的类型转换,
如果两个值的类型不同,则直接返回false,如果二者类型相同,再比较二者的值
console.log("55" == 55) //true
console.log("55" === 55) //false
!==
不全等,和不等类似,但是它不会进行自动的类型转换,如果两个值的类型不同,它会直接返回true
特殊的值:
null和undefined
由于undefined衍生自null,所以null == undefined 会返回true,这个也比较特殊。
console.log(null == undefined) //true
但是 null === undefined 会返回false。
console.log(null === undefined); //false
NaN
NaN不与任何值相等,包括它自身
console.log(NaN == NaN); //false
判断一个值是否是NaN
使用isNaN()函数
var b = NaN;
console.log(isNaN(b)); //true
练习
条件运算符
条件运算符也叫三元运算符
语法:
条件表达式?语句1:语句2;
-
执行的流程:
-
条件运算符在执行时,首先对条件表达式进行求值,
-
如果该值为true,则执行语句1,并返回执行结果
-
如果该值为false,则执行语句2,并返回执行结果
-
如果条件的表达式的求值结果是一个非布尔值,会将其转换为布尔值然后在运算
"hello"?alert("语句1"):alert("语句2"); //"hello"-->true,接着执行语句1
-
优先级:
和数学中一样,JS中的运算符也是具有优先级的,
比如 先乘除 后加减 先与 后或
具体的优先级可以参考优先级的表格,在表格中越靠上的优先级越高,
优先级越高的越优先计算,优先级相同的,从左往右计算。
优先级不需要记忆,如果越到拿不准的,使用()来改变优先级。
逗号
- 使用逗号可以在一条语句中执行多次操作。
- 比如:var num1=1, num2=2, num3=3;
- 使用逗号运算符分隔的语句会从左到右顺序依次执行。
代码块
- 代码块是在大括号 {} 中所写的语句,以此将多条语句的集合视为一条语句来使用。
例如:
{
var a = 123;
a++;
alert(a);
}
- 我们一般使用代码块将需要一起执行的语句进行分组,需要注意的是,代码块结尾不需要加分号。
- JS中的代码块,只具有分组的的作用,没有其他的用途,代码块内容的内容,在外部是完全可见的
流程控制语句
程序都是自上向下的顺序执行的,
通过流程控制语句可以改变程序执行的顺序,或者反复的执行某一段的程序。
语句的分类:
1.条件判断语句
2.条件分支语句
3.循环语句
条件判断语句
使用条件判断语句可以在执行某个语句之前进行判断,如果条件成立才会执行语句,条件不成立则语句不执行。
语法一:
if(条件表达式){
语句...
}
//if语句在执行时,会先对条件表达式进行求值判断,
// 如果条件表达式的值为true,则执行if后的语句,
// 如果条件表达式的值为false,则不会执行if后的语句。
//if语句只能控制紧随其后的那个语句,
// 如果希望if语句可以控制多条语句,
//可以将这些语句统一放到代码块中
//if语句后的代码块不是必须的,但是在开发中尽量写上代码块,即使if后只有一条语句
语法二:
if...else...语句
当该语句执行时,会先对if后的条件表达式进行求值判断,
如果该值为true,则执行if后的语句;
如果该值为false,则执行else后的语句
if(条件表达式){
语句...
}else{
语句...
}
语法三:
if...else if...else
当该语句执行时,会从上到下依次对条件表达式进行求值判断
如果值为true,则执行当前语句。
如果值为false,则继续向下判断。
如果所有的条件都不满足,则执行最后一个else后的语句
该语句中,只会有一个代码块被执行,一旦代码块执行了,则直接结束语句
if(条件表达式){
语句...
}else if(条件表达式){
语句...
}else if(条件表达式){
语句...
}else if(条件表达式){
语句...
}else{
语句...
}
prompt函数的使用
/*
* prompt()可以弹出一个提示框,该提示框中会带有一个文本框,
* 用户可以在文本框中输入一段内容,该函数需要一个字符串作为参数,
* 该字符串将会作为提示框的提示文字
*
* 用户输入的内容将会作为函数的返回值返回,可以定义一个变量来接收该内容
*/
//score就是小明的期末成绩
var score = prompt("请输入小明的期末成绩(0-100):");
条件分支语句
switch语句
执行流程:
switch…case…语句在执行时,会依次将case后的表达式的值和switch后的条件表达式的值进行全等比较
-
如果比较结果为true,则从当前case处开始执行代码。
- 当前case后的所有的代码都会执行,我们可以在case的后边跟着一个break关键字,这样可以确保只会执行当前case后的语句,而不会执行其他的case
-
如果比较结果为false,则继续向下比较。
-
如果所有的case判断结果都为false,则从default处开始执行代码。
switch(条件表达式){
case 表达式:
语句...
break;
case 表达式:
语句...
break;
case 表达式:
语句...
break;
default:
语句...
break;
}
循环语句
通过循环语句可以反复执行某些语句多次
while循环
- 和if一样while中的条件表达式将会被转换为布尔类型,只要该值为真,则代码块将会一直重复执行。
- 代码块每执行一次,条件表达式将会重新计算。
语法:
while(条件表达式){
语句...
}
执行流程:
while语句在执行时,会先对条件表达式进行求值判断,
如果判断结果为false,则终止循环
如果判断结果为true,则执行循环体
循环体执行完毕,继续对条件表达式进行求值判断,依此类推
do…while循环
语法:
do{
语句...
}while(条件表达式)
执行流程
do…while在执行时,会先执行do后的循环体,然后在对条件表达式进行判断,
如果判断判断结果为false,则终止循环。
如果判断结果为true,则继续执行循环体,依此类推
while和do...while区别
while:先判断后执行
do…while: 先执行后判断
do…while可以确保循环体至少执行一次。
死循环:
//该循环不会停止,除非浏览器关闭,死循环在开发中慎用
//可以使用break,来终止循环
while(true){
...
break;
}
for循环
语法:
for(①初始化表达式 ; ②条件表达式 ; ④更新表达式/迭代条件){
③(循环体)语句...
}
执行流程:
首先执行①初始化表达式,初始化一个变量,(注意:①初始化表达式只执行一次)
然后对②条件表达式进行求值判断,如果为false则终止循环
如果判断结果为true,则执行③循环体
循环体执行完毕,执行④更新表达式,对变量进行更新。
更新表达式执行完毕重复②--》 ③--》④
死循环
while(true){
}
for(;;){
}
break和continue
-
break 和 continue 语句用于在循环中精确地控制代码的执行。
-
使用break语句会使程序立刻退出最近的循环,强制执行循环后边的语句。
-
break和continue语句只在循环和switch语句中使用,主要最外层有循环或者switch就可以。
var j = 2; if(j == 2){ break; //此处的break语句不会执行 } for(var i=0 ; i<5 ; i++){ console.log(i); if(i == 2){ break; //此处的break语句会执行,因为外层有for循环 } } -
使用continue语句会使程序跳过当次循环,继续执行下一次循环,并不会结束整个循环。
for(var i=0 ; i<5 ; i++){ if(i==2){ continue; //当i = 2时,只会跳过本次循环,下次循环从i=3开始 } console.log(i); }
label
? 使用 label 语句可以在代码中添加标签,以便将来使用。
? 语法:
– label: statement
? 例子:
start: for (var i=0; i < count; i++) {
alert(i);
}
outer:
for(var i=0 ; i<5 ; i++){
console.log("@外层循环"+i)
for(var j=0 ; j<5; j++){
break outer; //结束外层循环
console.log("内层循环:"+j);
}
}
? 这个例子中定义的 start 标签可以在将来由 break 或 continue 语句
引用。加标签的语句一般都要与 for 语句等循环语句配合使用
对象(Object)
JS数据类型
JS中数据类型分为基本数据类型和引用数据类型
-
基本数据类型
- String 字符串
- Number
- boolean
- null
- undefined
-
引用数据类型
- 对象(以后我们看到的值,只要不是上边的5种,全都是对象)
对象概念
- 对象是一种复合数据类型,在对象中可以保存多个不同数据类型的属性,它将很多值聚合到一起,可以通过名字访问这些值。使用typeof检查一个对象时,会返回object
- 对象也可以看做是属性的无序集合,每个属性都是一个名/值对。
- 对象除了可以创建自有属性,还可以通过从一个名为原型的对象那里继承属性
对象的分类:
-
内建对象:
由ES标准中定义的对象,在任何的ES的实现中都可以使用;比如:Math String Number Boolean Function Object....
-
宿主对象:
由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象,比如 BOM DOM
-
自定义对象:由开发人员自己创建的对象
创建的对象
方式一:
/*
* 使用new关键字调用的函数,是构造函数constructor
* 构造函数是专门用来创建对象的函数
* 使用typeof检查一个对象时,会返回object
*/
var obj = new Object();
方式二:
使用对象字面量来创建一个对象
var obj = {};
/*
* 使用对象字面量,可以在创建对象时,直接指定对象中的属性
* 语法:{属性名:属性值,属性名:属性值....}
* 对象字面量的属性名可以加引号也可以不加,建议不加,
* 如果要使用一些特殊的名字,则必须加引号
* 属性名和属性值是一组一组的名值对结构,
* 名和值之间使用:连接,多个名值对之间使用,隔开
* 如果一个属性之后没有其他的属性了,就不要写,
*/
var obj2 = {
name:"猪八戒",
age:13,
gender:"男",
test:{name:"沙僧"}
};
向对象中的属性增删改
为对象创建属性
语法:
//语法一:
对象.属性名 = 属性值;
//语法二:
对象[“属性名”] = 属性值; //这种方式能够使用特殊的属性名
对象的属性名没有任何要求,不需要遵守标识符的规范,但是在开发中,尽量按照标识符的要求去写。
属性值也可以任意的数据类型。
如果对象的属性名是一个特殊的属性名,不能采用.的方式来操作,需要使用另一种方式:
语法:对象["属性名"] = 属性值
obj."123" = 789; //控制台有可能报错,不建议用这种方式命名属性名
obj["123"] = 789;//特殊的属性名,需要用 对象["属性名"] = 属性值
读取时也需要采用这种方式
使用[]这种形式去操作属性,更加的灵活,在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性
读取对象中的属性
语法:
//语法一
对象.属性名
//语法二
对象[“属性名”] //"属性名"可以使字符串常量,也可以是字符串变量
如果读取一个对象中没有的属性,它不会报错,而是返回一个undefined
console.log(obj.hello); //,因为obj没有hello属性,,结果为undefined
删除对象的属性
语法:
-
delete 对象.属性名
-
delete 对象["属性名"]
var obj = new Object(); //定义对象
obj.name = "zhangfei"; //创建属性
delete obj.name; //删除属性
console.log(obj.name); //obj对象的属性name已删除,结果为undefined
练习:
从以上的练习学到的知识:
in 运算符:循环遍历对象自身的和继承的可枚举属性(不含Symbol属性).
- 通过该运算符可以检查一个对象中是否含有指定的属性
如果有则返回true,没有则返回false
- 语法:
"属性名" in 对象
js对象属性的特性
- JS对象的属性值,可以是任意的数据类型,甚至也可以是一个对象
var obj = new Object();
var obj2 = new Object();
obj2.name = "猪八戒";
obj.test = obj2; //obj的test属性是一个对象
console.log(obj.test.name); //猪八戒
基本数据类型和引用数据类型的内存结构
基本数据类型的数据,变量是直接保存的它的值。
变量与变量之间是互相独立的,修改一个变量不会影响其他的变量。
引用数据类型的数据,变量是保存的对象的引用(内存地址)。
如果多个变量指向的是同一个对象,此时修改一个变量的属性,会影响其他的变量。
比较两个变量时,对于基本数据类型,比较的就是值,
对于引用数据类型比较的是地址,地址相同才相同,如果两个对象是一摸一样的,但是地址不同,它也会返回false
枚举对象中的属性
语法:
for(var 变量 in 对象){
}
练习
var obj = {
name: "孙悟空",
age: 18,
gender: "男",
address: "花果山"
};
for (var n in obj) {
console.log("属性名:" + n); //name age gender address
console.log("属性值:" + obj[n]); //"孙悟空" "18" "男" "花果山"
}
函数(Function)
函数也是一个对象,也具有普通对象的功能(能有属性)
函数中可以封装一些代码,在需要的时候可以去调用函数来执行这些代码
使用typeof检查一个函数时会返回function
创建函数的三种方式:①构造函数、②函数声明、③函数表达式
调用函数 语法:函数对象()
构造函数
创建一个函数对象,用typeof检查:
var fun = new Function();
console.log(typeof fun); //Function
//我们在实际开发中很少使用构造函数来创建一个函数对象
//创建一个函数对象
//可以将要封装的代码以字符串的形式传递给构造函数
var fun = new Function("console.log('Hello 这是我的第一个函数');");
//封装到函数中的代码不会立即执行
//函数中的代码会在函数调用的时候执行
//调用函数 语法:函数对象()
//当调用函数时,函数中封装的代码会按照顺序执行
fun();
函数声明
function 函数名([形参1,形参2...形参N]){
语句...
};
//函数调用
函数名();
函数表达式
var 函数名 = function([形参1,形参2...形参N]){
语句...
};
调用函数
语法:函数对象([实参1,实参2…实参N]);
fun() sum() alert() Number() parseInt()
当我们调用函数时,函数中封装的代码会按照编写的顺序执行
立即执行函数
函数定义完,立即被调用,这种函数叫做立即执行函数
立即执行函数往往只会执行一次
/*(function(){
alert("我是一个匿名函数~~~");
})();*/
(function(a,b){
console.log("a = "+a);
console.log("b = "+b);
})(123,456);
其他
遍历对象
for(var v in obj){
document.write("property:name ="+v+"value="+obj[v]+"
" );
}
形参和实参
形参:形式参数
定义函数时,可以在()中定义一个或多个形参,形参之间使用,隔开
定义形参就相当于在函数内声明了对应的变量但是并不赋值,形参会在调用时才赋值。
function sum(a,b){
console.log("a = "+a);
console.log("b = "+b);
console.log(a+b);
}
/*
* 在调用函数时,可以在()中指定实参(实际参数)
* 实参将会赋值给函数中对应的形参
*/
sum(1,2);
实参:实际参数(实参可以是任意类型)
调用函数时,可以在()传递实参,传递的实参会赋值给对应的形参,
调用函数时JS解析器不会检查实参的类型和个数,可以传递任意数据类型的值。
如果实参的数量大于形参,多余实参将不会赋值,
function sum(a , b ){
var d = a + b ;
return d;
}
sum(1,2,3); //多余实参将不会赋值,即3无法赋值
如果实参的数量小于形参,则没有对应实参的形参将会赋值undefined
function sum(a , b ){
console.log(a); //1
console.log(b); //undefined
}
sum(1);
返回值,就是函数执行的结果。
使用return 来设置函数的返回值。
语法:return 值;
该值就会成为函数的返回值,可以通过一个变量来接收返回值
return后边的代码都不会执行,一旦执行到return语句时,函数将会立刻退出。
function sum(a , b , c){
//alert(a + b +c);
var d = a + b + c;
return d;
console.log(11); //前面有return 语句,该语句不会执行
}
return后可以跟任意类型的值,可以是基本数据类型,也可以是一个对象。
如果return后不跟值,或者是不写return则函数默认返回undefined。
function sum(a , b , c){
return ; //return后不跟值,或者是不写return则函数默认返回undefined。
console.log(11); //前面有return 语句,该语句不会执行
}
//不写return则函数默认返回undefined。
function sum(a , b , c){
console.log(11); //前面有return 语句,该语句不会执行
}
//调用函数
//变量result的值就是函数的执行结果
//函数返回什么result的值就是什么
var result = sum(4,7,8);
break、continue和return
break
退出当前循环
continue
跳过当次循环
return
退出函数
练习,注:返回值可以是任意的数据类型
对象的属性值可以是任何的数据类型,也可以是个函数
var obj = new Object();
obj.name = "zhangsan"
obj.sayName = function(){ //对象的属性值也可以是个函数
console.log(obj.name);
};
function fun(){
console.log(obj.name);
};
obj.sayName(); //调用方法
fun(); //调用函数
var obj2 = {
name:"猪八戒",
age:18,
sayName:function(){ //定义方法
console.log(obj2.name);
}
};
obj2.sayName();
注:
函数和方法的区别:
没有区别,只是叫法不同;函数在对象里叫方法;不在对象中叫函数
函数也可以称为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数时这个对象的方法调用这个函数就说调用对象的方法(method)
eval()函数
/*
* eval()
* - 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回
* - 如果使用eval()执行的字符串中含有{},它会将{}当成是代码块
* 如果不希望将其当成代码块解析,则需要在字符串前后各加一个()
*
* - eval()这个函数的功能很强大,可以直接执行一个字符串中的js代码,
* 但是在开发中尽量不要使用,首先它的执行性能比较差,然后它还具有安全隐患
*/
作用域
作用域简单来说就是一个变量的作用范围。
在JS中作用域分成两种:
1.全局作用域
直接在script标签中编写的代码都运行在全局作用域中
全局作用域在打开页面时创建,在页面关闭时销毁。
全局作用域中有一个全局对象window,window对象由浏览器提供,可以在页面中直接使用,它代表的是整个的浏览器的窗口。
在全局作用域中创建的变量都会作为window对象的属性保存
在全局作用域中创建的函数都会作为window对象的方法保存
在全局作用域中创建的变量和函数可以在页面的任意位置访问。
在函数作用域中也可以访问到全局作用域的变量。
尽量不要在全局中创建变量
变量的声明提前和函数的声明提前
-
变量的声明提前
-
使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值), 但是如果声明变量时
不使用var关键字,则变量不会被声明提前
-
console.log("a = "+a); //undefined
var a = 123; //相当于在最前面声明a变量 var a;
console.log("b = "+b); //报错:b is not defined
b = 123;
函数的声明提前
使用函数声明形式创建的函数 function 函数(){},它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数,使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
fun(); //正常输出:我是一个fun函数
//函数声明,会被提前创建
function fun(){
console.log("我是一个fun函数");
}
fun2(); //报错:fun2 is not a function
//函数表达式,不会被提前创建
var fun2 = function(){
};
2.函数作用域
函数作用域是函数执行时创建的作用域,每次调用函数都会创建一个新的函数作用域。
函数作用域在函数执行时创建,在函数执行结束时销毁。
在函数作用域中创建的变量,不能在全局中访问。
当在函数作用域中使用一个变量时,它会先在自身作用域中寻找,
如果有就直接使用
如果没有则向上一级作用域中寻找,直到找到全局作用域,
如果全局作用域中依然没有找到,则会报错ReferenceError
/*
* 在函数作用域也有声明提前的特性,
* 使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
* 函数声明也会在函数中所有的代码执行之前执行
*/
function fun3() {
fun4();
console.log(a); //undefined
var a = 35; //在函数作用域最前面声明 var = a;
function fun4() { //在函数fun3最前面声明函数fun4
alert("I'm fun4");
}
}
在函数中要访问全局变量可以使用window对象
在函数中,不使用var声明的变量都会成为全局变量
/*
* 在函数中,不使用var声明的变量都会成为全局变量
*/
function fun5() {
//d没有使用var关键字,则会设置为全局变量
d = 100;
}
fun5();
//在全局输出c
console.log("d = " + d);
定义形参就相当于在函数作用域中声明了变量
/*
* 定义形参就相当于在函数作用域中声明了变量
*/
function fun6(e) {
//形参e,相当于在fun6中定义了一个局部变量
//var e;
alert(e);
}
fun6(); //调用fun6时,没有传参数,相当于只声明了e,没有赋值,所以当执行alert(e)时,输出undefined
this(上下文对象)
我们每次调用函数时,解析器(浏览器引擎) 都会将一个上下文对象作为隐含的参数传递进函数。
使用this来引用上下文对象,根据函数的调用形式不同,this的值也不同。
this指向当前对象
this的不同的情况:
1.以函数的形式调用时,this是window
function fun() {
console.log(this.name); //全局name
}
//创建一个对象
var obj = {
name: "所悟空",
sayName: fun
}
var name = "全局name";
//以函数形式调用,this是window
fun();
2.以方法的形式调用时,this就是调用方法的对象
function fun() {
console.log(this.name); //所悟空
}
//创建一个对象
var obj = {
name: "所悟空",
sayName: fun
}
var name = "全局name";
//以方法的形式调用,this是调用方法的对象
obj.sayName();
3.以构造函数的形式调用时,this就是新创建的对象
构造函数
构造函数是专门用来创建对象的函数
一个构造函数我们也可以称为一个类
通过一个构造函数创建的对象,我们称该对象时这个构造函数的实例
通过同一个构造函数创建的对象,我们称为一类对象
构造函数就是一个普通的函数,只是他的调用方式不同,
如果直接调用,它就是一个普通函数
如果使用new来调用,则它就是一个构造函数
例子:
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function(){
alert(this.name);
};
}
var per = new Person("孙悟空",18,"男"); //使用new来调用,则Person就是一个构造函数
构造函数的执行流程:
1.创建一个新的对象
2.将新的对象作为函数的上下文对象(this)
3.执行函数中的代码
4.将新建的对象返回
instanceof 用来检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数
如果该对象是构造函数的实例,则返回true,否则返回false
Object是所有对象的祖先,所以任何对象和Object做instanceof都会返回true
Dog(){
}
var dog = new Dog();
console.log(dog instanceof Object); //true
原型(prototype)
-
创建一个函数以后,解析器都会默认在函数中添加一个数prototype
prototype属性指向的是一个对象,这个对象我们称为原型对象。function MyClass(){ //prototype属性默认在MyClass函数中,prototype默认指向一个原型对象 }
-
当函数作为构造函数使用,它所创建的对象中都会有一个隐含的属性指向该原型对象。我们可以通过__proto__来访问该原型对象
var mc = new MyClass(); //有一个隐含属性__prototype__ var mc2 = new MyClass(); var mc3 = new MyClass();
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
- 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
- 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。
我们可以将对象中共有的属性和方法统一添加到原型对象中,
这样我们只需要添加一次,就可以使所有的对象都可以使用。
当我们去访问对象的一个属性或调用对象的一个方法时,它会先自身中寻找,
如果在自身中找到了,则直接使用。
如果没有找到,则去原型对象中寻找,如果找到了则使用,
如果没有找到,则去原型的原型中寻找,依此类推。直到找到Object的原型为止,Object的原型的原型为null,
如果依然没有找到则返回undefined
使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
hasOwnProperty()
这个方法可以用来检查对象自身中是否含有某个属性
语法:对象.hasOwnProperty(“属性名”)
/*
* 原型对象也是对象,所以它也有原型,
* 当我们使用一个对象的属性或方法时,会在自身中寻找,
* 自身中如果有,则直接使用,
* 如果没有则去原型对象中寻找,如果原型对象中有,则使用,
* 如果没有则去原型的原型中寻找,直到找到Object对象的原型,
* Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
*/
toString方法
当我们直接在页面中打印一个对象时,事实上是输出的对象的toString()方法的返回值
如果我们希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
}
var per = new Person("孙悟空",18,"男");
console.log(per.toString()) //[object Object]
console.log(per) //相当于 console.log(per。toString())
Person.prototype.toString() = function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
};
console.log(per.toString()) //Person[name=孙悟空,age=18,gender=男]
垃圾回收(GC)
就像人生活的时间长了会产生垃圾一样,程序运行过程中也会产生垃圾
这些垃圾积攒过多以后,会导致程序运行的速度过慢,
所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾
当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,
此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,
所以这种垃圾必须进行清理。
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,
我们不需要也不能进行垃圾回收的操作
我们需要做的只是要将不再使用的对象设置null即可
数组(Array)
数组也是一个对象,是一个用来存储数据的对象和Object类似,但是它的存储效率比普通对象要高
数组中保存的内容我们称为元素
普通对象使用字符串作为属性名,数组使用索引(index)来操作元素
索引指由0开始的整数
数组的操作:
创建数组
var arr = new Array();
var arr1 = new Array(1,2,3,4);
//或者使用字面量来创建数组
var arr = [];
var arr1 = [1,2,3,4];
向数组中添加元素
语法;
数组对象[索引] = 值;
arr[0] = 123;
arr[1] = "hello";
创建数组时直接添加元素
语法:
var arr = [元素1,元素2....元素N];
//例如
var arr = [123,"hello",true,null];
获取和修改数组的长度
使用length属性来操作数组的长度
获取长度:
数组.length
对于非连续的数组,length获取到的是数组的最大索引+1
对于连续的数组,length获取到的就是数组中元素的个数
//连续
var arr = new Array();
arr[0] = 0;
arr[1] = 1
console.log(arr.length); //2
//非连续
var arr1 = new Array();
arr1[0] = 0;
arr1[10] = 10;
console.log(arr1.length) // 11
修改数组的长度
数组.length = 新长度
如果修改后的length大于原长度,则多出的部分会空出来
var arr = new Array();
arr[0] = 1;
arr[1] = 3;
arr[2] = 2;
arr.length = 6;
console.log(arr);
如果修改后的length小于原长度,则原数组中多出的元素会被删除
var arr = new Array();
arr[0] = 1;
arr[1] = 3;
arr[2] = 2;
arr.length = 2;
console.log(arr);
向数组的最后添加元素
由于length会获取到数组的最大的索引+1,数组[数组.length] = 值;
var arr = new Array();
arr[arr.length] = 70;
arr[arr.length] = 80;
arr[arr.length] = 90;
console.log(arr); //70,80,90
数组遍历
//创建一个数组
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
//遍历方式一:
for(var i=0 ; i
数组的方法
slice(sart,[end])
可以从一个数组中截取指定的元素
该方法不会影响原数组,而是将截取到的内容封装为一个新的数组并返回
参数:
1.截取开始位置的索引(包括开始位置) (左闭右开)
2.截取结束位置的索引(不包括结束位置)
第二个参数可以省略不写,如果不写则一直截取到最后
参数可以传递一个负值,如果是负值,则从后往前数
splice()
/*
* splice()
* - 可以用于删除数组中的指定元素
* - 使用splice()会影响到原数组,会将指定元素从原数组中删除
* 并将被删除的元素作为返回值返回
* - 参数:
* 第一个,表示开始位置的索引
* 第二个,表示删除的数量
* 第三个及以后。。
* 可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
*/
arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
var result = arr.splice(3,0,"牛魔王","铁扇公主","红孩儿"); //从索引3开始,删除0个元素,添加"牛魔王","铁扇公主","红孩儿"3个元素
console.log(result); //"孙悟空","猪八戒","沙和尚","唐僧","牛魔王","铁扇公主","红孩儿","白骨精"
join([splitor])
可以将一个数组转换为一个字符串
该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
参数:
需要一个字符串作为参数,这个字符串将会作为连接符来连接数组中的元素
如果不指定连接符则默认使用逗号
arr = ["孙悟空","猪八戒","沙和尚","唐僧"];
result = arr.join("@-@");
sort()
可以对一个数组中的内容进行排序,默认是按照Unicode编码进行排序,所以对数字进排序时,可能会得到错误的结果
调用以后,会直接修改原数组。
我们可以自己来指定排序的规则,我们可以在sort()添加一个回调函数,来指定排序规则,
? -回调函数中需要定义两个形参,浏览器将会分别使用数组中的元素作为实参去调用回调函数,使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边
-浏览器会根据回调函数的返回值来决定元素的顺序,
? 如果返回一个大于0的值,则元素会交换位置
? 如果返回一个小于0的值,则元素位置不变
? 如果返回一个0,则认为两个元素相等,也不交换位置
? -如果需要升序排列,则返回 a-b,如果需要降序排列,则返回b-a
arr = [5,4,2,1,3,6,8,7];
arr.sort(function(a,b){
//升序排列
//return a - b;
//降序排列
return b - a;
});
concat()
可以连接两个或多个数组,并将新的数组返回,该方法不会对原数组产生影响
var arr = ["孙悟空","猪八戒","沙和尚"];
var arr2 = ["白骨精","玉兔精","蜘蛛精"];
var arr3 = ["二郎神","太上老君","玉皇大帝"];
var result = arr.concat(arr2,arr3,"牛魔王","铁扇公主");
reverse()
该方法用来反转数组(前边的去后边,后边的去前边),该方法会直接修改原数组
arr = ["b","d","e","a","c"];
arr.reverse();
函数对象的方法
call()和apply()
-
这两个方法都是函数对象的方法,需要通过函数对象来调用
-
当函数调用call()和apply()时都会调用函数自身的执行
function fun(a,b) { console.log("a = "+a); console.log("b = "+b); } fun.call();//执行call()方法的同时,也执行fun()函数 -
在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
function fun(a,b) { console.log(this); // 这个对象为obj } var obj = { name: "obj", sayName:function(){ alert(this.name); } fun.call(obj); //fun.apply(obj); -
call()方法可以将实参在对象之后依次传递
fun.call(obj,2,3); //obj 是对象,2和3是实参 -
apply()方法需要将实参封装到一个数组中统一传递
fun.apply(obj,[2,3]);
arguments方法
/*
* 在调用函数时,浏览器每次都会传递进两个隐含的参数:
* 1.函数的上下文对象 this
* 2.封装实参的对象 arguments
* - arguments是一个类数组对象(arguments不是数组类型,只能说argument用法很像数组),它也可以通过索引来操作数据,也可以获取长度
* - 在调用函数时,我们所传递的实参都会在arguments中保存
* - arguments.length可以用来获取实参的长度
* - 我们即使不定义形参,也可以通过arguments来使用实参,只不过比较麻烦
* arguments[0] 表示第一个实参
* arguments[1] 表示第二个实参 。。。
* - 它里边有一个属性叫做callee,
* 这个属性对应一个函数对象,就是当前正在指向函数的对象
*/
function fun(){
console.log(arguments instanceof Array); //false,arguments不是数组
console.log(Array.isArray(arguments)); //false
//console.log(arguments[1]);
//console.log(arguments.length);
console.log(arguments.length);
console.log(arguments.callee);
console.log(arguments.callee == fun); //true
}
fun("hello",true);
包装类
在JS中为我们提供了三个包装类:
String() Boolean() Number()
通过这三个包装类可以创建基本数据类型的对象
例子:
var num = new Number(2);
var str = new String("hello");
var bool = new Boolean(true);
但是在实际应用中千万不要这么干。
当我们去操作一个基本数据类型的属性和方法时,
解析器会临时将其转换为对应的包装类,然后再去操作属性和方法,
操作完成以后再将这个临时对象进行销毁。
var s = 123;
//s变量首先会转成Number类型的对象,Number类型的对象添加一个hello属性,值为"你好";
//当执行完这整条语句时,Number对象会被销毁
s.hello = "你好";
console.log(s.hello); //s变量重新转Number类型对象,但是没有hello属性了,undefined
console.log(typeof s); //string
Date
日期的对象,在JS中通过Date对象来表示一个时间
创建对象
创建一个当前的时间对象
var d = new Date();
console.log(d); //Sat Nov 13 2021 11:25:38 GMT+0800 (中国标准时间)
创建一个指定的时间对象,需要在构造函数中传递一个表示时间的字符串作为参数
日期的格式 月份/日/年 时:分:秒
var d2 = new Date("2/18/2011 11:10:30");
console.log(d2); //Fri Feb 18 2011 11:10:30 GMT+0800 (中国标准时间)
方法:
getDate():获取当前日期对象是几日
var d2 = new Date("2/18/2011 11:10:30");
console.log(d2); //Fri Feb 18 2011 11:10:30 GMT+0800 (中国标准时间)
/*
* getDate()
* - 获取当前日期对象是几日
*/
var date = d2.getDate();
console.log(date); //18
getDay():获取当前日期对象时周几
- 会返回一个0-6的值
- 0 表示周日
- 1表示周一
var d2 = new Date("2/18/2011 11:10:30");
var day = d2.getDay();
console.log(day); //5
getMonth():获取当前时间对象的月份
会返回一个0-11的值
- 0 表示1月
- 1 表示2月
- 11 表示12月
var d2 = new Date("2/18/2011 11:10:30");
var month = d2.getMonth();
console.log(month); //1
getFullYear() :获取当前日期对象的年份
var year = d2.getFullYear();
console.log(year); //2011
getTime():获取当前日期对象的时间戳
- 时间戳,指的是从格林威治标准时间的1970年1月1日,0时0分0秒, 到当前日期所花费的毫秒数(1秒 = 1000毫秒)
- 计算机底层在保存时间时使用都是时间戳
var d3 = new Date("1/1/1970 0:0:0");
time = d3.getTime();
console.log(time); //-28800000
Date.now():获取当前的时间戳
var start = Date.now();
console.log(start); //1636775545722
Math
Math属于一个工具类(类似Java的静态类),它不需要我们创建对象,它里边封装了属性运算相关的常量和方法
我们可以直接使用它来进行数学运算相关的操作
注释:Math 对象并不像 Date 和 String 那样是对象的类,因此没有构造函数 Math(),像 Math.sin() 这样的函数只是函数,不是某个对象的方法。您无需创建它,通过把 Math 作为对象使用就可以调用其所有属性和方法。
字符串的相关的方法
正则表达式
正则用来定义一些字符串的规则,程序可以根据这些规则来判断一个字符串是否符合规则,
也可以将一个字符串中符合规则的内容提取出来。
创建正则表达式方式一:
语法:
var 变量 = new RegExp("正则表达式","匹配模式"); //匹配模式可以不写
使用typeof检查正则对象,会返回object
var reg = new RegExp("a"); 这个正则表达式可以来检查一个字符串中是否含有a
在构造函数中可以传递一个匹配模式作为第二个参数,
? - i 忽略大小写 (ignore)
? -g 全局匹配模式(global)
练习:
var reg = new RegExp("ab","i");
console.log(reg.test("abc")); //true
console.log(typeof reg); //object
创建正则表达式二:
var 变量 =/正则表达式/
var 变量 =/正则表达式/匹配模式 例如:var reg = /a/i //判断某个字符串是否含有a且忽略大小写
练习:
var reg = /ab/i
console.log(reg.test("abc")); //true
console.log(typeof reg); //object
正则语法
| 或
[] 或
【^ 】 除了
reg = /[^ab]/; //字符串中是否包含除了a和b的其他字符串
console.log(reg.text("abc")); //true
[a-z] 小写字母 (也可以[e-i])
[A-Z] 大写字母
[A-z] 任意字母,但是还包括了其他ASCII在此之中的
[0-9] 任意数字
支持正则表达式的 String 对象的方法
split()
var str = "1a2b3c4d5e6f7";
/*
* split()
* - 可以将一个字符串拆分为一个数组
* - 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
* - 这个方法即使不指定全局匹配,也会全都插分
*/
/*
* 根据任意字母来将字符串拆分
*/
var result = str.split(/[A-z]/);
console.log(result);
search()
/*
* search()
* - 可以搜索字符串中是否含有指定内容
* - 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1
* - 它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串
* - serach()只会查找第一个,即使设置全局匹配也没用
*/
var str = "hello abc hello aec afc";
/*
* 搜索字符串中是否含有abc 或 aec 或 afc
*/
result = str.search(/a[bef]c/);
console.log(result); //6
match()
/*
* match()
* - 可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
* - 默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索
* 我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
* 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
* - match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
*/
str = "1a2a3a4a5e6f7A8B9C";
result = str.match(/[a-z]/ig);
console.log(result);
replace()
/*
* replace()
* - 可以将字符串中指定内容替换为新的内容
* - 参数:
* 1.被替换的内容,可以接受一个正则表达式作为参数
* 2.新的内容
* - 默认只会替换第一个
*/
str = "1a2a3a4a5e6f7A8B9C";
result = str.replace(/[a-z]/gi , "");
console.log(result); //123456789
量词
/*
* 量词
* - 通过量词可以设置一个内容出现的次数
* - 量词只对它前边的一个内容起作用
* - {n} 正好出现n次
* - {m,n} 出现m-n次
* - {m,} m次以上
* - + 至少一个,相当于{1,}
* - * 0个或多个,相当于{0,}
* - ? 0个或1个,相当于{0,1}
*/
元符号
/*
* . 任意一个符号
* \w
* - 任意字母、数字、_ [A-z0-9_]
* \W
* - 除了字母、数字、_ [^A-z0-9_]
* \d
* - 任意的数字 [0-9]
* \D
* - 除了数字 [^0-9]
* \s
* - 空格
* \S
* - 除了空格
* \b
* - 单词边界
* \B
* - 除了单词边界
*/
/*
* 检查一个字符串中是否以a开头
* ^ 表示开头
* $ 表示结尾
*/
注:检查一个字符串中是否含有 . ,在正则表达式中使用\作为转义字符,如\.
var reg1 = /./; //任意字符
var reg2 = /\./; //转义后,单纯代表 .
//(相当于reg2)转义后,单纯代表 .
//理解:直接用字符串做正则表达式,遇到特殊字符需要转义, \\-->\,所以\\.--->\. 相当于var = reg2 = /\./
var reg3 = new RegExp("\\.");
console.log(reg1.test("agb")) //true
console.log(reg2.test("agb")) //false
console.log(reg2.test("agb.")) //true
console.log(reg3.test("agb.")) //true
DOM
dom介绍
- DOM,全称Document Object Model文档对象模型。
- JS中通过DOM来对HTML文档进行操作。只要理解了DOM就可以随心所欲的操作WEB页面。
- 文档(Document)
- 文档表示的就是整个的HTML网页文档
- 对象(Object)
- 对象表示将网页中的每一个部分都转换为了一个对象。
- 模型(Model)
- 使用模型来表示对象之间的关系,这样方便我们获取对象。
节点
-
节点Node,是构成我们网页的最基本的组成部分,网页中的每一个部分都可以称为是一个节点。
-
比如:html标签、属性、文本、注释、整个文档等都是一个节点。
-
虽然都是节点,但是实际上他们的具体类型是不同的。
-
比如:标签我们称为元素节点、属性称为属性节点、文本称为文本节点、文档称为文档节点。
-
节点的类型不同,属性和方法也都不尽相同。
-
节点:Node——构成HTML文档最基本的单元。
常用节点分为四类- 文档节点:整个HTML文档
- 元素节点:HTML文档中的HTML标签
- 属性节点:元素的属性
- 文本节点:HTML标签中的文本内容
节点的属性
文档节点(document)
- 文档节点document,代表的是整个HTML文档,网页中的所有节点都是它的子节点。
- document对象作为window对象的属性存在的,可以直接使用。
- 通过该对象我们可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。
元素节点(Element)
- HTML中的各种标签都是元素节点,这也是我们最常用的一个节点。
- 浏览器会将页面中所有的标签都转换为一个元素节点,我们可以通过document的方法来获取元素节点。
比如:
– document.getElementById()
– 根据id属性值获取一个元素节点对象。
属性节点(Attr)
-
属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。
-
可以通过元素节点来获取指定的属性节点。
? 例如:
– 元素节点.getAttributeNode("属性名");注意:我们一般不使用属性节点。
文本节点(Text)
- 文本节点表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点。
- 它包括可以字面解释的纯文本内容。
- 文本节点一般是作为元素节点的子节点存在的。
- 获取文本节点时,一般先要获取元素节点。再通过元素节点获取文本节点。
例如:
– 元素节点.firstChild;
– 获取元素节点的第一个子节点,一般为文本节点
事件
- 事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间,简单理解:就是用户和浏览器之间的交互行为。
- JavaScript 与 HTML 之间的交互是通过事件实现的。
- 对于 Web 应用来说,有下面这些代表性的事件:点击某个元素、将鼠标移动至某个元素上方、按下键盘上某个键,等等。
绑定事件的方式:
1.可以在标签的事件属性中设置相应的JS代码
例子:
2.可以通过为对象的指定事件属性设置回调函数的形式来处理事件
例子: