javascript是弱类型,解释型,脚本语言。
1.弱类型:数据类型不固定,可以随时改变。(不用去声明数据类型)
2.解释型:相对于编译型来说。
1编译型语言:程序在运行之前就需要整体的进行编译(翻译)。
2解释型:程序运行的时候不会编译,拿一行代码,解释一行代码。
3.脚本语言:
脚本:是一种程序,它不能独立运行,需要一个载体。
核心,ECMAScript,负责核心语法部分(简称ES,主要讲的是ES5然后讲ES6、ES7…)
文档对象模型,DOM 一套提供给程序员操作浏览器功能的API
浏览器对象模型,BOM 一套提供给程序员操作页面元素的API
1.控制浏览器弹出警告框
alert(" ");
2.计算机在页面中输出一个内容
document.write(" ") ;可以向body中输出一个内容
3.向控制台输出一个内容
console.log(" ");
4.在页面中弹出一个输入框,给用户提供输入信息位置
prompt(" ");
5.弹出一个确认框。有确认和取消按钮;
confirm(" ");
代码从上往下执行
1.行内写法(局限性大,代码分离性差,可读性不强)
编写到标签的onclick属性中
你也点我一下 编写到超链接的href属性中
2.内嵌式(通常在body的最下面写,因为代码从上往下执行)
3.外链式(项目会把JS代码和HTML CSS进行分离)
一旦引入外部文件,中间不能再写命令,
如要写再创建一个script标签
字面量都是些不可变值例如1 2 3 4 5
变量可以用来保存字面量 例如 x=1 2 3 且变量的值是可变的。还可以通过变量对字面量进行描述 ,例如 var age(年龄)=80
声明变量: var a;
变量赋值: a=123;
合并成 var a=123;
一个变量声明一次就好。
一次定义多个变量:
1.第一种情况
var d = 1, e = 2;
2.第二种情况
var d = e =30;
1.声明了一个变量e(不带var),将30放进去
2.声明了一个变量d(带var),然后等于e ,相当于var d=e;
3.拿到了e中的1,将值放到d中。
变量之间相互赋值:
var a=123;
var b=345;
a=b;此时a的值为345
交换变量的第一个思路:使用第三方的变量进行交换;
var a=10;
var b=20;
var c;
c=a; //c=10;
a=b; //a=20;
b=c; //b=10;
交换变量的第二个思路:做加法,一般适用于数字的交换;
var a=10;
var b=20;
a=a+b; //a=30
b=a-b; //b=10
a=a-b; //a=20
变量起名有一定的规则:
1.数字,字母,下划线和$符。
2.不能以数字开头。
3.不能用关键字,保留字。
4.变量名要有意义。不要用拼音不要用中文。
5.驼峰命名法
1.String:字符串
2.Number:数值
3.Boolean:布尔值
4.Null:空值
5.Undefined:未定义
6.Object:对象
其中String Number Boolean Null Undefined属于基本数据类型,而Object属于引用数据类型(对象)。
在JS中字符串声明变量时需要使用引号引起来,使用双引号和单引号都可以,但是不要混着用。
引号不能嵌套,一单一双可以。
在字符串中我们可以使用 \ (斜杠)作为转义字符,当表示一些特殊字符时可以使用\进行转义
\ “ 表示 ”(双引号)
\ ’ 表示 ’ (单引号)
\ n 表示换行
\ t 表示制表符 (tab)
加引号输出字面量 字符串str
alert("str")
不加引号输出变量 str
alert(str)
在js中所有的数值都是Number类型,包括整数和浮点数(小数)
声明变量时不需要用引号引起来。
//数值123
var a = 123
//字符串123
var b = "123"
可以使用一个运算符 typeof 来检查一个变量的类型 语法:typeof 变量/值
例如: console.log(typeof a);
检查为字符串时,会返回 string
检查为数值时,会返回number
计算机对于小数运算会有偏差。
只有一个值undefiend
通常表示变量声明但是未初始化。
1.声明了变量未赋值
格式:typeof 值/变量(可以在后面写声明的变量 ,也可以直接写需要获取类型的值)
console.log(typeof a);
得到的结果是数据类型名的小写形式。
boolean,布尔
string,字符串
number,数值
undefined,值未定义(定义变量未初始化)返回underfined两种情况,一是声明未赋值,二是未声明。
object,当是对象或null时将会得到object
null是基本类型的值。但是typeof null的时候返回的是object。
其他的值:到时候再说
弱类型语言:弱在哪里:
类型转换分为两种类型:
1.将值转为布尔值(Boolean) 使用Boolean()小工具(得到的结果就是true和false)
var str= ;
console.log(Boolean(str));
2.将值转为数值(Number) 使用Number()小工具。
布尔值转数值:true转换为1,false转换为0.
null转数值:转换为0.
undefined:会转换为NaN.
var str= ;
console.log(Number(str));
字符串转数值的话:
1.字符串中只包含数字,包含浮点数 原样转换出来。
2.空字符串,空白串转换为0.
3.其他情况(数字字母结合之类)转换为NaN.
parseInt()
,将字符串转换为整数(如果其中的值不是字符串那么先转换为字符串)。
它会忽略前面的空格,找到第一个非空格的字符。如果这个字符是数字或负号,将会看第二位是否是数字如果是就转换为数值,一直向下找。一直找到不是数字的。
var str="25px";
console.log(parseInt(str));
parseFloat()
小工具:将字符串转换为小数。(用的比较少)
3.将值转为字符串(String)
1.数值、布尔、字符串有toString()
值会原样转换。
2.undefined和null是没有toString()的,所以调用会报错。
var str= 25;
console.log(str.toString())
3.转换后的类型获取
var str= true;
console.log(str.toString())//布尔转字符
console.log(typeof String(str));//获取到类型为 string
4.原本的类型不改变
var str= true;
console.log(str.toString())//布尔转字符
console.log(typeof str.toString()); //toString()获取类型写法
console.log(typeof String(str));//获取到类型为 string
console.log(typeof str);//str 还是Boolean类型
1.如果能调用toString()就自己调用toString()。
2.是null,则返回null。
3.如果是undefined,则返回undefined。
var str= null; //null转字符串
console.log(String(str)); //返回null
隐士类型转换和上面的规则相同,它通常和运算符相关联。(自己偷偷转换)
举例
Undefined+1 自己将underfined偷偷转为了数值类型 输出NaN NaN+1输出还是NaN
NaN:not a namber;非数字,属于number类型, 用来表示数值的一种不正常的状态,一般情况下会在计算出现错误,无法计算的时候出现;
用数值和一个不是数值的数据进行算数运算,就会返回NaN;
console.log(11-"a");//NaN
NaN与任何数值计算都会得到NaN
console.log ( NaN + 7 ); // NaN
NaN与任何数字都不等,包含它本身;特殊到NaN不等于NaN;(和任何数比较结果都是false)。
console.log ( NaN == 0 ); // false
console.log ( NaN == NaN ); // false
关于NaN
不是数字,但属于数值类型
用数值和一个不是数值的数据进行算数运算,就会返回NaN;
NaN与任何数值计算都会得到NaN
NaN与任何数字都不等,包含它本身;特殊到NaN不等于NaN;
NaN不是数字,所以isNaN返回的是false
console.log(typeof(NaN));效果是在控制台输出’number‘;
特例NaN,和任何值都不相等,包括都不等于自己,只能用isNaN做判断
表达式:将数据(变量、数值)用运算符按照对应的规则连接起来的式子叫表达式。可以被求值。
分类
var a=123;
var result=typeof a; //获取a的数据类型
console.log(typeof result); // 以string形式返回
当对非Number的值进行运算时,会将这些值先转为Number值再运算,最后得到一个Number类型的值。(除了字符串加法 )
任何值做减 乘 除 运算时都会转为Number**(隐式类型转换)** ,原理和Number()函数一样
var d="123"; //字符串类型123
d=d-0;
d=d*1;
d=d/1; 都可以得到Number类型 123
var result;
result=true+false; //1+0=1
result=NaN+true; //NaN+1=NaN
var result;
result="你好"+123; // 得到 你好123
result=123+"1"; // 拼接得到 1231
result=1+2+"3"; // 先1+2得到3 然后再拼串 得到33
result="1"+2+3; // 先1+2得到12 然后再拼串 得到123
var result=123; //Number类型123
result=result+"";//加空串得到 String类型123
除法(/)
被除数/除数=商
1.被除数为0,结果为0。
2.除数为0,结果为Infinity
。
3.任何数和Infinity运算结果还是Infinity
4.被除数 和除数都为0,结果为NaN。
求模,取余(%)
第一个数小于第二个数,结果是第一个数。
console.log(3 % 5) // 得到3
第二个数不能为0,如果为0结果为:NaN。
console.log(3 % 0) // 得到NaN
求余数。可以通过(n% 2
余数是否为0 就知道是否是偶数,1就是奇数)。
求一个范围内的数。
console.log(x % 8); //它的结果只能是0~7之间的数
求出一个数字每一位上的数字是多少。
例如:
678 我的需求:我想知道个位、十位、百位分别是多少。
var v1 = 678 / 1 % 10; //个位除以1 然后求模10
console.log(v1);
var v2 = parseInt(678 / 10 % 10); //十位除以10 然后求模10,用parseInt()输出整数
console.log(v2);
var v3 = parseInt(678 / 100 % 10); //百位除以100 然后求模10,用parseInt()输出整数
console.log(v3);
只需要一个操作符
var a= true;
a=-a; //true转数值为1
console.log(a) // 输出值为-1
可以对一个其他数据类型使用 +号来将其转为number类型 ,原理和Number()函数一样**(隐式)**
注意:并不会改变原变量的数据类型
a=1+"2"+3; //输出a为string类型 123
a=1++"2"+3; //输出a为number类型 6
自增++
a++的值等于原变量的值(自增前的值) //先用后加
++a的值等于新值(自增后的值) //先加后用
举例1
var c=10;
c++; //这里c++等于原值10,但是c自增了一次,c变成11了.
console.log(c++) //c变成11了,c++在11上维持原值,所以输出11.
举例2
var a=3;
console.log(++a) //++a为4 a为4
console.log(++a) //++a为5 a为5
console.log(++a) //++a为6 a为6
console.log(a++) //a++为6 (因为前面a为6了,所以a++在6的基础上等于原值6) 但是a已经加了4次 a的值这时为7
console.log(a++) //a++为7 是因为前面a已经变为7 在7的基础上等于原值所以为7 但是a这时已经是8了.
举例3
var d=20;
var result= d++ + ++d +d
//这里 d++维持原值为20 但是d自增1次变成了21
//所以这里 ++d 是在d变成21的基础上自增1,等于22了
//最后d已经经过两次自增了,变成了22
//所以最后result输出得到20+22+22等于64.
自减(同自增一样)
a=a+b 简写为 a+=b;
a=a-b 简写为 a-=b;
*=
/=
%=
=
,将等号右边的值或表达式的结果放到变量中。
左边肯定是容器(变量、对象属性),右边肯定是值或有值的内容。
比较运算符最后的结果应该是布尔值,true或false。
>
<
>=
<=
比较规则:
如果两个操作数都是数值,执行数值比较。
如果两个操作数都是字符串,比较两个字符串对应的字符编码。(不常用)
从第一个字符的编码开始比较,如果第一个字符的编码能够比较出大小则后面的不比较,如果不能比较出大小则继续比较第二位。一直向后比较。
如果到最后都没有比较出来,则谁的位数多谁大。
console.log('234' > '123456789');//输出true '2'编码值为50 ;'1'编码值为49.
如果是其他类型比较则使用Number()
进行转换。
NaN和任何数比较结果都是false。
相等和不相等 (会自动转换数值类型再做比较)
==
相等 ,如果两个操作数相等,返回true。
!=
不相等,如果两个操作数不相等,返回true。
如果类型相同比较值是否相等。
类型不同,只要有一个操作数是数值就先调用Number()
基本类型number、string、boolean和基本类型number、string、boolean。会先转换为数值。
undefined和null是相等的。
console.log(null == undefined);// true 其是为相等的(这里并没有调用Number())
console.log(null >= undefined);// Number(null) >= Number(undefined) 0 >= NaN false
NaN和NaN不相等。
console.log(NaN != NaN);//true
1.console.log(null == 0);//false null在做判断的时候,不进行类型转换
2.console.log(null >= 0);//true null>=0,null 是会进行类型转换的 Number(null) >= 0 0>=0 true
3. console.log(null == undefined);//true (没有理由记住就好)
console.log(null >= undefined);//false Number(null) >= Number(undefined) 0 >= NaN//false
全等和不全等 (不进行类型转换且数据类型和值相等的情况下全等)
===
,全等,两个操作数未经过类型转换相等的情况下返回true。!==
,不全等。在两个操作数为经过转换就不相等的情况下返回true。=
是赋值,==
是进行判断是否相等,===
是进行判断是否全等(没有经过类型转换值就得相等)
相等操作符、比较操作符只能比较两个值,但是有时候我们需要多个比较(需要有多个条件),这个时候我们就需要逻辑运算符。
&&
,逻辑与(与,and),第一个操作数和第二个操作数都为true时候返回true,否则返回false。(一假则假) console.log(true && true);//true
console.log(true && false);//false
console.log(false && true);//false
console.log(false && false);//false
逻辑运算符的返回值:操作数如果不是布尔值那么经过Boolean()
进行转换,返回时还是返回原来的值。
console.log(null && 1);//null 这里就是返回原来的null,而不是返回布尔值false
如果第一个操作数经过Boolean()工具转换为true,那么将会返回第二个操作数。如果第一个操作数经过Boolean工具转换为false,则返回第一个操作数。(已经得到结果,后面的第二操作数压根就不执行)
例如:console.log(1 && 2);//2 1转布尔值为true ,所以返回第二个操作符2
console.log(null && 1);//null null转布尔值为false,直接返回null。后面的1都不执行了。
短路操作:逻辑与操作属于短路操作,如果第一个操作数能够决定结果(第一个操作数为false时),那么就不对第二个操作数求值。
||
,逻辑或(或,or),如果两个操作数都为false时返回false,否则返回true。(一真则真)
console.log(true || true);//true
console.log(false || true);//true
console.log(true || false);//true
console.log(false || false);//false
console.log(1 || 2);// 1转布尔值为true,直接返回1
console.log(0 || 2);// 0转布尔值为false ,返回第二个操作符2
console.log(0 || null);// 0转布尔值为false ,返回第二个操作符null
题目1:
需求:有一个年份,我想知道是平年还是闰年。
//1. 已知的条件 年份
//2. 什么是平年、什么闰年 计算公式是什么。
4年一闰,百年不润。四百年一闰。
//能被4整除不能被100整除 或者 能够被400整除的才是闰年。
var year = 2021;
console.log((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
!
,取反(非,not),用来获得指定布尔值的取反的结果。(最终的结果是布尔值)。
该操作符可以应用任何值,变量如果不是布尔值那么逻辑非会先将它的值转换为布尔值,然后再求反。
var a = 0;
var b = 10;
console.log(!(a || b)); /// (0 || 10) 返回的是10 !(10) //不是布尔值 调用Bollean()得到true ,true取反为 false 。
隐式转换为相应的布尔值:!!a(a可以是其他数据类型)
var a = "6";
console.log(!!a); //!!a 可以将a转换为自身对应的布尔值.
取反还可以取相反的结果
格式:运算元1? 运算2: 运算3;
运算元1为条件。运算元2是表达式。运算元3也是表达式。(如果运算元1不是布尔值也会转换为布尔值再运算)
运算过程:如果运算元1为true,得到的结果是运算元2,为false的情况下得到的结果是运算元3。
举例:
var year = 2000;
var con = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);//一真为真
var res = con ? '闰年' : '平年';
console.log(res);
var a = 0;
var b = 10;
var c = a > b ? a : b; // 0>10 为false,所以c=b(运算元3)=10.
console.log(c);
运算元
1 + 2 ,1和2分别代表运算元(操作数)
运算符按照运算元来进行分类:
+
、-
、!
+
、-
、&&
、||
在js中可以使用{}来为语句进行分组,同一个{}中的语句我们称为一组语句。
它们要不都执行,要不都不执行
一个{}中的语句我们也称为一个代码块
{
alert();
console.log();
} //代码块后面可以不用加;(分号)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hgB120GR-1610018155588)(C:\Users\宋文现\AppData\Roaming\Typora\typora-user-images\image-20200705101513459.png)]
简要的规则:一元运算符优先级通常比较高,然后是二元然后是三元。如果你是在不确定运算符的优先级那就加括号。
使用条件判断语句可以在执行某个语句之前进行判断
语法一:
if(条件表达式){
语句...
}
//if语句在执行时,会先对条件表达式进行求值判断,
如果条件表达式值为true,则执行if后的语句
如果条件表达式值为false,则不会执行if后的语句
if语句只能控制紧随其后的语句,如果希望if语句可以控制多条语句,可以将这些语句统一放到代码块中。
语法二:
if(条件表达式){
语句...
}else{
语句... //里面可以继续嵌套 if...else if... else语句
}
//当该语句执行时,会对if后的条件表达式进行求值判断,
如果条件表达式值为true,则执行if后的语句
如果条件表达式值为false,则会执行else后的语句
只执行if或else中的一个代码块。
语法三:
if(条件表达式){
语句...
}else if(条件表达式){
语句...
}else if(条件表达式){
语句...
}else{
语句...
}
执行过程:
===
)。注意:
switch语句在比较值的时候使用的是全等操作,不会发生类型转换。
default语句可以省略.(看需求)
break关键字可以省略。
:匹配到case并执行完对应语句后如果没有break;的话,会向下继续寻找直到找到break退出switch,过程中的语句也会被执行出来。
var month=parseInt(prompt("请输入月份"))
switch (month) {
case 1:
case 2:
case 3:
alert("是春季呢");
break;
case 4:
case 5:
case 6:
alert("是夏季呢");
break;
case 7:
case 8:
case 9:
alert("是秋季呢");
break;
case 10:
case 11:
case 12:
alert("是冬季呢");
break;
default:
alert("你怕不是来着火星");
break;
}
//合理穿透:当存在多种值需要执行相同代码时使用穿透可以节省代码,只写一个break;如上。
switch也可以作条件判断,if也可以做精确(全等)判断,考虑合适与否。
switch也可以作条件判断:
switch(true){
case(条件判断表达式): //表达式的值true或false
语句;
break;
}
格式:
while(条件表达式){
重复执行的代码
}
执行过程:
使用while循环要注意三个要素:
循环中可以嵌套任意我们学过的代码,包括循环。这样就形成了循环的嵌套。
:如果while内部嵌套了while,运行到内部while时会在内部while循环直到false跳出循环才会接着执行下面的代码。
//1.打印1~100的整数。
var a=1;
while(a<=100){
console.log(a);
a++;
}
//2.打印1~100之间的偶数。
var a=1;
while(a<=100){
if(a%2==0){
console.log(a)
}
a++;
}
//3.1~100的和。
var a=1;
var num=0;
while(a<=100){
num=a+num;
a++;
}
console.log(num);
//4. 1-100偶数的和
var a=1;
var num=0;
while(a<=100){
if(a%2==0){
num=a+num;
}
a++;
}
console.log(num);
//5.5行6列的矩形
var a=1;
while(a<=5){
b=1;
while(b<=6){
document.write("*")
b++;
}
document.write("
")
a++;
}
//6. 5行三角形
var a=1;
while(a<=9){
b=1;
while(b<=a){ //这个while直到false跳出才会去执行下面的 document
document.write("*")
b++;
}
document.write("
")
a++;
a++;
}
//7. 99乘法表
var a=1
while(a<=9){ //这里有9行
b=1
while(b<=a){
document.write(b+"*"+a+"="+a*b+" ")
b++
}
document.write("
")
a++;//这里决定内部while执行几遍,也就是这行有几列。
}
语法:其实和while差不多,只是把3个条件写在一起了
for(var i=1(初始化表达式);i<10(条件表达式);i++(更新表达式)){
循环语句;
}
执行顺序:
1.执行初始化表达式,初始化变量
2.执行条件表达式,判断是否执行循环
如果为true。则执行循环语句,如果为false,则不执行循环。
3.执行完循环语句后,就执行更新表达式,然后再重复 2(第二步)
注意:1.for循环中的三个部分都可省略,也可写在外部
2.如果ror循环中不写任何表达式,只写2个;(分号),此时是死循环。
//打印1-100内 7的倍数的个数和和
var num=0;
var sum=0;
for(i=1;i<=100;i++){
if(i%7==0){
num++;
sum=sum+i;
}
}
console.log(num);
console.log(sum);
//打印水仙花数(水仙花是三位数,个位的3次方+十位的3次方+百位的3次方=本身)
for(var i=100; i<1000;i++){
var bai=parseInt(i / 100 % 10);
var shi=parseInt(i / 10 % 10);
var ge=(i / 1 % 10);
if(bai*bai*bai+shi*shi*shi+ge*ge*ge==i){
console.log(i);
}
}
质数练习
//1.遍历1-100之间的质数并输出(质数只能被1和本身整除,1不是质数也不是合数,质数必须是比1大的自然数)
for( var i=1;i<=100;i++){ //1-100遍历
var flag=true; //先假设是i是质数先。
for(var b=2;b
//2.在页面中接受一个用户输入的数字,并判断该数是否为质数。
var num =parseInt(prompt("请输入一个大于1的整数:"))
if(num<=1){
alert("你这不按要求来啊");
}else{
var flag=true;
for(var i =2; i
语法:
do{
循环代码;
}while(条件表达式)
执行顺序:先执行do中的语句,然后检查条件表达式是否成立,如果成立true继续执行do内的代码。
break关键字可以用来退出switch或循环语句
不能在if语句中使用,但是如果if语句是在循环语句中的话则可以
break只对最近的循环语句起作用,如果内层循环有break的话只结束内层循环,而不会影响外层循环。
可以为循环语句创建一个label(任意取名),来标识当前的循环,然后使用break时,可以在break后跟着label,这样break将会结束指定的循环,而不是最近的。(外层循环结束了,内层自然也就结束了)
outer:(取名)
for(var i=0;i<5; i++){
console.log("@外层循环"+i);
for(var j=0;j<5; j++){
break outer; //label用法
console.log("@内层循环"+j);
}
}
continue关键字可以用来跳过当次循环
同样continue也是默认只会对离他最近的循环起作用,内层写的影响内层,不影响外层。
如果只写一个continue的话(没有条件的情况),每一次都会跳过。
也可以和break一样用label来标识当前循环,使用continue时后跟label,来跳过指定循环,而不是最近的。
outer:
for(var i=1;i<5; i++){
console.log("@外层循环"+i);
for(var j=1;j<=5; j++){
if(j==2){
continue outer;
}
console.log("@内层循环"+j);
}
}
console.time("计时器的名字") //以字符串命名 然后开始
需要测试运行时间的语句放在中间
console.timeEnd("计时器的名字") //结束
数组可以用来存储一组值。
数组的好处就是可以对里面的一组值进行批量操作。
数组:一组值,数组可以存储多个值(每一项可以保存任何的数据类型,但是一般情况下都是相同的数据类型),有序的集合。
下标(索引、键、key),为了能够拿到对应位置的数据,所以给它标识。
下标都是从0开始。
元素:下标和值的组合叫元素。
类和对象的概念
数组是对象类型的(引用类型)的一种。
ES中没有类,有对象。
1.使用Array来创建
var colors = new Array();//现在我就创建了一个新的空数组。
console.log(colors); //控制台输出数组
console.log(typeof colors);//返回数组类型
new
是操作符,它表示调用后面的内容(Array
,你可以暂时将Array
理解为类,但实际上Array不是类。)
2.在Array中如果只有一个元素并且是数值,将会创建数值个数的元素的数组,如果只有一个元素值是其他类型则会创建只有一个元素的数组。
console.log(new Array(4));//里面是值都是undefined;
var color =Array("red","blue") //声明数组时也可以省略new操作符,结果一样(内部也会调用`new Array())
3.字面量方式
var color=["red","blue"]; //直接中括号就好了
数组.length 可以获取数组里的元素的数量(数组长度);
console.log(arr.length)
数组.length 可以用来修改数组长度 arr.length = 5;
a.增加长度:设置更大的length来增加数组的空间
arrStus.length = 5;
b.减少长度:设置更小的length来减少数组的空间
arrStus.length = 2;
数组长度 = 数组最大下标 + 1;
数组最大下标 = 数组长度 - 1;
操作数组时首先要干的事就是找下标。
var color2 = ['red', 'blue', 'green', 'pink', 'yellow'];
console.log(color2[2]); // 输出green
读取时候使用 数组[下标] 的方式。
如果读取时超过了最大的下标,那么值为undefined
。
中括号中可以放置的是任何返回数值或数值型字符串的表达式。如
var color2 = ['red', 'blue', 'green', 'pink', 'yellow'];
console.log(color2['0']);
console.log(color2[25 - 25]);
console.log(color2[1 + 1]);
4.拿取数组中的最后一个元素(数组中最后一个元素下标就是color2.lenght-1)
var color2 = ['red', 'blue', 'green','pink'];
//如何拿到最后一个元素。
console.log(color2[color2.length - 1]);
5.遍历:将数组中的所有值拿出来。(配合lenght属性)
//顺序遍历
var color2 = ['red', 'blue', 'green','pink'];
for (var i = 0; i < color2.length ; i++) {
console.log(color2[i]);
}
//倒序遍历
for (var i = color2.length - 1; i >= 0 ; i--) {
// console.log(i);
console.log(color2[i]);
}
1.在末尾增加
使用lenght属性始终向数组末尾添加元素
var colors = ['red', 'blue'];
colors[colors.length] = 'green'; //向末尾加了一个green;
console.log(colors); //变成[red , blue , green]
colors[colors.length] = 'pink'; //又向末尾加了一个pink;
console.log(colors); //变成[red,blue,green,pink]
2.使用下标增加的话,设置时超过了最大下标的话,那么数组的最大下标为最后设置的下标,同时数组的长度变为 设置后的下标+1
var colors = ['red', 'blue', 'green'];
colors[5] = 'pink';
console.log(colors); //此时的数组长度为6了。
3.在数组的开始处进行添加
var col=["red","blue","yellow","pink"];
for(var i=col.length;i>=0;i--){ //这里i=col.length 最大下标为4 数组长度增加了一位;0~4长度为5
col[i]=col[i-1]; //一波操作下来变成了[r,r,b,y,p]
}
col[0]="black"; //这里重新为col[0]赋值,值为你想要在开始处添加的元素。
console.log(col);
4.数组指定位置处添加
例如:将pink插入到第二个下标的位置。(0 1 所以其实是下标为1的位置)
var colors = ['red', 'blue', 'green'];
for (var i = colors.length; i >= 0; i--) { //老规矩i=colors.lenght 最大下标为3 ,数组长度加1为4(0~3)
if (i === 1) { i=1,其实是下标为1的位置,如果想要插入到哪个下标的位置,只需更改i===?;下面的colors[1]改成相应的。
break;
}
colors[i] = colors[i - 1];//第一步colors[3]=colors[2] [r,b,g,g]
}
colors[1] = 'pink'; //到这里已经是[r,b,b,g],需要重新为下标1的元素赋值,值为你要插入的元素值
console.log(colors);
5.删除数组末尾的元素
lenght属性是可以修改的,如果lenght修改的值比原来的小,后面的值会自动删除。
var col=["red","blue","yellow","pink"];
col.length--;
console.log(col);
6.删除数组开头的元素
var col=["red","blue","yellow","pink"];
for (var i = 1; i < col.length ; i++) { // i=1-3,数组长度为3
col[i - 1] = col[i]; //操作下来得出[b,y,p,p]
}
col.length --; //长度减一,末尾元素删除 变成了[b,y,p]
console.log(col);
7.删除指定位置的元素
var col=["red","blue","yellow","pink"];
for (var i = 1; i < col.length ; i++) { i=1 col[i-1]=col[0]所以删除下标为0的元素,所以改变i的值来调整[i-1]的值(即你要删除的元素的下标)
col[i - 1] = col[i];
}
col.length --;
console.log(col);
8.数组求和
var arr=[1,2,3,4,5,6,7,8,9,10];
var num=0;
for(var i=0;i
1.默认arr[0]为最大值赋值给max
2.从arr[1]开始大于max(也就是arr[0]),然后arr[1]被赋值给max,成为目前最大
3.继续遍历arr[i] 并与max (现在是arr[1]了)比较,如果比arr[1]大的话,又重新赋值给max
4.循环比较赋值得出最大值
这里其实max相当于一个容器,储存当前最大值,有比它大的就重新赋值,没有就它最大。
var arr = [1,2,3,4,5,6,7,8,9,10,88,22,-1,100];
var max = arr[0]; //默认arr[0]为最大值赋值给max
for (var i = 0 ; i < arr.length ; i++) {
if (arr[i] > max) { //从arr[1]开始大于max ,然后被赋值给max,直到下面遍历的数超过max,然后又重新赋值给max ,这样重复比较赋值得出最大值.
max = arr[i];
}
}
console.log(max);
var arr= [1,2,3,4,5,6,7,8,9,10,88,22,-1,100];
var min = arr[0];
for (var i = 0 ; i < arr.length ; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
console.log(min);
var arr=[10,1,35,61,89,36,55];
for(i=1;iarr[j+1]){
var temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
console.log(arr);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qj8FkanP-1610018155592)(C:\Users\宋文现\AppData\Roaming\Typora\typora-user-images\image-20200707180551100.png)]
var arr=[1,2,3,4,3,4,2,1,3,4,5];
var newArr=[]; //创建空数组来装非重复值
for(var i=0;i
1.利用空数组
var arr = [1,2,3,4,5,6,7,8,9,10,88,22,-1]; // 变成arr = [-1,22,88,10,9,8,7,6,5,4,3,2,1]。
var newArr = []; //创建空数组
for (var i = arr.length -1 ; i>= 0; i--) {
newArr[newArr.length] = arr[i]; // 倒序遍历给newArr数组
}
console.log(newArr);
2.获得对调元素的下标然后交换位置
var arr = [1, 2, 3, 4];//4,3,2,1
for (var i = 0; i < arr.length / 2; i++) { 获得到要对调的元素的下标。
console.log(i);
console.log(arr.length - 1 - i);
//交换它们的位置
var tmp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = tmp;
}
console.log(arr); */
两个循环遍历一遍
var arr1 = [1,2,3,4];
var arr2 = [5,6,7,8,9];
var arr = []; //建arr[]空数组来装合并后的数组
for (var i = 0; i < arr1.length ; i++) {
arr[arr.length] = arr1[i];
}
for (var j = 0; j < arr2.length ; j++) {
arr[arr.length] = arr2[j];
}
console.log(arr);
var performeres = [
//编号,演员姓名,饰演角色,性格
[1, '孙红雷', '何辅堂', '为人正直不阿,欺强怜弱,善于机变。'],
[2, '巍子', '魏正先', '鹰视狼顾,心狠手黑。'],
[3, '陈数', '程立雪', '气质如兰,观之可亲,思想卓荦,才华压众。'],
[4, '郭珍霓', '刘二泉', '动不便,但若论手段心机,十个健全人也不是她的对手。'],
[5, '陈祉希', '朱彩灵', '刀马旦出身,水般柔美,火样性格。含威不露,顾盼神飞。']
];
document.write("");
var str = "编号 演员姓名 饰演角色 性格 ";//表头
for (var i = 0; i < performeres.length ; i++) {
str += "";
str += ""+performeres[i][0]+" "; //字符串拼接
str += ""+performeres[i][1]+" ";
str += ""+performeres[i][2]+" ";
str += ""+performeres[i][3]+" ";
str += " ";
}
document.write(str);
document.write("
");
维:维度。
数组每个元素都可以存储任意类型的数据,数组中元素的值还为数组。
数组一般情况下就到3维,一维和二维用的多,三维数组几乎不用。但是不管是多少维的数组都是一层一层的往里面找。
var arr= [
[1,2], //arr数组下标0的元素
[3,4] //arr数组下标1的元素
];
console.log(arr[0][1]); //得到[1,2]中的2
console.log(arr[1][0]); //得到[3,4]中的3
函数:完成指定任务并且已经命名的代码块。可以进行反复的使用。
函数本质上也是一种数据,是属于对象类型的。函数的也是值,与其他变量的数据类型不同的是,函数中包含的是代码,可执行的代码。
1.系统函数,系统提供的(Blooen() String() Number())
2.自定义函数,如果系统不能满足需求就自己写
var variable = function(){
语句
}
variable() //调用
这种声明方式是函数表达式方式,既外围语句是表达式。(不能以function开头 )
这种方式声明的函数,调用必须在创建之后(执行到这个表达式)才行。
printTable(); //调用
function printTable(){
console.log('闫海静真英俊!');
}
这种声明方式调用可以在函数前面,这种声明方式在代码真正运行之前这个函数就已经被声明了。
这种函数名可以重复,一但重复后面的覆盖前面的。
var a = new Function("console.log('abc')")
是使用Function构造函数来声明函数。给你说这个就是为了说明函数是一个引用类型。因为使用了new
不建议使用该方法声明函数,因为该方法会导致代码解析两次(一次常规解析ES代码,第二次是解析传入到函数中的字符串)。
函数是数据,函数名是这个数据的标识。
如果要访问函数对应的数据而不是执行函数的话,需要去掉函数名后面的那对圆括号。
圆括号表示的是函数调用符
函数是一个数据,函数名是标识,一个函数可以有多个标识。
设计自定义函数的时候:基本原则:用户(调用函数的人)可以参与控制自定义函数,可以对自定义函数进行一些微调。
function printTable(r,c) {
document.write('');
for (var row = 0; row < r; row++) {
document.write('');
for (var col = 0; col < c; col++) {
document.write('哈哈哈哈@!@# ');
}
document.write(' ');
}
document.write('
');
}
printTable(3,3);
printTable(5,5);
()
里面实际使用的参数。(下面的3,3是实参)注意:
arguments对象
中。arguments对象只在函数内部才有。
arguments对象实际上是一个类数组的对象。我们可以访问这个对象来获得传递给函数的每一个实参。
array-like
,像数组,但不是数组。因为它有下标、有length属性。
如何区分是数组还是类数组 我们以后再说。
函数中的形参可写可不写,即使不写形参也可以使用arguments对象获得。因为使用形参比较方便。
arguments对象的length属性用来确定传递进来多少个实参。
可以通过length属性的值的不同(根据传入的参数个数的不同),进行不同的操作。
arguments
对象中保存着一个叫callee的属性,这个属性是一个指针,它指向拥有这个arguments对象的函数。arguments.callee指的就是这个函数。
返回值。
return 要返回的值
return语句将return后面的值返回到函数调用处。
//定义一个函数,求1到n的和。
function he(n) {
var sum = 0;
for (var i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
he(10)
console.log(he(10)); //sum返回到函数调用处,函数的结果就是sum,这里就是打印sum的意思
注意:
undefined
。undefined
通过以上的特点:return的作用:1.返回函数中要返回的值。2终止执行函数(return后面没有内容就只是单纯的终止函数执行。)
函数体、参数、返回值:是组成一个完整函数的三大件。
返回值的情况:
1.没有return,写再多函数的返回值还是undefined
2.有return,后面不跟东西,返回值也是undefined
3.return后跟的就是函数的返回值,也可以理解为函数的执行结果。
4.return只会返回函数结果,并不会打印,所以需要声明一个变量来接收,再打印变量。
var rel=he(10);
console.log(rel)
IIFE:
Immediately Invoked Function Expression
,意为立即调用的函数表达式,也就是说,声明函数的同时立即调用这个函数。
在规范当中函数表达式语句
,1不能以大括号开头({
),2不能以function关键字开头。
(function(){ //就是外面用一个括号把函数包起来,然后直接用括号调用。
console.log('foo');
})();
IIFE函数只能运行一次,因为引用类型没有标识符,执行完成之后会被JS的垃圾回收机制释放。
特点:
function say(a){ //递归推演。递是进去,归是出来。
console.log(a);
if(a>=1){
say(a-1); //此处又重新调用函数say
}
console.log(a); //输出3,2,1,0,0,1,2,3
}
say(3)
思路:这里每次调用的函数虽然是同一个函数,但是每次调用的时候产生的执行环境是不同的
say(3) console.log输出 3 3>=1 执行say(2),又返回去调用函数say(2),记住这里下面还有一个console.log(3)没执行呢
say(2) console.log输出 2 2>=1 执行say(1),又返回去调用函数say(1),记住这里下面还有一个console.log(2)没执行呢
say(1) console.log输出 1 1>=1 执行say(0),又返回去调用函数say(0),记住这里下面还有一个console.log(1)没执行呢
say(0) console.log输出 0 0>=1 false;不执行if ,直接执行下面的console.log(0);这时候say(0)执行完了,执行环境销毁了,接着归回去执行刚刚未执行的。
每归回去执行完以后都会销毁对应的执行环境。
感觉跟循环有点像,都是执行完再去执行下面的。
2.1-5累加求和(递归方式)
function say(a){
if(a>=1){
a+=say(a-1); //这里a=a+say(a-1) ,只执行到右边的say(a-1),左边的a=a+未执行
}
return a;
}
console.log(say(5));// 这里既调用又打印
思路:
say(5) 5>1 然后a=a+say(5-1),去执行say(4)去了,这里的a为5 还有a=a+未执行
say(4) 4>1 然后a=a+say(4-1),去执行say(3)去了,这里的a为4 还有a=a+未执行
say(3) 3>1 然后a=a+say(3-1),去执行say(2)去了,这里的a为3 还有a=a+未执行
say(2) 2>1 然后a=a+say(2-1),去执行say(1)去了,这里的a为2 还有a=a+未执行
say(1) 1>1 然后a=a+say(1-1),去执行say(0)去了,这里的a为1 还有a=a+未执行
say(0) 0>1 false 这时执行下面返回a ,所以say(0)返回值为0,这里执行完了销毁,返回去执行未执行的
say(1):a=a+say(0)=1+0 say(1)返回值为1
say(2):a=a+say(1)=2+1 say(2)返回值为3
say(3):a=a+say(2)=3+3 say(3)返回值为6
say(4):a=a+say(3)=4+6 say(4)返回值为10
say(5):a=a+say(4)=5+10 say(5)返回值为15,最后值为15
注意:
什么是回调函数
回调函数的精髓:函数是对象类型的值,可以被当做参数传入到函数中。
函数传参时如果传入的是基本类型的值那是赋值,如果传入的是引用类型的值赋的是地址。
一个函数本身也是值,是一个对象,所以可以被当做实参传入到函数中,并且被执行。
回调函数被认为是一种高级的函数,一种被作为参数传入给另外一个函数(OF)的高级函数,回调函数会在OF内被执行或调用。
回调函数是什么:本质是一种模式,解决问题的套路。
回调函数的用处
举例:
1.
function foo(fn){
console.log('!!!!');
console.log(fn); //这里fn为bar,所以打印的是bar函数
fn(); //这里实则是bar(),调用了bar函数。
}
function bar(){
console.log('is bar');
}
foo(bar); //调用foo函数,把bar函数当作实参赋给foo函数的形参fn(这里实则是把地址赋过去)
2.
function foo(){
function bar(){
console.log('foo --------------> bar');
}
return bar; //foo函数的返回值是bar函数。
}
var res = foo(); //调用函数foo,并将他赋给变量res,因为foo函数的返回值是bar,实则是将bar赋给了 res
res(); //这里即等于bar(),调用了bar函数
3.回调函数的实例
//循环0~指定的数,然后用 各种过滤规则 来进行过滤。
//和5取余为0的都去掉。
//最后一位为3的都去掉。
function getNumber(num,fn,tn){
for (var i = 1 ; i <= num ; i++) {
if (fn(i)&&tn(i)) {//1 //这里通过形参调用函数,fn(i)为rules2(i) tn(i)为rules1(i)
console.log(i);//1
}
}
}
//1. 定义和5取余为0的规则
function rules1(n){//1
var yu=n%5; //定义变量接收结果
if (yu == 0) {//1
return false;
} else {
return true;//true 函数的返回值将返回调用处 ,也就是上面的tn(i)
}
}
//2. 定义 最后一位为3的都去掉。 的规则
function rules2(n){
var pos = n / 1 % 10;//获得最后一位的值
if (pos == 3) {
return false;
} else {
return true;
}
}
getNumber(100,rules2,rules1); //这里调用函数getNumber,并把函数rules2,rules1作为实参传给形参
堆、栈,数据结构中的内容。堆(链表结构)、栈(栈结构)。
程序运行的时候按照逻辑分为了堆内存和栈内存。
栈:栈结构中开辟的内存,比较小,速度比较快,操作系统分配并且自动回收。
特点:先进后出。
堆:堆结构中开辟的内存,比较大,速度比较慢。一般都是由程序员自己用的时候去申请,系统分配。如果要让内存回收,必须手动释放回收。
特点:先进先出
JavaScript中我们所有的内存几乎都是自动分配、自动回收的。JavaScript中封装了垃圾回收机制。
JavaScript中运行、执行环境分为两种:
Global
,全局执行环境,JavaScript代码开始运行的时候默认的环境。Function
,函数执行环境。调用一个JavaScript函数时将会进入到一个JavaScript的函数执行环境。每个执行环境我们也通常称为执行上下文。
代码在执行的时候会开辟出来一段栈空间
用来说明代码的执行顺序,这个栈叫执行栈。
每个执行环境分为两个阶段:
什么是作用域?
作用域:变量起作用的区域范围。(变量能够访问的范围)
作用域的作用?
隔离变量(函数外部定义的变量和函数内部定义的变量即使同名也没关系)
作用域的确定时机?
作用域在进入到全局执行环境或函数执行环境时就已经确定好了。(函数定义时产生)
作用域种类?
ES5中作用域分为两种,全局作用域和函数作用域(局部作用域)。
函数作用域:就是指函数{}中间的范围。
全局作用域:就是指整个页面的范围
一执行JavaScript就进入到了全局执行环境就有了全局作用域。执行(调用)某个函数时进入到了函数执行环境就有了某个函数的作用域链。
同一个函数多次调用会产生不同的执行环境,每次调用都会产生一个。
解释:前面第一次调用函数生成的函数执行环境执行完已经被销毁了,后面再调用这个函数生成的是新的函数执行环境,所以函数作用域不一样了,既然函数作用域不一样,那么作用域链自然也不一样
var c = 3;
function test(){
var a = 1;
var b = 2;
console.log(c);//输出3 ,这里打印了全局变量c
}
test();
console.log(b);//打印不了函数中的 局部变量b
function test(){
var a = 1;
var b = 2;
console.log(a);
}
test();
console.log(a);//调用不了test函数中的a,打印显示变量没定义。
在函数内部声明变量时,如果不使用var,那么默认声明了一个新的全局变量,外部也能访问到。如果函数有同名形参的话,则赋给形参。(形参还是局部变量)
var c = 3;
function test(){
var a = 1;
var b = 2;
c = 30; //默认声明了全局变量c =30
}
test();
console.log(c);// 先执行函数,函数中的声明了全局变量c=30所以这里打印的结果是30
函数内部是可以嵌套函数的
function test(){
function test1(){
console.log('test1');
}
test1();
console.log('test');
}
test();
作用域是变量起作用的范围,作用域链是用来查找变量的这样一系列的过程。
一个函数在定义时会生成一个属性[[scope]]
,这个属性里面存储的是函数定义时的作用域的层级关系。
1.函数没被函数嵌套的话:[[scope]]
即为全局作用域
2.函数被函数嵌套的话:[[scope]]
等于外层函数的作用域(外面有几层函数就有几层作用域)+全局作用域
var a = 0;
function test(){
var a = 1;
function test1(){
console.log(a); //找到test中的a=1打印
}
test1();
console.log('test');
}
test();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F4bAJhXI-1610018155595)(C:\Users\宋文现\AppData\Roaming\Typora\typora-user-images\image-20200708190020388.png)]
作用域链是函数执行时创建的作用域链是由当前的函数自身的作用域+[[scope]]属性
中的作用域组成的。
函数当前执行的作用域是作用域链的顶端,全局作用域是作用域链的最后端。访问顺序从顶端到最后端。
执行环境被销毁,作用域链也会被销毁。
函数不调用不执行,但是函数一定义就有了[[scope]]
属性,作用域是在声明函数的时候已经确定了
总结:
作用域链由当前执行环境的作用域和[[scope]]
属性组成,整个作用域链在函数调用时才形成。
[[scope]]
属性:函数__定义__时就已经生成了。函数即使不调用也会有这个属性。它其中包含的是这个函数的各个层级的作用域。每个执行环境作用域链都是独立的作用域链。
查找过程:
变量未定义
),设置时是向全局作用域中设置新的变量。不带var也能定义变量,那是在全局,函数中不行。在函数中定义变量不带var就是在全局作用域中定义了一个变量(严格意义上说不加var不是定义变量。)。
变量如果是基本数据类型(String、Boolean、Number、undefined、Null)会在栈内存开辟一段空间存储标识符,然后将基本数据类型的值也存储在栈内存中并且和标识符对应起来。
引用类型的值存储在堆内存中,存储引用类型的时候回给堆内存一个地址。但是标识符还是存储在栈内存中,为了能够让标识符和真正的数据结合起来在栈内存中存储的值是引用类型的地址。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eiVyWhbr-1610018155598)(D:/笔记案例/JS上课内容/7.8/day6-2/笔记、代码/day6_img/Snipaste_2020-07-08_14-15-07.png)]
查找变量和执行环境有关系,和堆没有关系。堆只是用来存储对象类型数据的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3BnNctYJ-1610018155600)(C:\Users\宋文现\AppData\Roaming\Typora\typora-user-images\image-20200708181001643.png)]
总结:
程序一开始执行,进入了全局环境,首先会创建全局环境并且压栈(执行栈),全局代码执行的时候依赖的是全局环境当中的东西。
全局变量如果是基本类型,那么这个值直接存在栈当中,如果这个变量的值是对象(函数、数组),那么函数和数组是要在堆内存中开始自己的空间专门存储(数据本身)。然后将堆里面的这块空间的地址存给栈当中对应的变量。
当程序执行碰到了函数调用,函数执行时也要有自己的环境去依赖。函数执行也是创建自己的函数环境进行压栈(函数执行环境一定压在全局执行环境的上面)。
局部变量,是函数环境当中存在的,只有函数执行,局部变量才会出现。函数执行完成之后,函数环境要弹出栈(销毁归还内存),局部变量也就不存在了。
当函数调用完成之后,会继续执行全局代码,一直到所有的全局代码都执行完成,代表程序执行结束,程序执行结束的时候,全局环境最后出栈(销毁)。
在执行环境的第一步(创建阶段时),会将带var的变量声明和函数的声明,放到所在的作用域顶端中,在执行阶段时,它的相关逻辑还是放在原来的位置进行赋值和其他的逻辑处理。
console.log(a)
var a=3;
变量提升后:
var a;
console.log(a); //所以输出undefined;
a=3
例子:
alert(a); //全局作用域变量提升 //碰到fn(),fn()作用域变量提升 //第二个fn()变量提升
var a = 0; function fn(); alert(a);//全局0 var a;
alert(a); var a; a=1; //全局1 alert(a);//un
function fn(){ var fn; alert(a);全局1 a=0;
alert(a); alert(a);//undefined alert(a++)//0
a = 1; a=0;
alert(a); alert(a);//0
} fn();
fn(); fn=function()
var fn = function(){ fn()
alert(a); alert //全局1
var a = 0;
alert(a++);
}
fn();
alert(a);
面向过程
以过程
为编程的中心
面向过程像流水线,一个阶段衔接另外一个阶段,每个阶段都有自己的输入、处理、输出。
最典型的面向过程语言:C语言。
面向对象
以对象作为中心的编程思想。
面向对象语言:Java Python PHP JavaScript
符合人类的思维习惯。
对于软件行业来说尤其是互联网行业,需求变更的比较频繁,而且复杂。
面向对象的思想核心就是可扩展性
类:一组相似事物的统称。
类的组成:
对象就是类的具体化,实物、实体,由类创建(实例)出来。
类就是模板,让多个对象拥有共同的属性、方法。
JavaScript当中没有具体的类,直接就是对象。而且在JavaScript中一切皆为对象。
对象:无序的键值对儿,它的值可以是基本值、对象、或函数。
数组:有序的键值对儿,它的值可以是基本值、对象、或函数。
var p = {
};
console.log(p);
声明了一个空对象(所谓的空对象指的是没有我们自己定义的内容)。
字面量方式声明的对象由于多个键:值
对组成的,每个键:值
对之间使用逗号分隔。
属性的值如果是字符串的话要加引号。
//age、name、sex都是名词,可以认为是属性、是对象的特征。
//对象属性的值也可以是函数,因为函数本身也是数据。这个时候可以称该属性为方法。say 动词
//javascript中函数永远不会单纯的属于这个对象,它们只是对于相同函数的引用。
var p = {
name:'yanhaijing',
age:18,
sex:'nan',
say:function(){
console.log('闫海静真英俊!');
}
};
console.log(p);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xy2fFdP8-1610018155603)(C:\Users\宋文现\AppData\Roaming\Typora\typora-user-images\image-20200710193830243.png)]
注意:
键是字符串并且不加引号(加上也行),键是其他类型也会被转换为字符串。
对象的属性名都是字符串类型
var p = {
1:'hehe',
undefined:'hello',
null:'world'
};
console.log(p);
如果键名不符合变量命名规则那就必须得加上引号。
var p = {
name:'yanhaijing',
'my Category':'person',
'1a':'hello'
}
对象的属性的值也可以是对象。
var p = {
p:{name:'yanhaijing'}
}
console.log(p);
写在object后面的括号里
var p = new Object( //object构造函数
{
name: 'yanhaijing',
age: 18,
sex: 'nan',
say: function () {
console.log('闫海静真英俊!');
}
}
);
console.log(p);
console.log(p.say())//调用函数
new是操作符标识调用后面的内容,创建一个对象。 (new Object()
,可以__暂时__将Object
看成一个类,它就创建了一个Object类型的对象),参照Array类型的数组
字面量方式创建对象,目的就在于简化创建包含大量属性的对象的过程。(字面量方式在内部也会调用new Object
)
我们声明Object类型的对象时候一般使用字面量方式定义。
object类型的对象它是一个__万能的对象__它可以根据其中的属性、方法存储任何的东西。
Object类型
的实例是个万能的对象,它可以根据其中的属性、方法,存储任何东西。
鸭子类型
//鸭子
var duck = {
duckSinging:function(){
console.log('嘎嘎!');
}
}
//鸡
var chiken = {
duckSinging:function(){
console.log('嘎嘎嘎');
}
}
//都加入了合唱团。
var choir = [duck,chiken];
//开始合唱
for (var i = 0 ; i < choir.length ; i++) {
choir[i].duckSinging(); //调用对象方法的值(函数)
}
鸭子类型指导我们只关注对象的行为,不关注对象本身,只要能达到我的需求,管你是什么对象。
以Object和对象字面量方式声明对象最大的缺点就是:代码重复,会产生大量重复的代码。
var p1 = {
name:'yangxianpeng',
age:18,
sex:'nan'
}
var p2 = {
name:'pengjinli',
age:73,
sex:'douxing'
}
//这样声明对象就很烦
换种思路:
function createPerson(name,age,sex) {
var o = new Object();//var o={}
o.name = name;
o.age = age;
o.sex = sex;
return o;
}
var p1 = createPerson('yangxianpeng',18,'nan');
var p2 = createPerson('pengjinli',17,'douxing');
console.log(p1);
console.log(p2);
console.log(p1 == p2);
console.log(p1 instanceof Object)
//1.就是声明一个函数,在函数内部声明一个对象以及属性。
//2.设置函数的返回值为这个对象
//3.再把函数的行参设为属性的值
//4.通过函数的实参传参把属性值传进去
//5.函数的返回值是对象,把对象赋给变量p1,p2打印
instanceof操作符
用来检测对象是什么类型的。(现在先这样认为。)
格式:对象 instanceof 类型
//这个对象是 对应的这个类型吗? 返回值是true或false。
我在程序当中有可能需要知道这个对象具体是什么类型的。现在都是Object类型。Object类型是万能的对象。
我就需要想办法知道某个对象的具体类型:
引出下面
构造函数:就是普通的函数,但是使用了new
操作符调用,这个时候通常称为构造函数,实际上不存在所谓的构造函数,这种方式应该叫函数
的构造调用
。(调用时会生成一个相应类型的对象)
定义要构造调用的函数时一般首字母大写(小写也行,但是大写是惯例)。
通过new关键字可以创建一个与函数类型相同的对象
new Object()会创建一个Object类型的对象
new Person() 会创建一个Person类型对象
new Array() 会创建一个 Array类型的对象
1.创建一个StuInfo类型的对象
function StuInfo(sName,sAge){
this.stuName = sName;
this.stuAge = sAge;
this.sayHi = function(){
console.log('Hi' + this.stuName);
}
}
//调用函数
//var stu1 = StuInfo();undefined;构造函数如果直接调用,返回undefined,因为构造函数中一般都不写return;即没有返回值;
var stu1 = new StuInfo('柳岩',31);
console.log(stu1);
var stu2 = new StuInfo('扎送',34);
console.log(stu2);
console.log(stu1 instanceof StuInfo)//true
1.不用创建对象,new调用时会创建对象
2.this暂时理解为当前正在实例的这个对象
3.要用new调用
注意:其实四种方式都算构造函数生成对象(前三种都有new object())
总结:
你每使用构造函数生成一个对象的时候都会在其中包含一个叫constructor
的属性。这个属性中存储的是一个指针,指向了生成该对象的构造函数
。
字面量方式生成的对象,也有constructor
属性,其指向的是Object
函数。(里面也调用了new object())
Object()
、Array()
、Function()
他们都是属于系统内建的。
构造函数中可以使用return语句,如果return的是基本类型的数据,那么return后面的值将会被忽略,最终得到的还是新创建的这个对象。
构造函数中返回的是其他对象。那么就返回这个对象。
例如:
function Person(name,age){
this.name = name;
this.age = age;
return {
name:'刘谭松',
age:12,
say:function(){
console.log('我已经不是三岁小孩了。');
}
}
}
var p = new Person('yanhaijing',18);
console.log(p); //这里返回的是return后的新对象
函数既是对象又是可执行的代码块:
新生成的对象
。有return如果返回的是基本类型就忽略,还是返回的新生成的对象,如果返回的是引用类型那么得到的就是这个引用类型。访问对象中的属性
使用.
表示法访问对象的属性。
使用[]
表示法访问对象的属性。最大优点就是可以通过变量、表达式来访问属性。([ ]访问要加双引号)
console.log(dog['color']);//对象['属性名']
console.log(dog.color);
可以在中括号中放置表达式,中括号中的表达式、变量都会进行运算。
var color = 'cat';
console.log(dog[color]);//dog['cat']
console.log(dog['col' + 'or']);
如果键不符合标识符命名规则需要使用[]
来进行访问,不能使用使用.
访问。
var p = {
name: 'yanhaijing',
'my Category': 'person',
'1a': 'hello'//键名不符合标识符命名规则。
}
console.log(p['1a']);
如果你访问的属性不存在,代码会返回undefined。是不会报错的。
增加、修改属性(有就修改,没有就增加)
如果添加、修改的键名不符合标识符命名规则那么只有使用中括号
。
添加属性:向对象中添加一个不存在的属性,其实就是往对象中添加属性
对象.属性名=属性值
对象["属性名"]=属性值
var dog={
name:"旺财",
sex:"man",
age:20,
"1a":25
}
dog.color="yellow";
dog["color"]="red";
删除属性
格式:delete 对象.属性
delete dog.age;
var 和不带var有什么区别:
window对象是JS中的最顶层对象。你在全局中声明的变量(带var
的)会被作为window对象的属性(变量)。
不带var的变量也会被作为window对象的属性。(不是变量)它只是window对象的属性。
var声明的全局变量不能使用delete删除,但是不带var声明的所谓的全局变量
可以使用delete删除。因为它只是属性
作用域链:描述查找变量的过程。
原型链:用来描述通过隐式原型对象查找属性的过程。
每个函数在创建的时候都会创建一个prototype属性,这个属性叫原型属性
,该属性中存储的是一个对象的引用(默认的时候是一个空对象)
在原型属性对应的对象中也有一个属性叫constructor属性,指向的是拥有这个原型对象的构造函数。(注意这里指向的函数是构造函数调用的函数,不是object函数)
console.log(Person.prototype.constructor===Person )//true
console.log(Person.prototype.constructor===Object )//false
prototype属性只有在函数被当做构造函数的时候(函数的构造调用)的时候才会有效。它的作用:由同一个构造函数生成的各个实例对象之间共享属性和方法。
__proto__
属性当调用构造函数创建一个新实例对象之后,该实例内部将包含一个内部属性__proto__
,指向构造函数的原型对象。
构造函数中的prototype属性和构造函数实例化出来的对象的__proto__
指向的是同一个对象。如下:
function Person(){
}
var p = new Person();
var p1 = new Person();
console.log(Person.prototype == p.__proto__); //true;Person.prototype是Person函数的原型对象
console.log(p.__proto__ == p1.__proto__); //true ;都指向同一个原型对象(Person.prototype)
基础原型链图:(图中的object是函数, Person.prototype既是Person的原型对象也是object函数实例化出来的一个对象)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zo8fD2Bw-1610018155605)(C:\Users\宋文现\AppData\Roaming\Typora\typora-user-images\image-20200711191606024.png)]
先在本对象中查找对应的属性,如果有就用了,如果没有那么就去该对象的__proto__
指向的对象(构造函数的原型对象)中去查找,如果有就用了。(按着__proto__
的指向一路找)
function Dog(){
this.name = '旺财'; //属性是实例对象私有的
}
Dog.sex="男" //Dog的静态属性,实例对象访问不到
var d1 = new Dog();
var d2 = new Dog();
Dog.prototype.say = function(){ //往原型对象中加了一个属性(方法)say,方法是公有的。
console.log('wang wang!');
}
d1.say();// d1中没有say这个属性,就往Dog.prototype(原型对象)中去找,找到就用了。
d2.say();
在原型中查找值的过程是一次搜索,对原型对象所做的任何修改都能够立即从实例上反映出来。(先创建的实例然后修改原型也是一样的。)如上。
__proto__
属性。prototype
和__proto__
都指向了同一个对象。因为在ES5的时候只允许操作prototype属性
,不允许操作实例对象__proto__
属性。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5o2lOApZ-1610018155606)(C:\Users\宋文现\AppData\Roaming\Typora\typora-user-images\image-20200711203525638.png)]
在实例化对象上找属性时,过程是先从自身找有没有这个属性,如果有就直接使用了,如果没有就沿着这个对象的隐式原型对象(__proto__
所指向的对象),继续找。如果能够找到就使用如果找不到就去找隐式原型对象中的__proto__
指向的对象,一直按照这种查找方式,直到最后找的是Object显式原型对象( Object.prototype),如果到这里都没有找到那就只能返回undefiend。
原型对象中的属性是给构造函数实例化出来的对象服务的,构造函数本身是不能使用的。
但是如果是Object的原型对象Object.prototype和Function的原型对象Function.prototype上的属性是可以使用的
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.say = function(){
console.log('Person.prototype.say');
}
var p = new Person('张三', 'nan');
Person.say();//报错,找不到say方法。
Obejct即是构造函数,也是Function实例化出来的对象,如下:
function Function(){
}
var Obejct = new Function()
所以Obejct作为对象的__proto__
指向的是构造函数的原型对象,即为Function.prototype
所有函数都是Function的实例, 包含它自己(Function是通过new自己产生的实例),所以Function作为实例化对象时,其__proto__
指向的是自己的原型对象Function.prototype
格式:对象 instanceof 函数
//这个对象是 对应的这个函数的实例化对象(或类型的对象)吗? 返回值是true或false。
A instanceof B
instanceof运算符
的第一个变量是一个对象,暂时称为A,第二个变量一般是一个函数,暂时称为B。__proto__
这条线来找,同时沿着B的prototype这条线来找,如果两条线能够找到同一个引用,既同一个对象,返回true,否则返回false。(即如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false)所有的引用类型都是Object函数的实例(其实Object也是Function实例对象),所以在检测引用类型时和Object时(使用instanceof操作符检测)都会返回true。
console.log(stu1 instanceof StuInfo ) //true
console.log(stu1 instanceof Object ) //true
function Foo() { }
var f1 = new Foo();
console.log(f1 instanceof Foo);//true
console.log(f1 instanceof Object);//true
//案例2
console.log(Object instanceof Function)//true
console.log(Object instanceof Object)//true
console.log(Function instanceof Object)//true
console.log(Function instanceof Function)//true
console.log(Object instanceof Foo)//false
console.log(Foo instanceof Function) //true
console.log(f1 instanceof Function)//false
console.log(Function.prototype.__proto__ === Object.prototype)//true
如果是基本类型,基本类型不是对象,所以在使用instanceof操作符时会始终返回false。
var A = function () {
}
A.prototype.n = 1
var b = new A();
//原型链在实例化的时候就已经确定好了
console.log(b);
A.prototype = {
n: 2,
m: 3
}
var c = new A()
console.log(c);
console.log(b.n, b.m, c.n, c.m)//1 undefined 2 3
var F = function () { };
Object.prototype.a = function () {
console.log('a')
};
Function.prototype.b = function () {
console.log('b')
};
var f = new F();
f.a()//a 可以找到Object.prototype
// f.b()//报错
F.a()//a
F.b()//b
for...in
用来遍历自身和原型链中可枚举的属性。
数组、函数都是对象,可以添加属性。同样,添加上属性之后还可以继续维持本来的功能。
数组是对象,数组对象中的索引(下标)本质上来说就是属性。length也是属性。
//遍历数组(不要用知道就好)
var a = [1,2,3,4]
for (var pro in a){ // var pro 可以自定义
console.log(pro); //遍历下标即属性
console.log(a[pro]);// 遍历元素的值
}
//遍历对象
function Person(){
this.name = 'pengjinli';
this.sex = 'nan';
this.age = 18;
}
Person.prototype.say = function(){
}
var p = new Person();
//不光对象本身的属性能够被遍历出来,在对象的原型链上的属性也会被遍历出来。
for (var pro in p) {
console.log(pro); //打印 name,sex,age,say
}
一些对象中有些属性是不可以遍历出来的,你可以理解为一般的时候用不到的属性
千万不要用for...in
遍历数组,虽然数组也是对象,但是数组的索引只是具有整数名称的枚举属性,for...in
不能保证遍历的顺序,而数组最重要的特征就是顺序(有序)。
可以判断对象中是否包含某个属性
语法:
var res = usrKey in 对象;
in右边必须是对象;
放回一个bool值,表示usrKey是否存在于对象中;
那怕属性值是undefinef,in检查都会返回true;
如果用delete删除了属性,in检查是会返回false
var obj = new Object();
obj.usrName = 'james';
obj.usrAge = 18;
obj.usrGender = true;
console.log('usrName' in obj); // true
console.log('usrHi' in obj); // false
前面的时候说this指代的是__当前正在实例的这个对象__,这种说法有些片面。this最终代表的是函数的执行者。
全局执行环境中的this。就是window。
console.log(this); //打印window
如果是__光秃秃的__函数调用this指向的是window(全局)。
function test(){
function test1(){
console.log(this);//window
console.log('@@@@');
}
test1();
}
test();
如果是通过对象的方法调用的,this指向这个对象。
var name="全局的属性"
// function fun(){
// console.log(this.name);
// }
var dog={
name:"旺财啊",
sex:"man",
age:20,
//say:fun
say:function(){
console.log(this.name)
}
}
var fun=dog.say
fun(); //函数调用this指向全局的name,相当于全局中的name
dog.say();//方法调用this指向调用它的对象,相当于dog.name
坑记住
var a = 1;
var foo = {
a: 2,
bar: function () {
console.log(this.a);
}
};
(false || foo.bar)();// 1 这里是个坑还讲不了现在
(foo.bar = foo.bar)(); // 1
每个函数对象都有call
和apply
两个方法,它的本质:设置函数体内的this对象
的值。
call(thisArg,arg1,arg2.....)
apply(thisArg,[argsArray])
括号前面1个是设置函数体内this的指向对象,后面是函数调用传入的实参
call调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可
apply调用的时候,参数必须是一个数组,然后再执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
如果第一个参数指定了null或者undefined则内部this指向window
call方法
var obj = {
name:'sex',
say:function(){
console.log(this);
console.log(this.name);
}
}
obj.say(); //函数调用内部打印出整个Obj对象 打印出sex
var obj1 = {
name:'hello',
sex:'nv'
}
obj.say.call(obj1);//强行的讲obj.say中的this设置为了obj1 所以函数调用内部打印出整个Obj1对象 打印出hello
apply方法
function Demo(name){
this.name = name;// 这里等于obj.name = yanhaijing;
}
var obj = {sex:'nan',age:18};
Demo.apply(obj,['yanhaijing']);//设置this指向0bj,
console.log(obj); //打印{sex:'nan',age:18,name:'yanhaijing'};
作用:
流程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E0Cr1ZeN-1610018155608)(D:/笔记案例/JS上课内容/7.11/day8-all/笔记、代码/4.对象_img/image-20200711163831171.png)]
基本类型判断使用typeof
typeof的返回值:
其他对象的类型判断
console.log(b instanceof Object);
console.log(b.constructor == Test);//true ,生成b对象的构造函数是Test
是否是同一个对象,用==
,判断的是是否是同一个地址。
JSON对象是ES中内置的对象,不用定义,直接就能用。
大写的JSON表示的是js中内置的对象,小写的json表示的是一种数据格式。
json是一种数据格式;我们以后大多数时候都是通过json数据格式进行前后端数据交互。
json本质上就是字符串,简称json串。
后台往前台传递数据时,要传json格式的数据。
可以表示三种类型的值。
简单的值:使用与JavaScript相同的语法,可以在JSON中表示字符串、数值、布尔值、null。
5
"Hello world"
null
false
对象:表示的是一组无序的键值对儿。
json中对象要求给属性加上双引号。
{
"name":"yanhaijing",
"age":29
}
数组:数组也是对象,表示一组有序的键值对儿。
[25,"hi",true]
[
{
"name":"张三",
"age":28
},
{
"name":"李四",
"age":30
}
]
{"success":false,"error_msg":"不是有效的话题id"}
JSON对象中有两个方法:
JSON.stringify(值)
,将JavaScript对象序列化为JSON字符串(用来向后多发送数据时)。
JSON.stringify输出的JSON字符串不包含任何的空格字符串和缩进。
序列化JavaScript对象时,所有的函数、原型中的成员、undefined属性都会被忽略。
var person = {
name: 'pengjinli',
age: 19,
sex: 'nan',
friends: [
'zs',
'ls',
'ww',
'ztc',
'lgd'
],
say: function () {
console.log('pengjinli 说: 闫海静真丑!');
},
money: undefined
}
console.log(JSON.stringify(person));
打印{"name":"pengjinli","age":19,"sex":"nan","friends":["zs","ls","ww","ztc","lgd"]}
JSON.parse(JSON字符串)
,将JSON字符串解析为原生的JavaScript值(用来得到后端的数据转换为我们使用的JavaScript数据)。
一旦传递给JSON.parse
的字符串不是有效的JSON就会报错。
console.log(JSON.parse('abc')); //报错
console.log(JSON.parse("abc")); //报错
console.log(JSON.parse('"abc"'));//这个是正确的。
ECMAScript还为数学计算提供了全局的内置对象,即Math对象。
将小数转换为整数,如果是整数则不改变。
Math.ceil()
,进一取整。
Math.floor()
,舍一取整。
Math.round()
,执行标准的四舍五入。
var num1 = 1.1;
var num2 = 1.9;
//math.ceil
console.log(Math.ceil(num1)); //2
console.log(Math.ceil(num2)); //2
//math.floor
console.log(Math.floor(num1)); //1
console.log(Math.floor(num2)); //1
//math.round
console.log(Math.round(num1)); //1
console.log(Math.round(num2)); //2
进行数学计算
Math.min()
,获得最小值。
Math.max()
,获得最大值。
Math.abs()
,求绝对值。
Math.pow(num,次方)
,进行幂运算。
Math.PI
,圆周率,这是一个属性。
var arr = [1,2,3,4,5,6,10];
console.log(Math.max.apply(null,arr)); //10 最大值
console.log(Math.min.apply(null,arr)); //1最小值
console.log(Math.max(...arr));
//绝对值
console.log(Math.abs(-1));
console.log(Math.abs(1));
//幂运算
console.log(Math.pow(4,3));//表示4的三次方
//圆周率
console.log(Math.PI);//这是个属性
Math.random()
,返回大于等于0小于1的一个随机数。
Math.floor(Math.random() * (可能的最大值 - 可能的最小值 + 1) + 可能的最小值)
案例:验证码
//验证码中的内容要有一个范围。 a-zA-Z0-9 4
var str = "abcdefghjklmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
var code = ''; //字符串拼接
for (var i = 1; i <= 4; i ++) { //4位数验证码
//随机出来的下标ind
var ind = Math.floor(Math.random() * (str.length - 1 - 0 + 1) + 0);
code += str[ind];
}
console.log(code);
Date是javascript中内置的函数(构造调用的),它用来处理日期和时间。
Date既然是函数就有两个角色(函数:可以运行的代码。对象:其中包含属性和方法)
是一个整数,用来进行计算。
从1970年1月1日0:0:0(计算机元年)~现在的毫秒数。
1秒等于1000毫秒,1毫秒等于1000微秒
Date.now()
,获得当前的时间戳。
当做构造函数来使用
格式:new Date();
得到当前的时间
new Date(年,月,日[,时[,分[,秒]]]);
getFullYear()
,获得4位的年份。getMonth()
,获得月份。 其中0表示一月,11表示12月。 //0~11getDate()
,获得月份中的天数。//1~31getDay()
,获得星期。0表示周日 16表示的是周一周六。getHours()
,获得小时。 //0 ~23getMinutes()
,获得分钟//0~59getSeconds()
,获得秒数。//0~59yyyy-mm-dd H:i:s
function formatDate(){
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
var nDate = date.getDate();
var day = date.getDay();
//获得对应的周几
switch(day){
case 0:
day = '周日';
break;
case 1:
day = '周一';
break;
case 2:
day = '周二';
break;
case 3:
day = '周三';
break;
case 4:
day = '周四';
break;
case 5:
day = '周五';
break;
case 6:
day = '周六';
break;
}
var hour = date.getHours();
var minutes = date.getMinutes();
var second = date.getSeconds();
var str = year + '-' + month + '-' + nDate + ' ('+ day +') ';
str += hour + ':' + minutes + ':' + second;//字符串太长拼接两次
console.log(str);
}
formatDate();
str是字符串但可以调用length
属性,返回字符串的长度。
var str="abc";
console.log(str.length); //3
在JavaScript中,提供了三个特殊的构造函数Number
、String
、Boolean
,函数可以使用new操作符来进行操作。 当你new 这些函数之后会生成对应类型的对象。
var str = new String('abc');
console.log(str); //变成string类型的对象
上面确实是一个对象,而且有__proto__
属性指向原型对象,原型对象中有大量的方法。
实际开发中不用,说这三个函数的原因是因为当你把number、boolean、string当做对象调用时时会调用对应的构造函数来生成一个对象。
var str= 'abc';
console.log(str.length);//是当做对象来调用的。
console.log(str);//还是普通值 abc
执行过程:
new String('abc')
创建了一个对象(字符串对象,包装对象);number、boolean、string都会经过上面的过程。
普通对象和包装对象的区别:主要是针对对象的生命周期。
charAt(),根据传入的位置取得其所在的字符。
var string = 'hello world!';
console.log(string.charAt(6));//()里的值也跟下标一样,从0开始,空格也算
console.log(string[1]);
charCodeAt(),根据传入的位置取得其所在的字符编码(unicode码)。(不常用)
var string = 'hello world!';
console.log(string.charCodeAt(1));// e 的 编码是多少。 打印101
String.fromCharCode(),根据传入的unicode码,转换为相应的字符。返回转化后的字符。
console.log(String.fromCharCode(101));// 打印 e
concat(),将一或多个字符串拼接起来返回拼接的到的新字符串。
var str1 = 'abc';
var str2 = 'efg';
var res = str1.concat(str2);
console.log(res); //abcefg
console.log(str1 + str2);//这也效果也一样
indexOf(searchValue[,offset]),从一个字符串中向后搜索给定的子字符串,然后返回子字符串的位置(如果没有找到该子字符串,则返回-1)。第二个参数可以指定从哪开始(默认从0位置开始查找);(常用)
var str = 'helloe';
console.log(str.indexOf('e'));// 返回1 ,从0开始找,两个e找前面的位置,没有则返回-1
//第二个参数用来设置查找的开始位置。默认0开始,返回位置
console.log(str.indexOf('o',4)); //返回4
lastIndexOf(),从一个字符串中向前搜索给定的子字符串,然后返回子字符串的位置(如果没有找到该子字符串,则返回-1)。
console.log(str.lastIndexOf('l')); //从后面开始找,返回位置还是顺序的
replace()方法,替换子字符串。(其他功能讲正则的时候说)将某个字符串置换成某个字符串。
var str = 'cat,bat,sat,fat';
var result = str.replace('at','ond');//将at替换成ond,只能替换一次(只有cat替换了),多次的话不能自动替换。
console.log(result);
slice(beginSlice[,endSlice]),提取一个字符串的一部分,返回一个新的字符串。beginSlice从0开始,endSlice可以省略,如果省略endSlice会一直提取到字符串末尾。(beginSlice是开启的位置,endSlice是结束的下标的----但结果不会包含结束的下标)—用的较多。(按下标取字符串)
var str = 'hello';
console.log(str.slice(1,2)); //e 从1开始到2截取但不包含2 (根据下标截取)
substr(start[,length]),返回一个字符串中从指定位置开始到指定字符数的字符。start,提取字符的位置,索引从0开始。length提取的字符数,length的最大值为字符串的长度减去1。省略length会从起始位置一直到字符串结束位置(按长度取字符串)
console.log(str.substr(3,2));//lo 从3开始截取2位 (根据长度截取)
split(),基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。(常用)
第一个参数如果不写的话会将整个字符串放入到结果数组中。
如果第一个参数是空串,则会将每个字符都作为数组的一个元素。
第二个参数用于指定分隔后的数组的大小,用来确保返回的数组不会超过该大小。
var colors = "red,blue,green,yellow";
console.log(colors.split()); //不写打印一个长度为1的数组 只有一个元素["red,blue,green,yellow"]
console.log(colors.split('')); //空串 打印每个字符都是一个数组元素
console.log(colors.split(',', 2)); //字符串按字符串里的逗号分隔,数组长度为2
toLowerCase(),将字符串转换为小写。
toUpperCase(),将字符串转换为大写。
var colors = "red,bLue,greEn,yellow";
console.log(colors.toLowerCase());
console.log(colors.toUpperCase());
valueOf(),返回对象的字符串、数值或布尔值表示。如果是包装类型返回包装类型的值,如果是对象则返回对象本身。
如果是包装对象取得是__proto__
原型对象中的valueOf(),返回的是基本值。如果是其他的对象类型,取得是Object构造函数原型对象中的valueOf(),返回的是对象本身。
该方法没有参数
返回值:如果是包装对象,返回的是包装对象中的基本值;如果不是包装对象类型,返回的是对象本身。
toString(),返回对象的字符串表示。
包装对象和非包装对象都可以使用这个方法,包装对象和非包装对象调用的也不是同一个toString()
方法。
是包装对象取得是__proto__
原型对象中的toString()
,如果是其他的对象类型,取得是该对象的__proto__
原型对象的toString()
该方法没有参数
返回值:如果是包装对象,返回的是包装对象中的基本值转换为字符串;如果不是包装对象类型,根据对象类型的不同返回值也不同。
对象分为包装对象和非包装对象。都可以使用valueOf和toString方法。s
[object Object]
字符串。var num = new Number(123);
//[[PrimitiveValue]]: 123 只有包装对象才有,表示的是基本值,如果不是基本对象 就没有基本值。
console.log(num.valueOf());//基本类型的valueOf拿的是基本值([[PrimitiveValue]]: 123)
var obj = {};
console.log(obj.valueOf());//不是包装对象,返回的就是对象本身。
//toString(),返回对象的字符串表示。
var num = new Number(123);
//如果是包装对象,返回的是包装对象中的基本值转换为字符串。 [[PrimitiveValue]]: 123
console.log(num.toString());
var obj = {};
//普通的对象返回的是[object Object]
console.log(obj.toString());
var arr = [1,2,3];
//如果是数组返回的是去掉中括号之后的列表。
console.log(arr.toString()); //1,2,3
function test(){
}
//函数返回的是函数的本身转换为字符串。
console.log(test.toString());
includes(string,n),返回布尔值,表示是否找到了参数字符串。
var s = 'hello world!';
console.log(s.includes('o')); // true
console.log(s.includes('w',4)); //true ,第二个参数是从下标位置4开始找
startsWith(string,n),返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith(string,n),返回布尔值,表示参数字符串是否在源字符串的尾部。
repeat(N),返回一个新字符串,表示将原字符串重复N次。返回新字符串。
var str = '闫海静真英俊!';
console.log(str.repeat(100));
padStart(length,str),如果没有到达length的长度使用str在头部进行填充。(可以用于前面补0的操作)
如果str与原字符串长度之和超过了指定的最小长度,会截去超出的位数。
如果原来字符串的长度等于或大于指定的length,原样返回。
如果第二个参数省略,会用空格来进行补全。
padEnd(length,str),如果没有到达length的长度使用str在尾部进行填充。
var x = 'x';
var newX1 = x.padStart(5,'ab');//ababx
console.log(newX1);
var x = 'x';
var nx1 = x.padEnd(5,'ab');
console.log(nx1);//xabab;
console.log(x.padEnd(4,'ab'));//xaba
//字符串是基本类型值,一般的方法只能返回新值,而不能改变字符串
let message = " hello world ";
log(message);
log(message.trim());
log(message.trimStart());
log(message.trimEnd());
math补充
//指数运算符 求一个数组的n次方
{
//es5
console.log(Math.pow(2, 10));
console.log(Math.pow(32, 5));
//es6
console.log(3 ** 3); //3的3次方
console.log(2 ** 10); //2的10次方
// 计算顺序 先计算右边 在依次计算
console.log(2 ** 3 ** 3);
}
{
//去掉小数部分
console.log(Math.trunc(3.12)) //3
//判断数字 正--》1 负--》-1 0--》0 NaN--》NaN
console.log(Math.sign(3.12)) //1
console.log(Math.sign(-3.12)) //-1
console.log(Math.sign(0)) //0
console.log(Math.sign(NaN)) //NaN
//平方根
console.log(Math.sqrt(4)) //2
//立方根
console.log(Math.cbrt(27)) //3
//求所有参数的平方和的平方根 3平方+4平方=5平方 5是3和4的平方和的平方根
console.log(Math.hypot(3, 4)) //5
}
既然以Array.prototype开头的那就说明 是给Array的实例对象使用的。
Array.prototype.push(),接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
var arr = ['red','blue','green'];
arr.push('black',"yellow"); //末尾加任意个数
console.log(arr);
Array.prototype.pop(),从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。
var arr = ['red','blue','green'];
console.log(arr.pop()); //返回green
console.log(arr); // red,blue
Array.prototype.unshift(),在数组前端添加任意个数选项并返回新数组的长度。
var arr = ['red','blue','green'];
console.log(arr.unshift('pink','hotpink')); //返回新数组长度5
console.log(arr); //p,h,r,b,g
Array.prototype.shift(),移除数组中的第一个项并返回该项,同时将数组长度减1。
var arr = ['red','blue','green'];
console.log(arr.shift()); //返回red
console.log(arr); // blue,green
Array.prototype.splice(),向数组的中部插入项。
整体格式:arr.splice(起始项,删除的个数,要插入的项目1,要插入的项目2......)
删除,可以删除任意数量的项,只需指定2个参数:要删除的第一项的位置和要删除的项数,返回删除的项组成的数组,原数组受到更改。
替换,可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需要指定3个参数:起始位置、要删除的项数、要插入的任意数量的项(插入的项数不必与删除的项数相等)。
插入,可以向指定位置插入任意数量的项,只需要提供3个参数:起始位置、0(要删除的项数)、要插入的项目(要插入的项目可以传入任意多个项)。
//删除
var colors = ['red','green','blue','yellow'];
var delColors = colors.splice(0,2); //从0下标开始删除2项
console.log(delColors); //返回删除的项组成的数组 [red,green]
console.log(colors); // 原数组变成[blue,yellow]
//替换
var colors = ['red','green','blue','yellow'];
var replaceColors = colors.splice(1,1,'pink','black'); //可以删除1个插入2个
console.log(replaceColors); //返回替换的项green
console.log(colors); // r,p,b,b,y
//插入
var colors = ['red','green','blue','yellow'];
colors.splice(1,0,'pink','white');
console.log(colors); //red pink white green blue yellow
Array.prototype.concat(value1,…,valuen),基于当前数组中的所有项创建一个新数组。这个方法会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾。最后返回新构建的数组。(合并数组)
如果传递给concat()方法的是一个或多个数组,则该方法会将这些数组中的每一项都添加到数组中。
没有给concat()方法传递参数的情况下,它只是复制当前数组并返回副本。返回的数组是新数组
var arr1 = [1,2,3,4];
var arr2 = [5,6,7,8];
var res = arr1.concat(arr2,[9,10]);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var res1 = arr1.concat(arr2,11);// [1, 2, 3, 4, 5, 6, 7, 8, 11]
console.log(res1);
Array.prototype.join(),使用指定的字符串拼接数组中的每个元素,组成一个字符串。
如果参数是空字符串(""
),则所有元素之间都没有任何字符。
var arr = ['red','green','blue'];
console.log(arr.join());//如果不写参数使用,号作为分隔符
console.log(arr.join('.'));
Array.prototype.reverse(),反转数组项的顺序,返回反转后的原数组。
var arr = ['red','green','blue'];
console.log(arr.reverse()); //blue,green,red
var arr1 = arr.reverse();//改变的原数组。
console.log(arr== arr1); //true
console.log(arr); //还是原来的数组
Array.prototype.slice(),基于当前数组中的一个或多个项创建一个新数组(该方法不会影响原始数组)。
只有一个参数的时候该方法返回从该参数指定位置到当前数组末尾的所有项组成的数组。
如果有两个参数,该方法返回的是起始位置和结束位置之间的项(但不包括结束位置的项)
var colors = ['red','green','blue','yellow','pink','white','black'];
var res1 = colors.slice(1); // ["green", "blue", "yellow", "pink", "white", "black"]
var res1 = colors.slice(1,4); //green blue yellow
var res1 = colors.slice(); //
console.log(res1);
Array.prototype.sort([sortFunc]),按升序排列数组项(最小的值位于最前面,最大的值排在最后面)。排序后改变原数组。
不传递参数的情况下,sort()方法会调用每个数组项的toString(),然后比较的是字符串。
sortFunc(这个参数),接收一个比较函数作为参数,这个函数接收两个参数(比较的两个数),如果第一个参数应该位于第二个参数之前则需要返回一个负数,如果相等则需要返回一个0,如果第一个参数应该在第二个参数后面则需要返回一个正数。
//这个函数返回负数,第一个数在前面。返回正数第一个数在后面。
//第一个-第二个数 = 负数 第一个数就在前面。
//第一个数-第二个数= 正数 第一个数就在后面。
升序:方法一
var values = [0,5,1,15,10];//0 1 5 10 15
var res = values.sort(function(value1,value2){
if (value1 < value2) {//0 5 //第一个数小于第二个数返回负数,返回负数 第一个数就在第二个数前面了。
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
});
console.log(res);
升序:方法二
var values = [0,5,1,15,10];//0 1 5 10 15
var res = values.sort(function(value1,value2){
return value1 - value2;
});
console.log(res);
降序:
var values = [0,5,1,15,10];//0 1 5 10 15
var res = values.sort(function(value1,value2){
return value2 - value1; //参数后面可以接属性,然后按属性排
});
console.log(res);
Array.prototype.toString(),返回数组的字符串表示。
var a = [1,2,3];
console.log(a.toString());
Array.prototype.indexOf(),查找指定的值并返回要查找的项在数组中的位置。没有找到返回-1。比较使用全等操作符。
var colors = ['red','green','blue'];
//返回的是下标。 没有找到返回-1
console.log(colors.indexOf('red',1)); //第二个参数从哪开始找
Array.prototype.forEach(),对数组中的每一项运行给定函数,这个方法没有返回值(返回值是undefiend
)。
forEach和for都能遍历数组不同点:
var colors = ['red','green','blue'];
colors.forEach(function(value,index){ value是值 index是下标
//函数里面写的是具体的功能。
console.log(value,'-------',index);
});
Array.prototype.map(),对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
var colors = ['red','green','blue'];
var res = colors.map(function(val1,index){
return val1 + index;
});
console.log(res); //["red0", "green1", "blue2"]
Array.prototype.filter(),对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
var colors = ['red','green','blue'];
var res = colors.filter(function(val,inde){
if (val == 'green') {
return false;
}
return true;
});
console.log(res); //red blue
Array.prototype.every(),对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true
var a = [5,6,7,8];
var res = a.every(function(val,inde){
if (val >= 6){
return true;
}
return false;
});
console.log(res); //false 全部true则返回true
Array.prototype.some(),对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
var a = [5,6,7,8];
var res = a.some(function(val,inde){
if (val >= 6){
return true;
}
return false;
});
console.log(res); //true 有一个true就返回true
Array.isArray(value),确定value是否是数组,如果是数组返回true否则返回false。
var b = ["red","yellow"];
console.log(Array.isArray(b)); //true
Array.prototype.reduce(function(previousValue, currentValue){}) : 遍历累加返回一个最终结果
var arr = [1, 2, 3, 4, 5];
//如果reduce方法只有第一个函数参数的话,那么第一次执行的下标是从1开始的,因为上一次返回值没有,默认是arr[0],
//当前的值是arr[1],这样是少了一轮遍历
//如果reduce方法拥有第二个参数,则这个参数就是初始进入的prevItemf,这样就是给累加一个初始值
var value = arr.reduce(function (prevItem, nowItem, index) {
// prevItem就是上次函数的返回值, nowItem就是当前遍历的数组的值
return prevItem + nowItem;
}, 0)
console.log(value)
slice()方法并没有改变原来的数组,返回一个新的数组
splice()方法他改变了原来的数组
/**
*slice()方法接收两个参数,一个是起始位置,一个是结束位置
* 可以只传一个起始位置,就会返回从起始位置到结尾的所有项
* 他会返回起始位置和结束位置之间的项,包含起始位置,但是不包含结束位置
*/
var arr = [1,2,3,4,5,6,7,8,9,0];
console.log(arr.slice(1))//[2, 3, 4, 5, 6, 7, 8, 9, 0]
console.log(arr.slice(1,4))//[2, 3, 4]
console.log(arr)// [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
/**
*slice()方法并没有改变原来的数组,返回一个新的数组
* slice(),两个参数还可以用负数哟
* 用负数的话就是 数组的长度 + 负数 来确定位置从哪里开始,从哪里结束
*/
console.log(arr.slice(-4,-2))//[7, 8] .....这个就是从 10-4 开始 10-2结束
console.log(arr.slice(-2,-4))//[] ..... 这个就是从 10-2 开始 10-4 结束
/**
* splice()方法应该是最强大的数组方法了
* 主要用途是向数组的中部插入项,参数有三个,一个是起始位置,第二个是删除,插入的项数,第三个是要插入的项
*/
var arr1 = [1,2,3,4,5,6];//删除任意数量的项
console.log(arr1.splice(0,1))//[1] 返回了要删除的项
console.log(arr1)//[2, 3, 4, 5, 6] 他改变了原来的数组
var arr2 = [1,2,3,4,5,6];//插入任意的数量项
console.log(arr2.splice(6,0,7,8,9))//[]
console.log(arr2)//[1, 2, 3, 4, 5, 6, 7, 8, 9]
var arr3 = [1,2,3,4,5,6];//向指定位置插入任意数量的项,并删掉任意数量的项
console.log(arr3.splice(1,2,7,8))//[2, 3]
console.log(arr3)//[1, 7, 8, 4, 5, 6]
Array.from方法用于将类数组对象转为真正的数组:类数组对象(array-like object,有length属性和索引元素)和可遍历对象。
function test(){
var res = Array.from(arguments);//将类数转换为数组 那就可以使用数组的相关方法。
console.log(res);
}
test();
Array.of用于将一组值转换为数组。返回新数组。
var arr = Array.of(1,2,3,4,5);
console.log(arr);
var a = new Array(4);
console.log(a); //长度为4,全是undefined
弥补了Array的不足。 如果只传递一个数值的时候 Array是有差异的。 但是使用Array.of()就不会有差异了。
var b = Array.of(4); //只有一个元素4的数组
console.log(b);
Array.prototype.includes()方法返回一个布尔值,表示某个数组是否包含给定的值。
该方法主要用来替代indexOf()
,因为indexOf()
是全等运算
,而NaN
和NaN
也不相等。
var a = [1,2,3,4,NaN];
var res = a.includes(5);
console.log(res); //false
对象转成数组
**Object.keys()**
方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
简单说就是保留对象的key组成数组
对象转成数组
**Object.values()**
方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in
循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
简单说就是保留对象的values组成的数组
检查对象上有没有某个属性,只检查对象本身,不检查原型
object.hasOwnProperty(proName)
其中参数object是必选项。一个对象的实例。
proName是必选项。一个属性名称的字符串值。
如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。