JavaScript入门学习第二周

796 阅读14分钟

一、数据类型转换

页面上的一切都是字符串类型,有可能做某些操作(+运算)时不适合,需要先转换,再进行操作。

1、强制转换,类型

①、转字符串

xx.toString();

undefined和null不能使用,因为不是对象,不能调用任何属性和方法;

String();

万能的,但是完全等效隐式转换,还不如+“”。

②、转数字

parsInt/Float(str/num);

  • 专门用于字符串转为整数的。
  • 执行原理:从左向右依次读取每个字符,碰到非数字字符就停止,parsInt不认识小数点,parsFloat认识小数点,一来就碰到了不认识的,则为NaN。

③、转布尔

Boolean(xx);

  • 万能的,任何人都可以转为一个布尔值;
  • 特殊:6个值转布尔后为false:0,"",undefined,null,NaN,false,其余的都为true。大多用于分支判断或循环中,会带此隐式转换。

2、隐式转换:多半都在运算符之中

二、运算符和表达式

1、算术运算:+ - * / %

①、隐式转换

默认,转为数字,在运算

②、特殊

  1. +运算,只要碰上一个字符串,则变为拼接
  2. / % - *,纯数字组成的字符串,也可以转为数字,但是非纯数字的字符串转为NaN,NaN参与任何算术运算结果仍为NaN。

2、比较运算

< > >= <= == != === !==

①、结果

布尔值

②、隐式转换

默认

左右两边都会悄悄的转为数字,再比较

特殊

  1. 如果左右【两边】参与比较的都是字符串,则是按位PK每个字符的十六进制的unicode号(十进制ascii码);
  2. NaN参与任何比较运算结果都为false,带了一个问题,没有办法使用普通的比较运算判断一个xx是不是NaN,解决:!isNaN(xx); true->有效数字 false->NaN;
  3. undefined==null,==区分不开undefined和null,全等:===,要求值和数据类型都要相同,换句话说,就是不再带有隐式转换,!==,不带隐式转换的不等比较。

3、逻辑运算符

①、隐式转换

悄悄的都变为布尔,然后综合比较得出结论

  • &&:全部的条件都为true,结果才为true,只要有一个为false,结果就为false;
  • ||:全部的条件都为false,结果才为false,只要有一个为true,结果就为true;
  • !:颠倒布尔值。

②、特殊用法

  • 短路逻辑:只要前一个条件已经可以得出最后结论,则后续条件不再执行!
  1. &&短路:如果前一个条件为true,后一个操作才执行如果前一个条件为false,后一个操作不执行简化了简单的分支:if(条件){操作}语法:条件&&(操作);举例:曾经:if(total>=500){total*=0.8};现在:total>=500&&(total*=0.8);
  2. 特殊:1简单的-> 操作只能有一句话!建议:能用短路分支绝对不用if分支;
  3. ||短路:如果前一个条件为true,不需要执行后一个如果前一个条件为false,需要执行后一个使用场景:两个值二选一 - 后期做浏览器兼容性(老IE)例:e=e||window.event;

4、位运算

  • 左移:m<<n,读作m左移了n位,相当于m*2的n次方;
  • 右移:m>>n,读作m右移了n位,相当于m/2的n次方;
  • 缺点:底数永远只能是2。

5、赋值运算

一句话执行了两个操作,先运算,再赋值

①、语法

+= -= *= /= %= ++ --

②、何时使用

只要取出变量中的值,在做计算,之后还要在保存回去时,就要试用赋值运算 i=i+1;//比较low的写法,推荐:i+=1 或者 i++;

③、递增

i++; 每次只能+1

④、累加

i+=n; 每次想加几,随便你

⑤、++ 分为 ++i 和 i++

  • 单独使用时,没有参与别的表达式,放前放后都一样
  • 如果参与了别的表达式:变量中的值其实都会+1
  1. ++i,返回的是递增后的【新值】
  2. i++,返回的是递增前的【旧值】

6、三目运算

①、作用

简化分支:if(){}else{}if(){}else if()else{};

②、语法

条件1?操作1:条件2?操作2:默认操作;

③、特殊

  1. 只能简化简单的分支 - 三目操作也只能有一句话
  2. 默认操作不能省略 - 哪怕条件都不满足,至少还要做一件事

7、舍入误差

①、语法

parseFloat(num.toFixed(n))

②、原因

电脑很笨,计算能力某些情况很差,计算不清

三、自定义Function

函数含义

需要先定义好,可以反复使用的一个代码段

何时使用

  1. 不希望打开页面立刻执行
  2. 以后可以反复使用
  3. 希望绑定在页面元素之上

1、创建并且调用

①、创建

1、声明方式创建函数

function 函数名(形参,...){
函数体;
return 返回值/结果;
}

2、直接量方式创建函数 - 无用

