目录
一、数据类型
Number Boolean Null Undefined
1.强制转换类型:
①.转换为Number
②.其他进制的数字
十六进制 :a = 0X10
八进制:a = 070
像这种070 当我们用parseInt进行转换的时候,有的浏览器会把它当作八进制数字,转换出来就是56
而有的浏览器,就是把它当作普通的070,也就是十进制,那他转换出来是70
那么我们为了指定它,需要加上10或者8↓
a = "070"
a = parseInt(a,10)====70
a = parseInt(a,8)====56
a = "070"
a = parseInt(a,8)
console.log(typeof a)
console.log(a)
在js中,如果需要表示16禁止的数字,则需要以0X开头,
如果需要表示8进制的数字,则需要以0开头,
如果表示二进制的数字,则需要以0b开头,但是不是所有的浏览器都支持
转换为Boolean
//
使用Boolean()函数
数字---->布尔
除了0和NaN,其余都是true
var a = 123;
// 调用Boolean()函数来将a转化为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----true
-----boolean
===========================
var a = 0;
// 调用Boolean()函数来将a转化为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----false
-----boolean
===========================
var a = NaN;
// 调用Boolean()函数来将a转化为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----false
-----boolean
===========================
var a = Infinity;
// 调用Boolean()函数来将a转化为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----true
-----boolean
字符串---->布尔
除了空串,其余都是true
null和undefined都会转换为false
对象也会转换为true
var a = "Hello JS"
//使用Boolean()函数来将a转换为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----true
-----boolean
===========================
var a = "" <----空串
//使用Boolean()函数来将a转换为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----false
-----boolean
===========================
var a = " "
//使用Boolean()函数来将a转换为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----true
-----boolean
===========================
var a = null
//使用Boolean()函数来将a转换为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----false
-----boolean
===========================
var a = undefined
//使用Boolean()函数来将a转换为布尔值
a = Boolean(a)
console.log(a)
console.log(typeof a)
-----false
-----boolean
===========================
二、运算符
运算符也叫操作符
通过运算符可以对一个或多个值进行运算,并获取运算结果
比如:typeof就是一个运算符,可以来获得一个值的类型,它会将该值的类型以字符串的形式返回
number string boolean undefined null object
算数运算符
当对非Number类型的值进行运算时,会将这些值转换为Number然后再运算
result = 2 + null
result = 2 + NaN <=====任何值和NaN做运算,结果都得NaN
+可以对两个值进行加法运算,并将结果返回 result = true + 1
var result = 2 + null
console.log("result="+result)
------result = 2
这里null为非Number类型的值,先将null转换为Number值为0,然后再运算,结果为2,
相当于进行了此操作↓
var a = null
a = Number(a)
console.log(a)
---------0
var result = 2 + NaN
console.log("result="+result)
-------NaN
var result = true + 1
console.log(result)
-----------2
将布尔值转换为number值 为1
如果对两个字符串进行加法运算,会将两个字符串进行拼接,拼串,拼接成一个字符串并返回,result = "你好"+"明天"
任何的值和字符串做加法运算,都会先转换为字符串,然后再和字符串进行拼串的操作,
result = "你好"+"明天"
console.log("result="+result)
------result=你好明天
result = "你好"+1
console.log("result="+result)
------result=你好1
result = 1+2+"3"
console.log(result)
-------33
我们可以利用这一特点,来将一个任意的数据类型转换为String,我们只需要为任意的数据类型+一个""即可将其转换为String
这是一种隐式类型转换,由浏览器自动完成,实际上它也是调用String()函数
↑var c = 123
c = c + ""; <=======> c = String(c);
var c = 123
console.log(typeof c) -----number
c = c+""
console.log(typeof c) -----String
-
-可以对两个值进行减法运算,并将结果返回 result = 100-"1" ====99
*
/
任何值和- * /运算时都会自动转换为Number
我们可以利用这一特点做隐式的类型转换,可以通过为一个值-0 *1 /1来将其转换为Number
原理和Number()函数一样,但是使用起来更加简单
var result = "1"
console.log(typeof result) ------string
result = "1"-0
console.log(typeof result) ------number
%
取模运算(取余数)
var a = 9%4
console.log(a)
------1
一元运算符:
只需要一个操作数
+ 正号
+不会对数字产生任何影响
- 负号
-可以对数字进行负号的取反
var a = 123
a = -a
console.log("a="+a) ===-123
对于非Number类型的值,它会先转换为Number,然后再运算
可以对一个其他的数据类型使用+,来将其转换为number
它的原理和Number()函数一样
var b = "123"
console.log(typeof b) ------string
b = +b
console.log(typeof b) ------number
自增 自减:
自增 ++
通过自增可以使变量在自身的基础上增加1,对于一个变量自增以后,原变量的值会立即自增1
自增分为两种:后++(a++),和前++(++a)
无论是a++还是++a都会立即使原变量的值自增1
不同的是a++和++a的值不同
a++的值等于原变量的值(自增前的值)
var c = 10;
// 第一次c++,是在10的基础上自增,此时c为11,下次在11的基础上自增↓
console.log(c++) -------------------10
console.log(c) -------------------11
// 第二次c++是在11的基础上自增,此时c为12
console.log(c++) -------------------11
console.log(c) -------------------12
++a的值等于原变量新值(自增后的值)
var d = 20;
console.log(++d) ====21
console.log(d) ====21
看+号在哪儿,在前边就先加1,在后边就后加1,++本质上都是让原值自增,a++是先赋值再自增,++a是先自增再赋值
自减-- 原理同上
var d = 20
20 + 22 +22
result = d++ + ++d +d
d++为20,此时d为21,++d,先自增,所以在21的基础上自增,++d为22,此时d也为22,
console.log("result="+result) -------64
逻辑运算符:
JS中为我们提供了三种逻辑运算符
!非
!可以用来对一个值进行非运算
所谓非运算就是指对一个布尔值进行取反操作
如果对一个值进行两次取反,他不会变化
如果对非布尔值进行运算,则会将其先转换为布尔值然后再取反
我们可以利用该特点,来将一个其他的数据类型转换为布尔值
可以对一个任意数据类型取两次反,来将其转换为布尔值
原理和Boolean()函数一样
&&与
可以对符号两侧的值进行与运算,并返回结果
如果两个值都是true则返回true,只要有一个false就会返回false
var result = true&&true
console.log(result) =======true
var result = true&&false
console.log(result) =======false
var result = false&&false
console.log(result) =======false
||或
可以对符号两侧的值进行或运算并返回结果
运算规则:两个都为false 结果为false,只要有一个true,结果就为true
var result = false || true
console.log(result) ======true
var result = false || false
console.log(result) =====false
var result = true || true
console.log(result) =====true
非布尔值的情况
对于非布尔值进行或运算时,会将其转换为布尔值,然后再运算,并且返回原值
与运算:如果两个值都为true,那么返回后边的值
var result = 1 && 2;
console.log("result="+result) =====>2
如果有一个值为false,则返回false那个值
result = 2 && 0
console.log("result="+result)=======>0
如果两个值都是false,那么返回前边的
result = NaN && 0
console.log("result="+result)=======>NaN
总结:
与运算:如果第一个值为true,则必然返回第二个值(&&)
如果第一个值为false,则直接返回第一个值(与运算中,两个都是ture才会返回true,只要有一个false就会返回false,)
或运算:如果第一个值为true,则直接返回第一个值,(||),如果第一个值为false,则直接返回第二个值
(因为或运算中只要有一个值为true就会返回true,恰好第一个值为true,那不必看第二个,第二个无论true还是false,都会返回true)
(第一个已经是false了,第二个如果是true,会返回true,如果是false,那么返回false,所以不管是谁,都会直接返回第二个值)
赋值运算符:
=
可以将符号右侧的值赋值给符号左侧的变量
var a = 123;
console.log(a)
//把123赋值给a
+=
a = a +5
等价于a+=5
-=
a = a-5等价于a-=5
*=
a=a*5等价于 a*=5
/=
a=a/5等价于 a/=5
%=
a = a*%5等价于 a%=5
关系运算符:
通过关系运算符, 可以比较两个值之间的大小关系
如果关系成立则返回true,如果关系不成立 则返回false
>大于号
判断符号左侧的值是否大于右侧的,如果关系成立,返回true,如果关系不成立返回false
var result = 5>10
console.log(result)
====false
>= 大于等于
判断符号左侧的值是否大于或等于右侧的,如果关系成立,返回true,如果关系不成立返回false
<小于号
判断符号左侧的值是否小于右侧的,如果关系成立,返回true,如果关系不成立返回false
<=小于等于
判断符号左侧的值是否大于或等于右侧的,如果关系成立,返回true,如果关系不成立返回false
非数值的情况
对于非数值的情况
console.log(1>true) false
console.log(1>=true) true
console.log(1>="0") true
console.log(1>=null) true
console.log(1>="hello") false
以上会将值转换为数值然后进行比较
"hello"转换为数值类型为NaN,任何值和NaN比较都是false
console.log(true>false) true
console.log(11<"5") false
如果符号两侧的值都是字符串,不会将其转换为数字进行比较,而会分别比较字符串中字符的Unicode编码
console.log("11"<"5")
↑ 1先和5比较,1的字符码小于5,后边就不用比较了,直接小于号,即使是
console.log("132233"<"5")也是小于号,因为第一位已经决定了大小
如果比较的两个字符串型的数字,可能会得到不可预期的结果,
注意:比较两个字符串型的数字时,一定一定要转型
比较两个字符串时,比较的是字符串的字符编码
比较字符编码时是一位一位的进行比较,如果两位一样则比较下一位,所以借用它来对英文进行排序
console.log("a"<"b") true
console.log("abc"<"b") true
比较中文没有意义
console.log("你">"我")
在字符串中使用转义字符输入unicode编码
\u四位编码
console.log("\u0031") --------1
在网页中使用Unicode编码&#编码;这里的编码需要的是十进制
<h1></h1>
<h1>਼</h1>
//2620十六进制 ,得转成十进制
<h1>਼</h1>
<h1 style="font-size: 100px;">☠</h1>
相等运算符:
用来比较两个值是否相等 如果相等返回true 如果不等返回false使用==来做相等运算
当使用==来比较两个值时,如果值的类型不同,则会自动进行转换,将其转换为相同的类型,然后来比较
console.log(1==1) -----true
var a = 10
console.log(a==10) -----true
console.log("1"==1) true 将字符串1转换为数字1
console.log(true=="1") true
console.log(null==0) false ,按理说null转成Number的话是0,0==0,结果应该为true,但是
这是一个特例,结果为false,并没有转成number。。
undefined衍生自null,所以这两个值做相等判断时,会返回true
console.log(undefined==null)
---true
NaN不和任何值相等,包括它本身
console.log(NaN==NaN) ====false
var b = NaN
判断b的值是否为NaN
console.log(b==NaN) 此方法行不通
可以通过isNaN()函数来判断一个值是否为NaN,如果该值是NaN则返回true
var b = NaN
console.log(isNaN(b)) ----true
不相等:
用来判断两个值是否不相等,如果不相等则返回true,相等则返回false
使用!=来做不相等运算
不相等也会对变量进行自动的类型转换,如果转换后相等则返回false
===
全等
用来判断两个值是否全等,和相等类似,不同的是它不会进行自动的类型转换,如果两个值的类型不同,直接返回false
console.log("123"==123) true
console.log("123"===123)false
!==
不全等
用来判断两个值是否不全等,和不同类似,不同的是他也不会进行自动的类型转换,如果两个值的类型不同,他也会返回true
console.log("1"!=1) false
console.log("1"!==1) true
条件运算符:
也叫三元运算符
语法:
条件表达式?语句一:语句二;
执行的流程:
条件运算符在执行时,首先对条件表达式进行求值,如果该值为true,则执行语句一,并返回执行结果,如果该值为false,则执行语句二,并返回执行结果
true?alert('对'):alert('错')
如果条件的表达式的求值结果是一个非布尔值,会将其转换为布尔值然后再运算
运算符的优先级 :和数学一样
先乘除后加减
var result = 1+2*3
console.log(result) ====7
如果||的优先级高,或者两个一样高,则应该返回3
如果与的优先级高,或者两个一样高,则应该返回1
var result = 1||2&&3;
console.log(result)====1
在js中有一个符号优先级的表,在表中越靠上优先级越高,优先级越高越优先运算,如果优先级一样,则从左往右运算
这个表并不需要去记忆,如果遇到优先级不清楚可以使用()来改变优先级
var result = 1||(2&&3);
console.log(result)====1
var result = (1||2)&&3;
console.log(result)====3
运算符
使用,可以分割多个语句,一般可以在声明多个变量时使用
var a;
var b;
var c;
使用,运算符同时声明多个变量,
var a,b,c
使用,运算符同时声明多个变量并赋值
var a=1,b=2,c=3
代码块
我们的程序是由一条一条的语句组成的
语句时按照自上而下一条一条执行的,
在js中可以使用{}来为语句进行分组
同一个{}中的语句 我们成为是一组语句,他们要么都执行,要么都不执行,
一个{}中的语句,我们也称之为叫一个代码块
在代码块的后边就不用写;了
js中的代码块只具有分组的作用,不具备其他用途,代码块内部的内容,在外部是完全可见的
流程控制语句:
我们都知道JS中的程序是从上到下一行一行执行的,
alert('hello')
console.log("你好")
点完弹框才会输出你好
通过流程控制语句可以控制程序的执行流程,使我们的程序可以根据一定的条件选择执行
语句的分类:
1.条件判断语句
2.条件分支语句
3.循环语句
一、条件判断语句:
使用条件判断语句可以在执行某个语句之前,进行判断,条件成立则执行语句,条件不成立语句则不执行
if语句
①语法:
if(条件表达式){
语句
}
if(true){
alert('嘻嘻')
}
if语句在执行时,会先对条件表达式进行求值判断,如果条件表达式的值为true,则执行if后的语句,如果条件表达式的值为false,则不执行if后的语句,
var a = 10
if(a>1)
alert('a比1大')
if语句只能控制紧随其后的语句,
var a = 10
if(a>1)
alert('a比1大')
alert('管不了我')
-----此时浏览器只会弹出'a比1大'不会弹出它下边的任何语句
如果希望if语句可以控制多条语句,可以将这些语句统一放到代码块中
var a = 10
if(a>1){
alert('a比1大')
alert('管不了我')
}
--------用{}代码块包起来,则里面的内容都可执行
if语句后的代码块不是必须的,但是在开发中尽量写上代码块,即使if后只有一条语句
var a = 15
if(a>10&&a%<20){
alert('nnnnn')
}
②语法:
if(条件表达式){
语句...
}else{
语句...
}
if...else...语句
当该语句执行时,会先对if后的条件表达式进行求值判断,如果该值为true则执行if后的语句,如果该值为false则执行else后的语句
var age = 60
if(age>=60){
console.log('退休')
}else{
console.log('上班')
}
------输出退休
③语法:
if(条件表达式){
语句...
}else if(条件表达式){
语句...
}else if(条件表达式){
语句...
}else{
语句...
}
if ...else if ... else
当该语句执行时,会从上到下依次对条件表达式进行求值判断,如果值为true,则执行当前语句,如果值为false,则继续向下判断,
如果所有的条件都不满足,则执行最后一个else后的语句,该语句中,只会有一个代码块被执行,一旦代码块执行了,则直接结束语句
if练习
prompt()函数的返回值是String类型的
编写程序,由键盘输入三个整数分别存入变量num1、num2、num3,对他们进行排序,并且从小到大输出
var num1 = +prompt('请输入第一个数') //因为prompt()函数返回的是string类型,需要转换成
var num2 = +prompt('请输入第二个数') //number型 所以在prompt前加一个+
var num3 = +prompt('请输入第三个数')
if(num1<num2&&num1<num3){
if(num2<num3){
console.log(num1+","+num2+","+num3)
}else{
console.log(num1+","+num3+","+num2)
}
}else if(num2<num1&&num2<num3){
if(num1<num3){
console.log(num2+","+num1+","+num3)
}else{
console.log(num2+","+num3+","+num1)
}
}else{
if(num2<num1){
console.log(num3+","+num2+","+num1)
}else{
console.log(num3+","+num1+","+num2)
}
}
二、条件分支语句:
也叫switch语句
语法:
switch(条件表达式){
case 表达式:
语句...
break;
case 表达式:
语句...
break;
case 表达式:
语句...
break;
case 表达式:
语句...
break;
default:
语句...
break;
}
执行流程:
switch...case..语句
在执行时会依次将case后的表达式的值和switch后的条件表达式的值进行全等===比较
如果比较结果为true,则从当前case处开始执行代码
当前case后的代码都会执行,我们可以在case的后边跟着一个break关键字,这样可以确保只会执行当前case后的语句,而不会执行其他的case
var num = 1;
switch(num){
case 1:
console.log("①")
case 2:
console.log("②")
}
第一个没有break,它会依次输出①②,但是我们只想要①
==============//使用break可以退出switch语句,break后的语句不执行
var num = 1;
switch(num){
case 1:
console.log("①")
break;
case 2:
console.log("②")
break;
default:
console.log('非法数字')
break;
}
=======输出①
如果比较结果为false,则继续向下比较
如果所有的比较结果都为false,则只执行default后的语句
switch语句和if语句的功能实际上有重复的,使用switch可以实现if的功能,同样使用if可以实现switch的功能,
所以我们在使用时可以根据习惯选择
var score = 25
switch(parseInt(score/10)){
case 10:
case 9:
case 8:
case 7:
case 6:
console.log('合格');
break;
default:
console.log('不合格')
break;
}
switch(true){
case score>=60:
console.log('合格');
break;
default:
console.log('不合格')
break;
}
循环语句:
通过循环语句可以反复的执行一段代码多次
向页面中输出连续的数字
while循环
while(条件表达式){
语句...
}
while语句在执行时,先对条件表达式进行求值判断,如果值为true,则执行循环体,循环体执行完毕以后,继续对表达式进行判断,如果为true,则继续执行循环体以此类推
如果值为false,则终止循环
像将条件表达式写死为true的循环,叫做死循环,该循环不会停止,除非浏览器关闭,死循环在开发中慎用
可以使用break来终止循环
while(true){
alert(n++)
判断n是否是10
if(n==10){
//退出循环
break;
}
}
创建一个循环:
1.初始化一个变量
var i = 0
2.在循环中设置一个条件表达式
while(i<10){
alert(i)
//3,定义一个更新表达式,每次更新初始化变量
i++;
}
创建一个执行10次的while循环
初始化表达式
var i = 0;
创建一个循环体,定义条件表达式
while(i<10){
设置更新表达式
alert(i++)
}
do... while循环
do{
语句...
}while(条件表达式)
do{
document.write(i++ +"<br/>")
}while(i<=5000)
do... while语句在执行时,会先执行循环体,循环体执行完毕以后,再对while后的条件表达式进行判断,
如果值为true,则执行循环体,循环体执行完毕以后,继续对表达式进行判断,如果为false,则终止循环
实际上这两个语句功能相似,不同的是while是先判断后执行,而do...while是先执行后判断,
do...while可以保证循环体至少执行一次,而while不能
while练习:
假如投资的年利率为5%,试求从1000块增长到5000块,需要花费多少年?
var money = 1000;
var count = 0;
while(money<5000){
money *=1.05;
count++
}
console.log(count)
for循环
for语句,也是一个循环语句,也称为for循环
在for循环中,有专门的位置来存放三个表达式
1.初始化表达式
2.条件表达式
3.更新表达式语法:
for(初始化表达式;条件表达式;更新表达式){
语句...
}
for(var i = 0;i<10;i++){
alert(i)
}
for循环执行流程:
①初始化表达式,初始化变量(初始化表达式只会执行一次)
②条件表达式,判断是否执行循环,如果为true,则执行循环语句③,如果为false,则终止循环
④执行更新表达式,更新表达式执行完毕继续重复②
for循环中的三个部分都可以省略,也可以写在外部,
如果任何条件都不写,只写两个分号,此时循环为死循环
for(;;){
alert('hhh')
}
var i = 0;
for(;i<10;){
alert(i++)
}
在页面中接收一个用户输入的数字,并判断该数是否是质数
质数:只能被1和它自身整除的数,1不是质数也不是合数,质数必须是大于一的自然数
var num = prompt("请输入一个大于1的整数");
// 判断这个值是否合法
if(num<1){
alert('不合法')
}else{
// 创建一个变量来保存当前数的状态
// 默认当前num是质数
var flag = true;
// 判断num是否为质数
// 获取2-num之间的数
for(var i = 2;i<num;i++){
// console.log(i)
// 判断num是否能被i整除
if(num%i==0){
// 如果num被i整除,说明num一定不是质数
// 设置flag为false
flag = false;
}
}
// 如果num是质数则输出
if(flag){
alert(num+"是质数")
}else{
alert('不是质数')
}
}
嵌套的for循环
1.通过一个for循环来输出图形
这个for循环执行几次,图形的高度就是多少
它可以用来控制图形的高度
for(var i = 0;i<5;i++){
document.write("*****<br/>")
}
for(var i = 0;i<5;i++){
document.write("*")
}
document.write("<br/>")
//外部for循环执行一次。内部执行五次
for(var i = 0;i<5;i++){
在循环的内部再创建一个循环,用来控制图形的宽度
内层循环可以来决定图形的宽度,执行几次宽度就是多少
for(var j = 0;j<5;j++){
document.write("*****<br/>")
}
}
for(var i =0;i<5;i++){
for(var j = 0;j<5;j++){
document.write("* ")
}
document.write("<br/>")//内循环执行五次,外循环执行一次,五次一换行
}
for(var i = 0;i<5;i++){
for(var j = 0;j<i+1;j++){
document.write("* ")
}
document.write("<br/>")
}
for(var i = 0;i<5;i++){
for(var j =0;j<5-i;j++){
document.write("* ")
}
document.write("<br/>")
}
九九乘法表:
for(var j =1;j<=9;j++){
for(var i = 1;i<=j;i++){
document.write("<span>"+i+"*"+j+"="+j*i+"</span>")
}
document.write("<br/>")
}
<style type="text/css">
span{
display: inline-block;
width: 100px;
/* height: 80px; */
border: 1px solid red;
}
</style>
break和continue
break关键字可以用来退出switch或循环语句(不能在if语句中使用break或continue)
break关键字会立即终止离他最近的那个循环语句
可以为循环创建一个label,来标识当前的循环
label:循环语句
使用break语句时,可以在break后跟着一个label,这样break将会结束指定的循环,而不是最近的
for(var i = 0;i<5;i++){
console.log(i)
break
}
------0
break一执行循环立即结束
if(true){
break ---------会报错(if语句不能使用break或continue)
console.log('hello')
}
for(var i = 0;i<5;i++){
console.log(i)
if(i==2){
break; -------这里的break对for循环起作用
}
}
-----0 1 2
outer:
for(var j =1;j<=5;j++){
console.log("外层循环"+j)
for(var i = 1;i<=j;i++){
break outer; ------终止外层for循环
console.log("内层循环"+i)
}
}
continue关键字可以用来跳过当次循环
for(var i = 0;i<5;i++){
if(i==2)
continue;
}
console.log(i)
---0 1 3 4
for(var i = 0;i<5;i++){
if(i==2)
break;
}
console.log(i)
---0 1
同样continue也是对离他最近的那个循环语句起作用
求一百以内的质数
性能逐步提升
测试如下的程序的性能
在程序执行时开启计时器
console.time("计时器的名字")可以用来开启一个计时器
他需要一个字符串作为参数,这个字符串将会作为计时器的标识
console.time('test');
终止计时器
console.timeEnd()用来停止一个计时器,需要一个计时器名字作为参数‘’
console.timeEnd('test');
开始和结束名字一样
可以通过Math.sqrt()对一个数进行开方
console.time('test')
for(var i = 2;i<=10000;i++){
var flag = true
for(var j = 2;j<i;j++){
if(i%j==0){
flag = false
}
}
if(flag){
console.log(i)
}
}
console.timeEnd('test')
console.time('test')
for(var i = 2;i<=10000;i++){
var flag = true
for(var j = 2;j<i;j++){
if(i%j==0){
flag = false
break;
}
}
if(flag){
console.log(i)
}
}
console.timeEnd('test')
console.time('test')
for(var i = 2;i<=10000;i++){
var flag = true
for(var j = 2;j<Math.sqrt(i);j++){
if(i%j==0){
flag = false
break;
}
}
if(flag){
console.log(i)
}
}
console.timeEnd('test')
三、对象
JS中的数据类型:
基本数据类型:
String字符串 Number数值 Boolean布尔值 Null空值 Undefined未定义
我们看到的值只要不是以上这几种,全部是对象
引用数据类型:
Object对象
基本数据类型都是单一的值 123 true 'hello',值和值之间没有任何联系
在js中表示一个人的信息 (name,age,gender)
var name = "张三",
var age = 3,
var gender = "男"
如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体,
对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性
对象的分类:
1.内建对象
由ES标准中定义的对象,在任何的ES的实现中都可以使用
比如Math Function String Number Boolean等。。。
2.宿主对象
由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
比如BOM DOM console.log document.write
3.自定义对象
由开发人员自己创建的对象
创建对象
var obj = new Object();
console.log(obj)
console.log(typeof obj)
使用new关键字调用的函数,是构造函数constructor,
构造函数是专门用来创建对象的函数
使用typeof检查一个对象时,会返回object
在对象中保存的值称为属性
向对象中添加属性
语法:对象.属性名 = 属性值
向obj中添加一个name属性
obj.name = "张三"
读取对象中的属性
语法:对象.属性名
console.log(obj.name)
如果读取我们对象中没有的属性,不会报错而会返回undefined
修改对象的属性值
语法:对象.属性名 = 新值
删除对象的属性
语法:delete对象.属性名
var obj = new Object()
//添加属性
obj.name = "张三"
obj.age = 3
obj.gender = "男"
console.log(obj)
//删除属性
delete obj.name
console.log(obj)
//修改属性
obj.age = 3
console.log(obj)
//获取属性
console.log(obj.name)
属性名:
对象的属性名不强制要求遵守标识符的规范,什么名字都可以使用,但是尽量按照标识符的规范去做
obj.var = "hello"
console.log(obj.var)
//用关键字var也可以
如果使用特殊的属性名,不能采用.的方式来操作
需要使用另一种方式:
语法:对象["属性名"] = 属性值
读取时也要采用这种方式
使用[]这种形式去操作属性,更加的灵活
在[]中可以直接传递一个变量,这样变量值的多少就会读取哪个属性
obj["hahah"] = "笑啥"
var n = "hahah"
console.log(obj[n]) // -----笑啥
obj["123"] = 789
console.log(obj["123"]) //-----789
属性值:
JS对象的属性值,可以是任意的数据类型,甚至它也可以是一个对象
obj.test = true
obj.test = null
obj.test = "hello"
obj.test = 123
console.log(obj.test)
var obj = new Object();
// console.log(typeof obj)
obj.name = "张三"
obj.age = 15
obj.gender = "男"
obj.name = "里斯"
// delete obj.name
// console.log(obj.name) undefined
var obj2 = new Object();
obj2.name = "哈哈哈"
obj.name = obj2
console.log(obj)
console.log(obj.name) //哈哈哈
in运算符
通过该运算符可以检查一个对象中是否含有指定的属性
如果有返回true,没有返回false
语法:
"属性名" in 对象
console.log("test" in obj)
JS中的数据类型
基本数据类型:String字符串 Number数值 Boolean布尔值 Null空值 Undefined未定义
引用数据类型:Object对象
JS中的变量都是保存到栈内存中,
基本数据类型的值直接在栈内存中存储,
值与值之间是独立存在,修改一个变量不会影响其他变量
对象保存到堆内存中,每创建一个新的对象就会在堆内存中开辟一个新的空间,
而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用
当通过一个变量修改属性时,另一个也会受到影响
当我们比较两个基本数据类型的值时,就是比较值,而比较两个引用数据类型时,比较的是对象的内存地址,
如果两个对象一模一样,但是地址值不同,也会返回false
对象字面量:
使用对象字面量来创建一个对象
var obj = new Object();
//等同于↑↓
var obj = {};
console.log(obj)
使用对象字面量可以在创建对象时直接指定对象的属性,
对象字面量的属性名可以加引号也可以不加,建议不加,
如果要使用一些特殊的名字,则必须加
"$%^%Y"
属性名和属性值是一组一组的名值对结构(键值对)
名和值之间使用冒号连接,多个名值对之间使用,隔开,
如果一个属性之后没有其他属性,就不用写,了
语法:
{属性名:属性值,属性名:属性值...}
var obj2 = {name:"张三"}
函数:
函数function
函数也是一个对象
document console...
一切皆对象
函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)
函数中可以保存一些代码在需要的时候调用
使用typeof检查一个函数对象时,会返回function
创建一个函数对象
可以将要封装的代码以字符串的形式传递给构造函数
封装到函数中的代码不会立即执行
函数中的代码会在函数调用的时候执行
调用函数:
语法:
函数对象()
当调用函数时,函数中封装的代码会按照顺序执行
fun()
var fun = new Function("console.log('hello,这是我的第一个函数')");
console.log(fun)
fun()
-------
但是,我们在实际开发中,很少使用构造函数来创建一个函数对象
-------
使用函数声明来创建一个函数
语法:
function 函数名([形参1、形参2、....形参N]){
语句...
}
--------
function fun2(){
console.log("这是我封装的第一个函数")
alert('哈哈哈哈')
document.write('哎')
}
console.log(fun2) //打印函数
fun2()//执行函数
--------
使用函数表达式来创建一个函数
var 函数名 = function([形参1、形参2、....形参N]){
语句...
}
function(){
console.log("我是匿名函数中封装的代码")
}
======
var fun3 = function(){
console.log("我是匿名函数中封装的代码")
};
fun3()
------
函数的参数
定义一个用来求两个数和的函数
可以在函数的()中来指定一个或多个形参(形式参数),多个形参之间使用,隔开
声明形参就相当于在函数内部声明了对应的变量,但是并不赋值
在调用函数时,可以在()中指定实参(实际参数)
实参将会赋值给函数中对应的形参
function sum(a,b){
console.log(a+b) //7
}
sum(3,4)
调用函数时解析器不会检查实参的类型
所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查,
函数的实参可以是任意的数据类型
调用函数时解析器不会检查实参的数量,多余的实参不会被赋值
如果实参小于形参,则没有对应实参的形参将是undefined
-------
函数的返回值
创建一个函数计算三个数的和
可以使用return来设置函数的返回值
语法:
return 值
return后的值将会作为函数的执行结果返回,可以定义一个变量来接收该结果
调用函数
变量result的值就是函数的执行结果
函数返回什么result的值就是什么,
在函数中,return后的语句都不会执行,
如果return语句后不跟任何值就相当于返回一个undefined
如果函数中不写return,也会返回undefinedreturn后可以跟任意类型的值
function sum(a,b,c){
var d = a+b+c
return d;
alert('hello') //----不执行
}
var result = sum(1,2,3)
console.log("result="+result) //6
-----------
定义一个函数,判断一个数字是否是偶数,如果是返回true,否则返回false
function isOu(num){
return num%2==0
}
var result = isOu(12)
console.log(result)
定义一个函数,可以根据半径计算一个圆的面积,并返回计算结果
function mianji(r){
return 3.14*r*r;
}
result = mianji(10);
console.log(result)
--------
实参可以是任意的数据类型,也可以是一个对象,当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递
--
创建一个函数,可以在控制台输出一个人信息
可以输出name age gender address
--
function sayHello(name, age, gender, address) {
console.log("我是" + name + "我今年" + age + "岁了" + "我是一个" + gender + "人" + "我住在" + address)
}
// sayHello("猪八戒",5,"男","高老庄") 我是猪八戒,我今年五岁了,我是一个男人,我住在高老庄
// sayHello("猪八戒","男",5,"高老庄") 我是猪八戒,我今年男了,我是一个5人,我住在高老庄
=====这种方式形参和实参的位置必须保持一致,形参第一个是谁,实参第一个也要是谁,否则打印出来的有可能会出现上面这种情况
所以我们要创建一个对象,对象里面的位置随意颠倒,打印出来的还会是我们想要的结果
function sayHello(o) {
console.log("我是" + o.name + "我今年" + o.age + "岁了" + "我是一个" + o.gender + "人" + "我住在" + o.address)
}
// 创建一个对象
var obj = {
name: '孙悟空',
age: 3,
gender: '男',
address: '高老庄'
}
sayHello(obj)
实参可以是一个对象,也可以是一个函数
mianji()
调用函数
相当于使用的是函数的返回值
function mianji(r) {
return 3.14 * r * r;
}
result = mianji(10);
console.log(result)
function funny(a){
console.log(a)
}
funny(mianji(5))
//funny(mianji)
mianji
函数对象
相当于直接使用函数对象
function mianji(r) {
return 3.14 * r * r;
}
result = mianji(10);
console.log(result)
function funny(a){
console.log(a)
}
// funny(mianji(5))
funny(mianji)
---
return返回值的类型
返回值可以是任意的数据类型,也可以是一个对象,也可以是一个函数
function fun5(){
return 10;
}
var a = fun5()
console.log(a)
----------------
function fun5(){
var obj = {name:"加油哇"};
return obj;
}
var a = fun5()
console.log(a)
function fun() {
alert("函数要执行了")
for (var i = 0; i < 5; i++) {
if (i == 2) {
// 使用break可以退出当前的循环(两个弹框 输出0 1)
// break;
// 使用continue用于跳过当此循环(两个弹框 输出0 1 3 4)
// continue
// 使用return可以结束整个函数(只有第一个弹框,输出0 1)
return;
}
console.log(i)
}
alert("函数执行完了")
}
fun()
function fun6(){
// 在函数内部再声明一个函数
function fun7(){
alert('我是fun7')
}
fun7()
// 将fun7函数对象作为返回值返回
return fun7;
}
// console.log(fun6())
a = fun6();
console.log(a)
// a()
// fun6()()
立即执行函数
函数定义完,立即被调用,这种函数叫做立即执行函数,立即执行函数往往只会执行一次
(function(){
console.log("我是一个匿名函数")
})();
(function(a,b){
console.log(a)
console.log(b)
})(123,12)
对象的属性值可以是任何的数据类型,也可以是个函数
var obj = new Object()
obj.name = "张三"
obj.sayName = function(){
console.log(obj.name)
}
调方法:
obj.sayName() //---张三
调函数:
fun()
函数也可以成为对象的属性,如果一个函数作为一个对象的属性保存, 那么我们称这个函数是这个对象的方法,调用这个函数就说调用对象的方法(method),但是它只是名称上的区别没有其他区别
枚举对象中的属性:
// 使用for... in语句
// 语法:
for(var 变量 in 对象){
}
for... in语句 对象中有几个属性,循环体就会执行几次,每次执行时,会将对象中的一个属性的名字赋值给变量
var obj = {
name:"张三",
age:18,
gender:"男",
address:"加利福尼亚州"
}
for(var n in obj){
console.log('hello')
} //hello输出四次
for(var n in obj){
console.log('n')//---属性名 name age gender address
console.log(obj[n])//---属性值 张三 18 男 加利福尼亚
}
作用域:
作用域指一个变量的作用的范围
在JS中一共有两种作用域: 全局作用域、函数作用域
1.全局作用域
--直接编写在script标签中的JS代码,都在全局作用域
--全局作用域在页面打开时创建,在页面关闭时销毁
--在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建,我们可以直接使用
--在全局作用域中,创建的变量都会作为window对象的属性保存,创建的函数都会作为window对象的方法保存
function fun(){
console.log("你好")
}
// fun() 你好
window.fun() //你好
var a = 10
console.log(window.a) //10
console.log(window)
变量的声明提前
使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值),
但是如果声明变量时不使用var关键字,则变量不会被声明提前
console.log(a)
var a =123 -undefined
console.log(a)
a =123 //--报错
函数的声明提前
--使用函数声明形式创建的函数function 函数名(){}
会在所有代码执行之前就被创建,所以我们可以在函数声明前来调用函数
-- 使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
函数声明,
// fun()
function fun(){
console.log("hhh")
}
fun()
//前后调用都可以输出hhh
var fun2 = function(){
console.log("wuwu")
}
fun2() //只能在后边调用
全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问到
2.函数作用域
--调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁,
每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量b,
当在函数作用域操作一个变量时,他会先在自身作用域中寻找,有就直接使用。没有就去上一级作用域中寻找,直到找到全局作用域,
如果全局作用域也没有,则报错ReferenceError
在函数中要访问全局变量可以使用window对象
在函数作用域中,也有声明提前的特性,
使用啊var关键字声明的变量,会在函数中所有的代码执行之前被声明,
函数声明也会在函数中所有的代码执行之前执行
在函数中不使用var声明的变量都会成为全局变量
var a = 10
function fun(){
console.log(a)
var b = 20
}
fun() //10
console.log(b) //undefined
function fun3(){
console.log(a) //undefined
var a = 35
fun4();
function fun4(){
console.log("我是fun4")
}
}
fun3() //我是fun4函数
var c = 20
function fun6(){
console.log(c) //undefined
var c = 10
c = 10 //(全局变量相当于 var c = 20 var c = 10)
d = 100 //(没有使用关键字 即为全局变量)
}
fun6() //undefined
console.log(c) //20
console.log(d) //100
-----
var e = 222
function fun7(){
console.log(e)
}
fun7() //222
var e = 222
function fun7(e){
console.log(e)
}
fun7(20) //20
//定义形参就相当于在函数作用域中声明了变量
var e = 222
function fun7(e){
console.log(e)
}
fun7() --undefined
var a = 123
function fun(a){
a=456
alert(a)
}
fun() //456
alert(a) //123
var a = 123
function fun(a) {
alert(a)
a = 456
}
fun() //undefined
alert(a) //123
// 给了形参a,那么a = 456,就是局部变量
// 如果没给形参,那么a = 456,就是改变的全局变量
// fun()123
// alert(a)456
this:
解析器在调用函数时每次都会向函数内部传递进一个隐含的参数
这个隐含的参数就是this,this指向的是一个对象,这个对象我们称之为函数执行的上下文对象,
根据函数的调用方式的不同,this会指向不同的对象
1.以函数的形式调用时,this永远都是window fun()
2.以方法的形式调用,this就是调用方法的那个对象
function fun8(a){
console.log(a)
console.log(this)
}
fun8(23);
使用工厂方法创建对象,通过该方法可以大批量的创建对象
function createPerson(){
//创建一个新的对象
var obj = new Object()
//向对象中添加属性
obj.name = "孙悟空",
obj.age = 18,
obj.gender = "男",
obj.sayName = function(){
alert(this.name)
}
//将新的对象返回
return obj;
}
使用工厂方法创建的对象,使用的构造函数都是object
所以创建的对象都是Object这个类型的,
就导致我们无法区分出多种不同类型的对象
function createPerson(name,age,gender) {
//创建一个新的对象
var obj = new Object()
//向对象中添加属性
obj.name = name,
obj.age = age,
obj.gender = gender,
obj.sayName = function() {
alert(this.name)
}
//将新的对象返回
return obj;
}
var obj2 = createPerson("猪不戒",16,"男")
obj2.sayName()
console.log(obj2)
构造函数
var obj = new Person()
var obj = new Cat()
创建一个构造函数,专门用来创建Person对象的,构造函数就是一个普通的函数,创建方式和普通函数没有区别,
不同的是构造函数习惯上首字母大写
构造函数和普通函数的区别就是调用方式的不同,
普通函数是直接调用,而构造函数需要使用new关键字来调用
构造函数的执行流程:
1.立刻创建一个新的对象
2.将新建的对象 设置为函数中的this,在构造函数中可以使用this来引用新建的对象
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类,
我们将通过一个构造函数创建的对象,称为是该类的实例
function Person(){
this.name = name
}
var per = new Person("孙悟空")
console.log(per.name)
使用instanceof可以检查一个对象是否是一个类的实例
语法:
对象instanceof构造函数,是则返回true
console.log(per instanceof Person) //true
console.log(per instanceof Object) //true
所有的对象都是Object的后代,
所以任何对象和Object做instanceof检查时都会返回true
this的情况:
1.当以函数的形式调用时,this是window
2.当以方法的形式调用时,谁调用方法,this就是谁
3.当以构造函数的形式调用时,this就是新创建的那个对象
构造函数的修改
创建一个Person构造函数
-在Person构造函数中,为每一个对象都添加了一个sayName方法,
目前我们的方法是在构造函数内部创建的,
也就是构造函数每次一执行,就会创建一个新的sayName方法,
也就是所有的实例的sayName都是唯一的,
这样就导致,构造函数执行一次就会创建一个新的方法,执行一万次创建一万个。。。
而这一堆方法都是是一样的,完全没必要,我们可以让他们共用一个方法,把它变成全局
function createPerson(name,age,gender) {
//创建一个新的对象
var obj = new Object()
//向对象中添加属性
obj.name = name,
obj.age = age,
obj.gender = gender,
obj.sayName = function() {
alert(this.name)
}
//将新的对象返回
return obj;
}
var obj2 = createPerson("猪不戒",16,"男")
obj2.sayName()
console.log(obj2)
function Person(name,age){
this.name = name,
this.age = age
this.sayName = fun
}
//将sayName方法在全局作用域中定义
但是将函数定义在全局作用域中,污染了全局作用域的命名空间,而且定义在全局作用域中也很不安全,所以有了接下来的原型对象
原型对象:
原型prototype
我们所创建的每一个函数,我们的解析器都会像函数中添加一个属性prototype,
这个属性对应着一个对象,这个对象就是我们所谓的原型对象
如果函数作为普通函数调用prototype没有任何作用,当函数以构造函数形式调用时,她所创建的对象中都会有一个隐含的属性,
指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象
我们可以将对象中共有的内容,统一设置到原型对象中
当我们访问对象的一个属性或方法时,他会先在对象自身中寻找,如果有则直接使用,如果没有,则会去原型对象中寻找,如果找到则直接使用
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,
也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
function Person(){
}
向Person的原型中添加属性a
Person.prototype.a = 123
向Person的原型中添加方法
Person.prototype.sayName = function(){
alert('hello')
}
var per = new Person()
var per1 = new Person()
// console.log(Person.prototype)
console.log(mc.a)
console.log(per.__proto__ ==Person.prototype)
console.log(per1.__proto__ ==Person.prototype)
原型对象也是对象,所以他也有原型,
当我们使用一个对象的属性或方法时,会先在自身寻找,
自身中有则直接使用,没有就去原型中寻找,有则直接使用,原型中如果没有,则去原型的原型中寻找,
直到找到Object对象的原型,Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined
//可以使用对象的hasOwnProperty()来检查对象自身中是否有该属性
toString
垃圾回收(GC)gabbage collection:
程序运行过程中也会产生垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢,
所以我们需要一个垃圾回收机制,来处理程序运行过程中产生的垃圾
当一个对象没有任何的变量或属性对他进行引用,此时我们将无法操作该对象,这种对象就是一个垃圾,
这种对象过多会占用大量的内存空间,导致程序运行变慢,
所以这种垃圾必须进行清理
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,
我们不需要也不能进行垃圾回收的操作,
我们需要做的只是要将不再使用的对象设置为null即可
数组(Array)
内建对象
宿主对象
自定义对象(最灵活、最麻烦)
数组(Array)
数组也是一个对象,它和我们普通对象功能类似,也是用来存储一些值的
不同的是普通对象是使用字符串作为属性名的,而数组是使用数组作为索引,操作元素
索引:从0开始的整数就是索引
数组的存储性能比普通对象更好,在开发中我们经常使用数组来存储一些数据
// 向数组中添加元素
语法:数组[索引] = 值
// 读取数组中的元素
如果读取不存在的索引,不会报错而会返回 undefiend
语法:数组[索引]
console.log(arr[2])
// 获取数组长度(元素的个数)
对于连续的数组,使用length可以获取到数组的长度
对于非连续的数组,使用length会获取到数组的最大的索引+1
尽量不要创建非连续数组
语法:数组.length
console.log(arr.length)
// 修改length
如果修改的length大于原长度,则多出部分会空出来,如果修改的length小于原长度,则多出元素会被删除
// 向数组的最后一个位置添加元素
语法:数组[数组.length] = 值
var arr = [1,2,3]
arr[arr.length] = 7
console.log(arr) //1,2,3,7
数组字面量
使用字面量来创建数组
语法:[]
var arr = [];
console.log(arr)
使用字面量来创建数组时,可以在创建时就指定数组中的元素
var arr = [10,23];
// console.log(typeof arr)
console.log(arr)
//使用构造函数创建数组时,也可以同时添加元素,把要添加的元素作为构造函数的参数传递,元素之间用,隔开
var arr3 = new Array(10,222)
console.log(arr3)
//创建一个数组中只有一个元素10
arr[10]
//表示创建一个长度为十的数组
arr2 = new Array(10)
console.log(arr2.length) ----10
数组中的元素可以是任意数据类型,也可以是对象,也可以是函数,也可以是数组
arr = ["hello",1,true,null,undefined]
var obj = {
name:'孙悟空'
}
arr[arr.length] = obj
arr = [function(){alert(1)},function(){alert(1)}]
// console.log(arr)
arr[0]()
arr[[1,2,3],[3,4,5]] ---二维数组
console.log(arr[0])
数组的四个方法
1.push()将一个或多个新元素添加到数组的末尾,并返回新的长度
var arr = ["孙悟空","猪八戒","沙和尚"]
arr.push("唐僧")
console.log(arr) ['孙悟空', '猪八戒', '沙和尚', '唐僧']
var result = arr.push("唐僧")
console.log("result=" +result) ---4 新的长度
2.pop()
删除数组的最后一个元素,并返回该元素。
var arr = ["孙悟空","猪八戒","沙和尚"]
arr.pop()
console.log(arr) --孙悟空 猪八戒
var result = arr.pop()
console.log("result=" +result) ---删谁返回谁
3.unshift()将新元素添加到数组的开头,并返回新的长度
向前边插入元素以后,其他的元素索引会依次调整
var arr = ["孙悟空","猪八戒","沙和尚"]
arr.unshift("你好呀")
console.log(arr)
['你好呀', '孙悟空', '猪八戒', '沙和尚']
var result = arr.unshift("你好呀")
console.log("result=" +result) ---4
4.shift()删除数组的第一个元素,并返回该元素。
var arr = ["孙悟空", "猪八戒", "沙和尚"]
var result = arr.shift()
console.log(arr)
console.log("result=" + result) 孙悟空
---数组的遍历
//所谓遍历 就是把数组中所有的元素取出来
var arr2 = ["孙悟空", "猪八戒", "沙和尚"]
for(var i = 0;i<arr2.length;i++){
console.log(arr2[i])
} //孙悟空 猪八戒 沙和尚
----练习
----
一般我们用for循环来遍历一个数组,JS中还为我们提供了一个方法,用来遍历数字
forEach() --只支持ie8以上的浏览器,ie8及以下的浏览器均不支持该方法,
所以如果需要兼容给ie8,则不要使用forEach,还是使用for循环来遍历
forEach()需要一个函数作为参数
像这种函数,由我们创建但是不由我们调用的,我们称为回调函数
var arr = ["孙悟空","沙和尚"]
arr.forEach(function(){
console.log("你好")
})
//你好 你好(输出两次)
//有几个参数 就会输出几次
var arr = ["孙悟空","沙和尚"]
arr.forEach(function(a){
console.log("a="+a)
})
//a=孙悟空
//a=沙和尚
数组中有几个元素 ,函数就会执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进来
我们可以定义形参来读取这些元素
浏览器会在回调函数中传递三个参数
第一个参数,就是当前正在遍历的元素
第二个参数,当前正在遍历的元素的索引
第三 个参数,正在遍历的数组
var arr2 = ["孙悟空", "猪八戒", "沙和尚"]
arr2.forEach(function(value,index,obj){
// console.log(value)
// console.log(index)
console.log(arr2== obj)
})
//true
slice
slice() 选择数组的一部分,并返回新数组。
可以用来从数组中提取指定元素,该方法不会改变元素数组,而是将截取到的元素封装到一个新的数组
第二个参数不写的话,此时截取从开始索引往后的所有元素
索引可以传递一个负值,如果传递一个负值,则从后往前计算 -1 表示最后一个元素
语法:对象.slice(start,end) 下标
var arr2 = ["孙悟空", "猪八戒", "沙和尚"]
console.log(arr2.slice(0,2)) //前闭后开
//孙悟空、猪八戒
splice() 从数组中添加/删除元素。
使用会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回
参数:
第一个:开始位置索引
第二个:表示删除的数量
第三个及以后可以传递一些新的元素,这些元素将自动插入到开始位置索引前边
var arr2 = ["孙悟空", "猪八戒", "沙和尚"]
console.log(arr2.splice(0,2)) //孙悟空 、猪八戒
console.log(arr2) //沙和尚
(2)
var arr2 = ["孙悟空", "猪八戒", "沙和尚"]
console.log(arr2.splice(0,1,"hhh"))
console.log(arr2)
数组的去重
var arr = [1,2,3,2,1,3,4,2,5];
for(var i = 0;i<arr.length;i++){
// console.log(arr[i])
for(var j = i+1;j<arr.length;j++){
// console.log("后来的===="+arr[j])
if(arr[i] == arr[j]){
arr.splice(j,1);
// console.log(arr[i])
j--
}
}
console.log(arr[i])
}
concat()连接两个或多个数组,并返回已连接数组的副本。该方法不会对原数组产生影响
join()将数组的所有元素连接成一个字符串。该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符,如果不指定则默认用,隔开,如果什么都不想用,直接传一个空串 join("")
reverse()反转数组中元素的顺序。该方法会对原数组产生影响
sort()对数组的元素进行排序 ,也会影响原数组,默认按照unicode编码进行排序
即使对于纯数字的数组,使用sort()排序时,也会按照unicode编码来排序,所以对数字进行排序时,可能得到错误的结果
我们可以自己来指定排序的规则
我们可以在sort()中添加一个回调函数,来指定排序的规则
回调函数中需要定义两个形参a,b
浏览器将会分别使用数组中的元素作为实参去调用回调函数
使用哪个元素调用不确定,但是肯定的是数组a一定在b前边
浏览器会根据回调函数的返回值来决定元素的顺序
如果返回一个大于0的值,则元素会交换位置
如果返回一个小于0的值,则元素位置不变
如果返回0,则认为两个元素相等 元素位置不变
arr = [5,4]
arr.sort(function(a,b){
//前边的大
if(a>b){
return 1
}else if(a<b){
return -1
}else{
return 0
}
//升序排列
return a-b
//降序排列
return b-a
})
var arr = [1,4,3]
var arr2 = [4,5,6]
var arr3 = ["hahah","连胜了"]
console.log(arr.concat(arr2)) [1,4,3,4,5,6]
console.log(arr.concat(arr2,arr3,"尊重对手")) [1, 4, 3, 4, 5, 6, 'hahah', '连胜了', '尊重对手']
console.log(arr.join()) 1,4,3
console.log(typeof arr.join()) string
console.log(arr2.join("hello")) 4hello5hello6
console.log(arr.reverse())3,4,1
console.log(arr) 3,4,1
console.log(arr.sort())1,3,4
var arr = [1,11, 4, 3]
console.log(arr.sort()) [1, 11, 3, 4]
函数的方法
call()和apply()
这两个方法都是函数对象方法,需要通过函数对象来调用
当对函数调用call()和apply()都会调用函数执行
fun.call()
fun.apply()
fun()
效果一样
不同的是 在调用call和apply()时,可以将一个对象指定为第一个参数
此时这个对象将会称为函数执行时的this
call()方法可以将实参在对象之后依次调用
fun.call(obj,2,3)
apply()方法需要将实参封装到数组中统一传递
fun.apply(obj,[2,3])
function fun(){
alert(this)
}
var obj = {}
fun() ---window
fun.call(obj)
fun.apply(obj) object
this的情况2
1.以函数的形式调用时,this永远都是window fun()
2.以方法的形式调用,this就是调用方法的那个对象
3.以构造函数的形式调用时,this是新创建的那个对象
4.使用call和apply调用时,this是指定的对象
===============
arguments参数列表 实参
在调用函数时,浏览器每次都会传递两个隐含的参数,
1.函数的上下文对象this
2.封装实参的对象 arguments
arguments是一个类数组对象,不是数组,
它也可以通过索引来操作数据 也可以获取长度
在调用函数时,我们所传递的实参都会封装到arguments中
console.log(arguments instanceof Array) false
console.log(Array.isArray(arguments)) false
arguments.length可以用来获取实参的长度
我们即使不定义形参,也可以通过arguments来使用形参 只不过比较麻烦
arguments[0]第一个实参
arguments[1]第二个实参
定不定义形参 实参都会在arguments中保存
callee 这个属性对应一个函数对象,就是当前正在执行的函数的对象
console.log(arguments.callee)
Date:
使用Date对象来表示一个时间
var d = new Date();
alert(d)
如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间
//创建一个指定的时间,需要在构造函数中传递一个表示时间的字符串作为参数
日期格式:月份/日/年份/时:分:秒
getDate() //返回月中的第几天(从 1 到 31)。
getDay() //返回星期几(0-6)。0表示周日 1表示周一
getFullYear() //返回年份。
getMonth() //返回月份(从 0-11)。0表示一月
getTime() //获取当前日期对象的时间戳
//时间戳: 返回自 1970 年 1 月 1 日午夜以来与指定日期的毫秒数。1s=1000ms
//计算机底层在保存时间时使用的都是时间戳
var d = new Date()
var date = d.getDate()
console.log(date)
获取当前时间戳,可以利用时间戳来测试代码的执行的性能
time = Date.now()
Math对象:
Math和其他对象不同,它不是一个构造函数
它属于一个工具类,不用创建对象,它里面封装了数学运算的相关属性和方法
abs(x) 返回 x 的绝对值。
console.log(Math.abs(-1)) 1
ceil(x) 返回 x,向上舍入为最接近的整数。
小数位只要有值就会向上取整
console.log(Math.ceil(1.1)) 2
console.log(Math.ceil(-1.5)) -1
floor(x) 返回 x,向下舍入为最接近的整数。
小数部分被舍掉
console.log(Math.floor(1.9)) 1
round(x) 将 x 舍入为最接近的整数。四舍五入
console.log(Math.round(1.2)) 1
random() 返回 0 到 1 之间的随机数。
console.log(Math.random()) 0.5591525264361912
生成0-10的随机数
生成0-X的随机数
for(var i = 0;i<100;i++){
console.log(Math.round(Math.random()*X))
}
生成1-10之间随机数
console.log(Math.round(Math.random()*9)+1)
生成一个X-Y之间的随机数
console.log(Math.round(Math.random()*(Y-X))+X)
max(x, y, z, ..., n) 返回值最高的数字。
min(x, y, z, ..., n) 返回值最小的数字。
console.log(Math.max(10,20)) 20
console.log(Math.min(10,20)) 10
pow(x, y) 返回 x 的 y 次幂值。
console.log(Math.pow(2,3)) 8 2^3
sqrt(x) 返回 x 的平方根。
console.log(Math.sqrt(9)) 3
包装类
基本数据类型
String Number Null Undefined Boolean
引用数据类型
Object
在JS中为我们提供了三个包装类,通过这三个包装类可以将我们的基本数据类型转换为
对象
1.String()
可以将基本数据类型字符串转换为String对象
2.Number()
可以将基本数据类型数字转换为Number对象
3.Boolean()
可以将基本数据类型布尔值转换为Boolean对象
但是注意 在开发中↓我们不会使用基本数据类的对象
如果使用基本数据类的对象,在做一些比较时,可能会带来一些不可逾期的结果~
var num = new Number(3)
console.log(num)
console.log(typeof num) object
// 向num中添加一个属性
num.hello = "你好"
console.log(num.hello)
如果var a = 3
a.hello = "你好"
console.log(a.hello) --undefined
方法和属性只能添加给对象,不能添加给基本数据类型
当我们对一些基本数据类型的值去调用属性和方法时,
浏览器会临时使用包装类将其转换为对象,然后再调用对象的属性和方法
调用完以后,在将其转换为基本数据类型
∴
var a = 123
a = a.toString()
console.log(a)
console.log(typeof a) stirng
字符串的方法
在底层字符串是以字符数组的形式保存的
["h","e","l","l","""""]
length 字符串的长度
charAt()
返回在指定位置的字符。
根据索引获取指定的字符
对原字符串没影响
var str = "hello JS"
console.log(str.charAt(0)) h
charCodeAt() 返回在指定的位置的字符的 Unicode 编码。
var str = "hello JS"
console.log(str.charCodeAt(0)) 104
String.fromCharCode() 从字符编码创建一个字符串。
var str = "hello JS"
console.log(str.charCodeAt(0))
console.log(String.fromCharCode(104)) h
concat() 连接字符串。作用和+一样
var str = "hello JS"
console.log(str.concat("你好")) hello JS 你好
indexOf()检索字符串。检索字符串中是否含有指定内容
含有该内容则返回第一次出现该内容的索引值,没有则返回-1,
可以指定第二个参数,指定开始查找的位置
console.log(str.indexOf("h",4))从第四个位置开始找h -1
var str = "hello JS"
console.log(str.indexOf("干嘛")) -1
lastIndexOf() 从后向前搜索字符串。
可以指定第二个参数,指定开始查找的位置
var str = "hello JS"
console.log(str.lastIndexOf("l")) 3先返回后边的
console.log(str.indexOf("l")) 2
console.log(str.lastIndexOf("l",3)) 从第三个开始往前找
slice() 提取字符串的片断,并在新的字符串中返回被提取的部分。
不影响原字符串,将截取到的内容返回
console.log(str.slice(1,2)) ---e 前闭后开
console.log(str.slice(1,-3)) ello
substring() 提取字符串中两个指定的索引号之间的字符。
和slice()不同的是 不能接收负值作为参数,如果写了负数,默认为零
而且还会自动调整参数的位置(1,0) 默认(0,1)
substr() 从起始索引号提取字符串中指定数目的字符。
console.log(str.substr(3,2)) lo
参数:
1.开始索引
2.截取长度
split() 把字符串分割为字符串数组。
参数:
需要一个字符串作为参数,将会根据该字符串去拆分数组
如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
var str2 = "hello,JS"
result = str2.split("l") 根据l拆
console.log(result)
console.log(Array.isArray(result))
console.log(result[0]) he
console.log(result[1]) 空
console.log(result[2]) o,JS
toLocaleLowerCase() 把字符串转换为小写。
toLocaleUpperCase() 把字符串转换为大写。
var str2 = "hello,JS"
console.log(str2.split()) ['hello,JS']
console.log(str.substring(0,3)) hel 前闭后开
正则表达式
admin
admin@qq.com
正则表达式用于定义一些字符串的规则
计算机可以根据正则表达式,来检查一个字符串是否符合规则,或者将字符串中符合规则的内容提取出来
//创建正则表达式对象
语法:
var 变量 = new RegExp("正则表达式","匹配模式")
//正则表达式的方法
test()
使用这个方法可以用来检查一个字符串是否符合正则表达式的规则
使用typeof来检查正则对象,会返回object
var reg = new RegExp("a") 这个正则表达式可以用来检查字符串中是否含有a,严格区分大小写
在构造函数中可以传递一个匹配模式作为第二个参数
i 忽略大小写
g 全局匹配模式
符合则返回true,否则false
var reg = new RegExp("a")
var str = "a"; true
var reg = new RegExp("a","i");
// reg = /a/i
console.log(typeof reg)
console.log(reg)
var str = "A" true
str = "abc" true
str = "bc" false
var result = reg.test(str)
console.log(result)
正则语法:
使用字面量来创建正则表达式
语法:var 变量 = /正则表达式/匹配模式
使用字面量的方式创建更加简单
使用构造函数创建更加灵活
创建一个正则表达式,检查一个字符串中是否有a或b
使用/a|b/;
reg = /a|b/;
创建一个正则表达式检查一个字符串中是否有字母
使用/[a-z]/ 表示任意小写字母
/[A-Z]/表示任意大写字母
/[A-z]/ 任意字母
忽略大小写 /[a-z]/i
[]里的内容也是或的关系
reg = /[ab]/ === reg = /a|b/;
检查一个字符串中是否含有abc adc aec
使用 /a[bde]c/
[^] 除了。。。
[^ab] 除了ab
字符串和正则相关的方法
split() 把字符串分割为字符串数组,即使不指定全局匹配 也会全都拆分
var str = "1a2b3c4d5e6f"
var result = str.split("c")
console.log(result) ['1a2b3', '4d5e6f']
根据任意字母将字符串拆分
方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
var result = str.split(/[A-z]/) [1,2,3,4,5,6]
search 检索与正则表达式相匹配的值 (indexof) 只会查找一个,设置全局匹配也没用
如果搜索到则返回第一次出现的索引,如果没有搜索到则返回-1
它可以接收一个正则表达式作为参数,然后会根据正则表达式去检索字符串
str = "abc,aec,adc"
result = str.search("abc")
console.log(result) 0
检索字符串中是否有abc 或aec或 adc
result = str.search(/a[bed]c/)
console.log(result) 0
如果搜索到则返回第一次出现的索引,如果没有搜索到则返回-1
match 找到一个或多个正则表达式的匹配,根据正则表达式,将字符串中符合条件的提取出来
默认情况 match只会找到第一个符合要求的 找到就不往下找了,我们可以设置正则表达式为全局匹配模式,
也可以为正则表达式设置多个匹配模式,且顺序无所谓
match会将匹配到的内容封装到一个数组中然后返回
这样就会匹配到所有内容
var str = "1a2b3c4d5e6f7A"
result = str.match(/[A-z]/)
console.log(result) a
result = str.match(/[A-z]/g)
console.log(result) a b c d e f
result = str.match(/[A-z]/gi) 既全局又忽略大小写
console.log(result) a b c d e f A
replace()
可以将字符串中指定内容替换为新的内容
参数:
1.被替换的内容 ,可以接收一个正则表达式作为参数
2.新的内容
默认只会替换第一个
result = str.replace("a","k")
console.log(result)
1k2b3c4d5e6f
result = str.replace(/a/gi,"k")
console.log(result)
result = str.replace(/[a-z]/gi,"")
console.log(result) 1 2 3 4 5 6
正则表达式语法:
创建一个正则表达式,检查一个字符串中是否含有aaa
量词:
通过量词可以设置一个内容出现的次数
{n} 正好出现n次
{m,n} 出现m到n次
{m,} 出现m次以上
+ 至少一个 相当一{1,}
* 0个或多个 相当于{0,}
? 表示0个或一个 相当于{0,1}
量词只对它前面的一个内容起作用
var reg = /a{5}/; 出现5次a
console.log(reg.test("aaaaac")) //true
var reg = /(ab){2}/;
console.log(reg.test("aabb")) //true
var reg = /ab{2}/;
console.log(reg.test("abb")) //true
出现1-3次
reg = /ab{1,3}c/
console.log(reg.test(abc)) true
检查一个字符串是否以a开头
^表示开头
检查一个字符串是否以a结尾
$表示结尾
reg = /^a/
console.log(reg.test("abc")) true
console.log(reg.test("bac")) false
reg = /a$/
console.log(reg.test("bca")) true
console.log(reg.test("bac")) false
如果在一个在正则表达式中同时使用^和$则要求字符串必须完全符合正则表达式
reg = /^a$/
console.log(reg.test("a")) true
console.log(reg.test("aca")) false
reg = /^a|a$/ 以a开头或以a结尾
console.log(reg.test("aca")) true
检查一个字符串中是否含有.
.表示任意字符
在正则表达式中使用\作为转义符
\.表示.
\\表示\
注意:使用构造函数时,由于它的参数是一个字符串,而\是字符串中的转义字符,
如果要使用\则需要使用\\来代替
var reg = /\./
reg = new RegExp("\\.")
查找单个字符,除了换行和行结束符
reg = /\./
\w 查找单词字符。任意字母数字下划线
\W 查找非单词字符。和\w相反
\d 查找数字。
\D 查找非数字字符。
\s 查找空白字符。
\S 查找非空白字符。
\b 匹配单词边界。
\B 匹配非单词边界。
创建一个正则表达式检查一个字符串中是否含有单词child
var reg = /\bchild\b/
console.log(reg.test("hello children")) //false
console.log(reg.test("hello child ren")) true
DOM
DOM事件,就是用户和浏览器之间的交互行为,
比如 点击按钮 鼠标移动 关闭窗口...
我们可以在事件对应的属性中设置一些js代码,这样当事件被触发时,这些代码将会执行
文档的加载
浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就运行一行
如果将script标签写到页面的上边,在代码执行时,页面还没有加载,页面没加载dom对象也没加载会导致我们无法获取到DOM对象
所以我们将js代码编写到页面的下部就是为了,可以在页面加载完毕以后再执行js代码
onload事件,会在整个页面加载完成以后才触发
为window绑定一个onload事件
该事件对应的响应函数将会在页面加载完成之后执行,
这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了
window.onload = function(){
}
DOM查询
childNodes属性会获取包括文本节点在内的所有节点,根据DOM标签空白也会被当成文本节点
注意:ie8及以下的浏览器均不会将空白文本当成子节点,所以该属性在IE8中会返回4个子元素,
而其他浏览器是9个
children属性 可以获取当前元素的所有子元素
firstchild可以获取到当前元素的第一个子节点(包括空白文本)
firstElementChild不支持ie8及以下的浏览器,如果需要兼容他们尽量不要使用
innerText该属性可以获取到元素内部的文本内容
它和innerHTML类似,不同的是,它会自动将html标签去除
DOM操作
JSON
json中允许的值:
字符串、数值、布尔值、null、对象、数组
//创建一个json对象
var arr = '{"name":"孙悟空","age":18,"gender":"男"}';
var arr = '[1,2,3,"hello",true]'