day6
数据类型的转换
转字符串:
(1)x.to string //不能是undefined和null (2)string(x) 万能的,任何人都能转为字符串;
转数字
parseInt/Float()
专门为字符串转数字准备的, parseInt/Float从左往右依次读取,碰到非数字字符就停止,如果一来就不认识,则为NaN,parseInt不认识小数点,parseFloat只认识第一位小数点。
Number()
万能的任何人都能转为数字,相当于隐式转化
转布尔
Boolean()//万能的,任何人都能转为布尔; 除了:0,“ ”,undefined,null,NaN,false;
function
function函数,也叫作方法,是需要预定义,以后会反复使用的代码段,
声明函数
function 函数名(形参){ 函数体; return返回值; }
直接量函数
var函数名=function(){ 函数体; return返回值; }
return
return :退出的意思; 只不过return后面跟了一个数据,会顺便将其返回到全局作用中,但只负责返回,不负责保存,所以在调用函数式,需要一个变量把他接住。 调用函数 var result=函数名(实参列表);
作用域
全局作用域:
全局变量和全局函数在任何地方都可以使用
函数/局部作用域:
局部变量,和局部函数,在函数调用时内部可用; 内部使用规则:优先使用局部,局部没有找全局,全局没有就报错。
特殊
1.千万不要对着未声明的变量直接赋值,会导致全局污染。 2.局部的东西全局不能用,解决方法:return; 3.哪怕没有写return,其实最后也有一个return,但是返回的是undefined 4.return一般只会出现在函数的最后,而且只能有一个;
声明提前
在程序正式执行之前,会将var声明的变量和function声明的函数集中提前到当前作用域顶端,变量比函数名更轻,但是赋值留在原地。
按值传递
两个变量之间赋值,分两种情况:如果传递的是原始值:修改一个变量,另一个变量是不会受到影响的; 如果传递的是引用类型,修改一个变量,另一个变量会受到影响;
编码和解码
编码:var 不认识=encodeURIComponent(); 解码: var 原文=dencodeURIComponent("不认识");
分支结构
switch....case...语法;
switch(变量/表达式){ case值1:操作1;case值2:操作2; }
特殊
1.不具备隐式转换 2.默认只要一个case满足,就会将后面所有操作全部做一次,建议每一个case后面跟一个break; 如果中间连续几个操作相同,可以省略掉中间部分; 面试题
if和switch
Switch 缺点:必须知道后面的结果才能使用,不能做范围判断;
优点:执行率相对较高。
If :优点:可以范围判断
缺点:执行率较慢;
循环结构
1.var 循环变量= 几; while(循环变量){ 操作; 变量变化; } 2.do...while var 循环变量= 几; do{ 操作; 变量变化; }while(循环条件)
3.for(var 循环变量= 几;循环条件;变量变化;){操作;} 退出循环语句: break 退出整个循环 countinue 退出本次循环
数组的API
1.arr转为字符串 语法:var str=arr.join("自定义连接符");
2.拼接数组: var newArr=arr.concat(值1,arr)
3.截取数组: var newArr=arr.slicat(starti, end) 此方法不修改原来的数组,只会返回一个新数组,含头不含尾,第二参数可以省略不写,截取到末尾,如果两个都不写,表示从头截取到尾。
4.删插替:
arr.splice(starti,n,新值1...)
n代表删除的个数
5.反转数组:arr.reverse();
6.排序:arr.sort(); 默认悄悄转为字符串,按位pk,按照字符串排列 按照数字升序排列: arr.sort(function(a.b){ return a-b; })
7.栈和队列 栈:其实就是一个数组,只不过要求只能从一端进出,另一端是封闭的, 前进:arr.unshift 添加元素的新方式,不建议添加数组; 前出: var first=arr.shift 删除元素的新方式,一次只能删除一个,而且是第一个; 后进:arr.push(新元素。。) 后出:var last=arr.pop()
String
多个字符组成的只读字符数组:
1.转义字符:
2.大小写转换:
大写:var upper=str.toUpperCase();
小写:var lower=str.LowerCase();
3.获取字符串中指定位子的字符:str.charAt(i) 4.获取字符串中指定位置的字符的ascii码 var ascii=str.CharCodeAt(i); 根据ascii码转回原文: var 原文=String.fromCharCode(ascii); 5.检索字符串:获取关键字下标 var i=str/arr.indexOf[关键字]的位置; 特殊:start可以省略不写,从0开始查找; 6.截取字符串: var substr=str/arr.slice(starti,end+1); str.Substring(starti,end+1); str.Substr(starti,n)//n代表截取的个数,不必考虑含头不含尾, 7.拼接字符串 var Newstr=str.concat(新字符串)
8.替换字符串: var newStr=str.replace("关键字",“新内容”); 9.切割、分割字符串 var arr=str.split("任意切割法")
正则表达式
定义字符串的【字符出现规则】的一个表达式
何时使用:切割、替换、【验证】
如何使用: /正则表达式/
1、最简单的正则:关键字原文 "no" -> /no/gi 只要用上正则就可以添加后缀
g:全部 i:忽略大小写
2.备选字符集:/【备选字符集】/
强调:a.一个中括号只管一个数字
b.正则表达式 【默认只要满足条件,不管其他了】,解决:前加^,后加/
【默认只要满足条件,不管其他了】,解决:前加^,后加/ -
特殊:如果备选字符集中的ascii码是连续的,中间的部分可用-代替掉
一位数字:[0-9]
一位字母:[A-Za-z]
一位数字、字母、下划线[0-9A-Za-z_];
一位汉字: [\u4e00-\u9fa5]
除了数字之外:[^0-9]
3、预定义字符集:前辈们提前定义好的,我们直接使用的
一位数字 [0-9] \d
一位数字、字母、下划线 \w
一位空白字符:\s
一位除了换行外的任意字符:.
建议:优先使用预定义字符集,满足不了的时候再用备选字符集自定义
4、量词:规定一个字符集出现的次数
有明确数量
字符集{n,m}:前面相邻的字符集,最少出现n次,最多出现m次
字符集{n,}前面相邻的字符集,最少出现n次,多了不限
字符集{n}前面相邻的字符集,必须出现n次
无明确数量:
?:可有可无,最多一次
* :可有可无,多了不限
+ :至少一次,多了不限
5、选择和分组
选择:多个规则中选择其中一个
规则1|规则2
分组:将多个字符集临时组成一组子规则
(规则1|规则2)
6、指定匹配位置:
^:开头
$:结尾
特殊:如果两者同时出现,要求从头到尾完全匹配 - 只要是做验证,必须加上
7、密码验证:4位,数字和字母,必须出现一位大写和一位数字 /^[0-9a-z]{4})->不能全由数字组成 (、![0-9a-z]+$)->不能全由数字组成,不能全由小写组成,不能全由数字和小写组成
/^(?![0-9a-z]+)[0-9A-Za-z]{4})(?![A-Za-z]+)[0-9A-Za-z]{4}$/ - 4位,数字和字母,必须出现一位大写和一位数字和一位小写 二、*****字符串中支持正则表达式的API 1、切割: var arr=str.split("固定切割符"/regexp)
2、高级替换法: var newStr=str.replace("固定关键字"/regexp,function(a,b,c){ console.log(a);//第一个形参保存的是正则匹配到的每一个关键字 console.log(b);//第二个形参保存的是正则匹配到的每一个关键字的第一个字符的下标 console.log(c);//原文本身 return a.length==2?"":"*"; });
3、格式化:在使用replace替换时,如果搭配上了正则,并且正则中加入分组,那么我们的高级替换法会得到更多的形参
有几个分组,就会多出几个形参。
var newStr=id.replace(reg,function(a,b,c,d,e,f,g,h){
//// console.log(a);//第一个形参保存的是正则匹配到的关键字 //// console.log(b);//第二个形参会第一个分组匹配到的关键字 //// console.log(c);//第三个形参会第2个分组匹配到的关键字 //// console.log(d);//第四个形参会第3个分组匹配到的关键字 //// //....说不清楚有多少个,具体看有多少个分组 //// console.log(e);//关键字下标 //// console.log(f);//原文本身 // return c+"年"+d+"月"+e+"日"; // })
Math对象
Math对象:提供了一些数学计算的API 强调:不需要创建,直接使用:全局对象window、Math
属性:Math.PI 得到3.1415926
API: 1、取整:3种 1、上取整:超过一点点,就取下一个整数 var result=Math.ceil(num);
2、下取整:哪怕超过的再多,也会省略掉小数部分
var result=Math.floor(num);
3.四舍五入取整
var result=Math.round(num);
以上三种方法只能取整数 取整的方式:以上三个 + *parseInt + *num.toFixed(0) 推荐:num.toFixed(d) 优点:具有四舍五入,并且小数位数可以自己设置 缺点:返回是一个字符串,搭配上一个parseFloat
//*笔试题:要求不允许使用toFixed,自己封装出toFixed的操作
var tofixed=function(num, d){
num*=Math.pow(10,d)
num=Math.round(num)
num/=Math.pow(10,d)
return num
}
2、乘方和开方 *乘方:var result=Math.pow(底数,幂) 开方:var result=Math.sqrt(num);//只能开平方
3、最大值和最小值: var max/min=Math.max/min(a,b,c,d,....); 问题:本身不支持数组参数的 解决: var max=Math.max.apply(Math.arr); apply是ES5才会学习的东西,apply具有打散数组的功能
4、绝对值:把负数变为正数 Math.abs(负数)
5、**随机数:Math.random(): 在0-1之间取随机的小数,但是有可能取到0,不可能取到1 有可能取到最小数,但是绝对不可能取到最大数 parseInt( Math.random()(max-min+1)+min)
2、Date对象:提供了操作日期的API
创建一个当前值: var now=now Date(); *创建一个自定义时间: var birth=new Date("") var start=new Date("2018/4/16");
3、创建一个自定义时间: var birth=new Date(yyyy,MM-1,dd,hh,mm,ss); 缺点:月份需要进行修正,0 代表 1月
4、复制一份日期: 为什么:日期的所有的API都是直接修改原日期对象的,无法获得修改之前的日期 所以,在执行API之前都要先进行复制,然后在操作复制后的日期 var end=new Date(start);
2、操作: 1、两个日期对象之间可以相减,得到一个毫秒差,换算出你想要的任何一部分 - 日期的本质底层保存的就是一个毫秒 其实创建还有第五种方式:var date=new Date(毫秒)
2、API: 分量:时间的单位 年月日星期:FullYear Month Date Day 时分秒毫秒:Hours Minutes Seconds Milliseconds 每一个分量都有一对儿getXXX/setXXX的API get用于获取 set用于设置
特殊:
1、取值范围:
年 - 当前年份的数字
月 - 011
日 - 131
星期 - 06:外国人觉得星期天是一周的第一天
小时 - 023
分秒 - 0~59
2、唯独星期不允许设置set
// console.log(birth.getFullYear());
// console.log(birth.getMonth());
// console.log(birth.getDate());
// console.log(birth.getDay());
// console.log(birth.getHours());
// console.log(birth.getMinutes());
// console.log(birth.getSeconds());
3、建议如果你希望对某个分量做加减
date.setXXX(date.getXXX()+/-n);
date.setFullYear(date.getFullYear()+3);//对日期+3年
3、建议如果你希望对某个分量做加减
date.setXXX(date.getXXX()+/-n);
date.setFullYear(date.getFullYear()+3);//对日期+3年
*String Number Boolean - > 具有包装类型
*Array *Function Math(数学) Date(日期) *RegExp(正则表达式:验证)
Error(错误)
*Object(面向对象)
Global - 全局对象:在前端/浏览器端/客户端/js中被window代替了:功能:保存着全局变量和全局函数,只有window可以省略不写
1、Error:错误对象
1、***浏览器自带四种错误类型:可以快速找到自己的错误 语法错误:SyntaxError 符号写错了 引用错误: ReferenceError 没有创建就去使用了 类型错误: TypeError 不是自己的方法你却使用了,最典型的就是经常会undefined.xxx或null.xxx 范围错误:RangeError - 只有一个API会碰到:num.toFixed(d);//d的取值范围只能是0~100之间
2、只要发生错误,就会报错,会导致后续代码不执行(如果APP报错,那会直接闪退),我们程序不希望报错 错误处理:就算发生错误,也不会报错,不希望抛出错误,而是希望给一个错误提示即可,后续代码 依然可以继续允许
语法: try{ 只放入你可能出错的代码 }catch(err){ 发生错误的时候才会执行 console.log(err); }
try...catch...的性能非常差,几乎里面的代码效率会被降到最低,所以不推荐使用
*可以用一个技术代替:if...else... 提前预判 *开发经验:一切的用户都是坏人,都要防一手(!isNaN(x)、正则:把用户控死)
3、抛出自定义错误: throw new Error("自定义提示");
2、*****Function:函数对象:提前创建好的,以后可以反复使用的代码段
1、创建:3种 1、声明方式:function 函数名(形参列表){函数体;return 返回值} - 完整的提前 2、直接量方式:var 函数名=function(形参列表){函数体;return 返回值} 3、构造函数方式:var 函数名=new Function("形参",.....,"函数体;return 返回值"); 何时使用:函数体是动态拼接的
2、调用:如果有return,记得接住结果 var 结果=函数名(实参);
3、考点: 1、创建的三种方式 2、作用域:变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错 3、声明提前: 4、按值传递: 5、重载overload:相同的函数名,根据传入的实参的不同,自动选择对应的函数执行 为什么:减轻程序员负担! 问题:JS不支持重载! JS不允许多个同名函数同时存在,如果存在,最后的会覆盖之前的所有 解决:在【函数中】有一个对象:arguments对象,不需要我们创建,自带 什么是arguments:是一个类数组对象:但是不是数组,和数组有3个相同点 1、都可以使用下标 2、都可以使用length 3、都可以遍历 作用:***接受住传到函数内部的所有实参,哪怕你不写一个形参 可以做的事儿: 1、实现重载:可以通过在函数内部判断arguments的不同,执行不同的分支操作 2、以后有没有形参无所谓 3、正式开发中,有可能会将多个函数整合为一个函数 - 代码优化
6、***匿名函数:没有名字的函数 1、匿名函数自调: //此函数只会执行一次,执行后会自动释放,优点,自动释放 - 代替全局写法,提升网页的性能 (function(){ var a=2; console.log(a);
btn.onclick=function(){
console.log("释放了码");
}
//引用类型:在还有人使用的情况下,是不会自动释放的
})();
***作用域: 1、全局:成员,随处可用,可以反复使用,缺点:容易被污染
2、函数:成员,只能在函数调用时内部可用,不会被污染,缺点:一次性的,是会自动释放的
***函数的执行原理: 1、程序加载时: 创建执行环境栈(ECS): 保存函数调用顺序的数组 首先压入全局执行环境(全局EC) 全局EC引用着全局对象window window中保存着全局变量
2、定义函数时
创建函数对象:封装代码段
在函数对象中有一个scope(作用域)属性:记录着函数来自的作用域是哪里
全局函数的scope都是window
3、调用前
在执行环境栈(ECS)压入新的EC(函数的EC)
创建活动对象(AO):保存着本次函数调用时用到的局部变量
在函数的EC中有一个scope chain(作用域链)属性引用AO
AO有一个parent属性是函数的scope引用的对象
4、调用时
正是因为有前面三步,我们才有了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
5、调用完:
函数的EC会出栈,没人引用AO,AO自动释放,所以局部变量也就释放了
两链一包: 作用域链:以函数的EC中的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构,就称之为叫做作用域链 作用:变量的使用规则,查找变量
*****闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实函数一个函数,写法和以后有点不一样 何时使用:希望保护一个可以【反复使用的局部变量】 如何使用:4步 1、两个函数相互嵌套 2、外层函数创建出受保护的变量 3、外层函数要return返回内层函数 4、内层函数要操作受保护的变量
强调:
1、判断是不是闭包,有没有两个函数嵌套,返回内层函数,内层函数在操作受保护的变量
2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
缺点:受保护的变量,永远不会被释放,使用过多,造成内存泄漏
使用场景:防抖节流 - 有三个事件需要做防抖节流:执行的速度非常的快,减少DOM树的渲染
1、elem.onmousemove - 鼠标移动事件
2、input.oninput - 输入内容有变化就会触发
3、window.onresize - 当前窗口的尺寸如果发生了变化就会触发:JS版本的媒体查询
公式:
elem.on事件名=function(){
inner();
}
function fdjl(){
var timer=null;//1 2 3 - 定时器序号
return function(){
if(timer){clearTimeout(timer);timer=null}
timer=setTimeout(function(){
//操作
},1000)
}
}
var inner=fdjl();
对象:Array/String/Function/Math...对象具有属性和方法,都是预定义好,现在我们学习自定义对象 2、*****面向对象:Object:三大特点:封装、继承、多态 1、***开发方式: 面向过程:经过 - 开始->结束,其实我们一直以来的开发方式都是面向过程:先干什么再干什么最后干什么 面向对象:对象(属性和方法),js有一句话万物皆对象,假设一个人是一个对象的话: 属性:姓名、性别、身高、体重、爱好、智商... 方法:吃饭、睡觉、拉粑粑、跑步、走路、打字、说话... 为什么要面向对象:现实生活中所有的数据都要保存在一个事物中才有意义 何时使用面向对象:以后做任何操作都要封装在一个对象中 - 建议:不太适合初学者
2、封装对象:创建自定义对象:3种 1、直接量方式: var obj={ "属性名":"属性值", ... "方法名":function(){}, ... } 强调: 1、其实属性名和方法名的""可以省略不写的 - 暂时建议写上,以后我们会学习JSON数据格式,要求必须加"" 2、访问对象的属性和方法 *对象名.属性名 === 对象名["属性名"] *对象名.方法名(); === 对象名"方法名"; JS种一切对象的底层都是hash数组 3、访问到不存在的属性或者方法,返回undefined 4、可以后期随时随地的添加新属性和新事件 5、如果希望遍历出对象中的所有东西 for(var i in 对象名){ 对象名[i] }
6、***如果你希望在对象的【方法中】使用对象自己的属性:写为:this.属性名 *****难点:this的指向: 1、*单个元素绑定事件:this->这个元素 2、*多个元素绑定事件:this->当前触发事件的元素 3、***函数中使用this:this->谁在调用此方法,this指向就是谁 4、定时器this->window 5、箭头函数this->外部对象
2、预定义构造函数方式: var obj=new Object();//空对象 //需要自己后续添加属性和方法 obj.属性名="属性值"; obj.方法名=function(){}
以上两种方法创建都有一个缺陷:一次只能创建一个对象,适合创建单个对象的时候使用(第一种方式)
3、自定义构造函数方式:- 何时创建多个对象:2步 1、创建自定义构造函数 function 类名(name,age,salary){ this.name=name; this.age=age; this.salary=salary; }
2、反复调用自定义构造函数创建出对象
var xxx=new 类名("实参",...)