var 函数名=function(形参,...){
函数体;
return 返回值/结果;
}

②、调用

var 接住返回的结果=函数名(实参,...); 其实return的本意退出函数,但是如果return后跟着一个数据,顺便将数据返回到函数作用域的外部,但return只负责返回,不负责保存就算省略return,默认也会return undefined;体需不要得到函数的结果,看你自己。

2、作用域

①、全局作用域

全局变量 和 全局函数,在页面的任何一个位置都可以使用

②、函数/局部作用域

局部变量 和 局部函数,在当前函数调用时内部可用

变量的使用规则

优先使用自己的,自己没有找全局,全局没有报错特殊:

缺点
  1. 千万不要再函数中对着未声明的变量直接赋值会造成全局污染
  2. 局部可以用全局的,但是全局不能用局部的 - 解决:return

3、声明提前

  1. 在程序正式执行之前将var声明的变量(轻)和function声明的函数(重)都会悄悄集中定义在当前作用域的顶部但是赋值留在原地
  2. 声明方式创建的函数会完整的提前(第一种方式)直接量方式创建的函数不会完整提前,只有变量部分会提前(第二种方式)

声明时遵守以下原则

  1. 变量名和函数名尽量的不要重复
  2. 先创建后使用
  3. 如果笔试时需要先使用后创建,多半都是在考你声明提前

4、按值传递

两个变量之间进行赋值

  • 如果传递的是原始类型的值:修改一个变量,另一个变量是不会受到影响的,其实是复制了一个副本给对方
  • 如果传递的是引用类型的对象:修改一个变量,另一个变量是会受到影响的,因为大家操作其实是同一个地址值

四、预定义的全局函数

前辈们提前创建好的方法,我们可以直接使用,在任何位置都可以使用

1、编码和解码

  • 编码:var code=encodeURIComponent("原文");
  • 解码:var 原文=decodeURIComponent(code);
  • 其实这个东西在某次浏览器更新后,就当场淘汰了,浏览器自带此功能

2、isFinite(num)

  • 判断num是不是无穷大,true:有效数字 false:无穷大
  • 结果false:NaN,Infinity,分母为0

3、常用的

  • parseInt/Float、isNaN、eval
  • eval(str);:计算字符串,简单来说就是去字符串的“”。

五、分支结构:if分支 switch分支

1、语法

switch(变量/表达式){
		case1:
		操作1;
		case2:
		操作2;
		default:
		默认操作;
	}

2、特殊

  1. case的比较不带隐式转换
  2. 默认只要一个case满足后,会将后面所有的操作全部做完,解决:条件后加break;

③、建议

  • 每一个case的操作后都跟上一个break,有的地方也可以不加break:
  • 最后的一个操作default可以省略break;
  • 如果中间多个条件,做的操作是一样的,也不需要
  • default可以省略,如果条件都不满足的情况,什么事都不会做

②、if和Switch的区别

switch...case...

  • 缺点:必须要知道准备的结果才能使用,不能做范围判断
  • 优点:执行效率相对较高

if...else

  • 缺点:执行效率相对较低
  • 优点:可以是范围判断

六、循环结构

①、1、while循环

语法

while(循环条件){循环体};

2、do...while...循环

语法

do{循环体}while(循环条件);

while 和 do...while的区别

只看第一次:如果第一次大家都满足,两者没有区别,如果第一次不满足,while一次都不执行,dowhile至少会执行一次

3、for循环

for(循环变量;循环条件;变量的变化){
		循环体;
	 };

4、流程控制语句

退出循环:break;退出整个循环,continue;退出本次循环,根据需求进行分析使用哪一个。

七、数组的基础

1、基本概念

  • 概念:在一个内存(变量)中保存了多个数据的一个集合结构
  • 何时使用:只要存储的多个相关的数据,都要用数组集中保存;
  • 为什么使用:一个好的数据结构,可以极大的提升我们程序员的开发效率

2、数组的创建

①、直接量

var arr=[值1,...];

②、构造函数

var arr=new Array(值1,...);

  • 缺点:var arr=new Array(num);会创建一个长度num的空数组

3、访问数组

①、访问

数组名[下标]; 获取当前元素

②、添加/修改

数组名[下标]=新值;

③、特殊

  • 读取元素,下标越界,返回undefined
  • 添加元素,下标越界,下标不在连续,导致变成一个稀疏数组

4、数组的三大不限制

  1. 不限制长度
  2. 不限制类型
  3. 不限制下标越界

5、数组唯一的属性:数组名.length:获取当此数组的长度

三个固定套路

  1. 末尾添加:arr[arr.length]=新值;
  2. 获取倒数第n个:arr[arr.length-n];
  3. 删除倒数n个:arr.length-=n;

6、遍历数组:对数组中每个元素执行相同相似的操作

for(var i=0;i<arr.length;i++){
	arr[i];//当前次元素
	};

7、释放一个引用类型

先注意这个引用类型的数据有几个变量引用着,折几个变量都要释放后才会真正释放

8、关联(hash)数组

  • 关联(hash)数组:下标是可以自定义的
  • 关联(hash)数组使用的原因:索引数组的下标无具体的意义,不便于查找

①、创建关联(hash)数组

  1. 创建空数组:var arr=[];
  2. 为数组添加下标并且添加元素:arr["自定义下标"]=新值;

②、访问关联(hash)数组

arr["自定义下标"];

③、强调

  1. hash数组length永远失效,永远为0!
  2. 遍历hash数组,不能使用for循环,必须使用for in循环 - 专门用于遍历数组的
for(var i in arr){
   i;
}
  1. for in虽然不能定义从哪里开始,到哪里结束,专门用于遍历数组的,既可以遍历索引数组也可以遍历hash数组,索引数组依然使用for,hash数组再用for in。

④、hash数组的原理

hash算法

将字符串,计算出一个尽量不重复的数字(地址值)字符串内容相同,则计算出来的数字也一定是相同的

添加元素

将自定义下标交给hash算法,得到一个数字(地址值),直接将你要保存的数据放到这个地址之中

获取元素

将指定的自定义下标交给hash算法,得到一个和当初保存时一样的数字(地址值),通过地址就找到当前保存的数据

js里面的一切东西都是对象,除了undefined和null,一切对象的底层都是hash数组

二级联动

  1. select的专属事件:onchange:状态改变事件
  2. select具有一个专属属性:select.selectedIndex;//直接获取到当前选中项的下标
  3. 必须用到二维数组(再次细分)

八、数组的API

前辈们提前定义好的,我们可以直接使用的,以下函数只有数组可用

以下API不会修改原数组,只会返回一个新数组

1、数组转字符串

①、语法

var str=arr.join("自定义连接符");

②、固定套路

  • 将数组里面的内容拼接为一句话/单词,无缝拼接:var str=arr.join("");
  • 将数组拼接为DOM页面元素
  1. 转为字符串,并且拼接好标签var str="<开始>"+arr.join("</结束><开始>")+"</结束>";
  2. 渲染到DOM树上elem.innerHTML=str;

2、数组拼接:添加元素的新方式

把你传入的实参全部拼接到数组的末尾

①、语法

var newArr=arr.concat(新值1,...)

特殊

concat支持传入数组参数,会将你传入的数组打散为单个元素后在拼接

3、截取子数组

根据你传入的开始下标截取到结尾下标

①、语法

var subArr=arr.slice(starti,endi+1);

③、特殊

  1. 含头不含尾;
  2. endi可以省略不写,会从starti位置一直截取到末尾;
  3. 两个实参都可以省略,从头截到尾,深拷贝,和以前的按值传递(浅拷贝)不同,一个修改不会影响到另一个;
  4. 支持负数参数,-1代表倒数第一个。

以下API都会修改原数组

1、删除、插入、替换

①、删除

语法

var dels=arr.splice(starti,n);//n代表删除的个数

特殊

其实splice也有返回值,返回的是你删除的元素组成的一个新数组

②、插入

语法

arr.splice(starti,0,值1,...);

特殊

  1. 原starti位置的元素以及后续元素都会向后移动
  2. 千万不要插入一个数组,会导致我们的数组一些是一维,一些是二维,遍历时非常的难受

③、替换

语法

var dels=arr.splice(starti,n,值1,...);//删除的元素个数不必和插入的元素个数相同

2、翻转数组

语法

arr.reverse();

3、排序

①、冒泡排序

for(var j=1;j<arr.length;j++){
	for(var i=0;i<arr.length-j;i++){
            if(arr[i]>arr[i+1]){
		var middle=arr[i];
		arr[i]=arr[i+1];
		arr[i+1]=middle;
	}
    }
}

②、排序的API

语法

arr.sort();

升序排列

语法
arr.sort(function(a,b){
	return a-b;  //sort方法正好可以根据你返回的正数/负数/0来进行排序
})

降序排列

语法
arr.sort(function(a,b){
	return b-a;  //sort方法正好可以根据你返回的正数/负数/0来进行排序
})

强调:只要以后页面中有排序功能,他的底层一定是一个数组,因为只有数组具有排序的方法。

4、栈和队列:添加元素和删除元素的新方法

①、栈

其实就是数组,只不过是一端封闭,只能从另一端进出的数组

何时使用

优先使用最新的数据 ####③、如何使用

开头进语法
arr.unshift(新值,...);
//添加元素的新方式,向前添加,缺陷:导致其余元素的下标发生改变
开头出语法
var first=arr.shift();
//删除元素的新方式,向前删除,缺陷:导致其余元素的下标发生改变
结尾进语法
arr.push(新值,...);
//添加元素的新方式,向后添加,完全等效于arr[arr.length]或者arr.concat
结尾出语法
var last=arr.pop();//删除元素的新方式,向后删除

②、队列

其实就是数组,只不过是一端进,另一端出

何时使用

根据先来后到的顺序

  • 开头进:arr.unshift(新值,...);
  • 结尾出:var last=arr.pop();
  • 结尾进:arr.push(新值,...);
  • 开头出:var first=arr.shift();

九、二维数组

数组的元素,又引用着另一个数组

1、何时使用

在一个数组内,希望再次细分每个分类

2、创建

var arr=[		[],
		[],
		[]
	];

3、访问

arr[行下标][列下表];

4、特殊

  • 列下标越界,返回undefined
  • 行下标越界,报错,因为undefined不能使用[]

5、遍历二维数组

必然两层循环:外层循环控制行,内层循环控制列

for(var r=0;r<arr.length;r++){
	for(var c=0;c<arr[r].length;c++){
	console.log(arr[r][c])
	}
}

周期定时器:每过一段时间就会执行一次

  • 开启
timer=setInterval(function(){
		操作;
	      },间隔毫秒数)
  • 停止:clearInterval(timer)
  • 鼠标移入onmouseenter和移出onmouseleave

十、String的概念

多个字符组成的只读字符数组(只读:所有的字符串的API都不会修改原字符串,只会返回的新的结果)

1、和数组相同的地方

  1. 字符串中的个数:str.length
  2. 获取字符串中某个字符:str[i]
  3. 遍历字符串
  4. 所有数组不修改原数组的API,字符串也可以使用(concat、slice)

2、和数组不同的地方

所有的数组直接修改原数组的API,字符串都不可以使用,比如排序只有数组可以使用,但是字符串也有很多很多属于自己的API

3、引用/对象类型:11个

tring、Number、Boolean:包装类型 Array、Function、Date(日期)、Math(数学)、RegExp(正则:验证)、Error(错误)、Object(面向对象开发方式)、Global(全局对象)。

①、包装类型

专门将原始类型的值封装为一个引用类型的对象;只要试图用原始类型的变量调用属性或者方法时,自动包装;方法调用完毕后,自动释放包装类型,并且返回数据(又变回了原始类型)。null和undefined没有包装类型。

十一、String API

1、转义字符:\

①、作用

  1. 将字符串中和程序冲突的字符转为原文
  • "\ "" 和'\ ''
  1. 包含特殊功能的符号
  • 换行:\n
  • 制表符(大空格tab):\t
  1. 输出unicode编码的字符
  • \uXXXX:第一个汉字:\u4e00 ascii:19968
  • 最后一个汉字:\u9fa5 ascii:40869

2、大小写转换

将字符串中的每个英文字母统一的转为大写小写

①、何时使用

只要程序不区分大小写,就要先统一转为大写 或 小写,再比较(验证码)

①、如何使用

  1. 大写语法:var upper=str.toUpperCase();
  2. 小写语法:var lower=str.toLowerCase();

3、获取字符串中指定位置的字符

语法:var newStr=str.charAt(i);===str[i];

4、获取字符串中指定位置的字符的ASCII码

语法:var ascii=str.charCodeAt(i);

5、根据ascii码转回原文:

语法:var 原文=String.fromCharCode(ascii);

6、检索字符串:检查索引:获取关键字下标

  • 语法:var i=str/arr.indexOf("关键字",starti);
  • 从starti位置开始,查找右侧第一个关键字的位置starti可以省略,默认从0位置开始查找;
  • 返回值:找到,返回的是第一个关键字的第一个字符的下标;没找到,返回-1,我们不关心下标为多少,只关心为不为-1;
  • 作用:判断有没有;
  • 强调:数组也能用此方法,后期才添加上的。

7、截取字符串:

语法

var subStr=*str/arr.slice(starti,endi+1);
//和数组用法一样,支持负数参数,-n代表倒数第n个
 str.substring(starti,endi+1);
 //用法几乎和slice相同,不支持负数参数
str.substr(starti,n);
//支持负数参数,n代表截取的个数,不必考虑含头不含尾

8、拼接字符串

语法:var newStr=str.concat(str1,...);还不如+运算

9、替换字符串

语法:var newStr=str.replace("关键字"/正则,"新内容");

10、切割/分割字符串:

①、作用

将字符串转为数组

②、语法

var arr=str.split("自定义切割符");

③、特殊

  • 切割后,切割符就不存在
  • 切割符"",切散每一个字符

JS创建空元素:

①、语法

var elem=document.createElement("标签名");

②、为此空标签添加必要的属性或事件

elem.innerHTML="内容";
elem.属性名="属性值";
elem.on事件名=function(){};

③、渲染到DOM树上

父元素.appendChild(新元素)