# 1、自定义Function: 什么是函数:需要先定义好,可以反复使用的一个代码段 何时使用:1、不希望打开页面立刻执行 2、以后可以反复使用 3、希望绑定在页面元素之上 如何使用:
1、创建并且调用:2种
1、创建
*1、【声明方式】创建函数
function 函数名(形参,...){
函数体;
return 返回值/结果;
}
2、【直接量方式】创建函数 - 无用
var 函数名=function(形参,...){
函数体;
return 返回值/结果;
}
2、调用
var 接住返回的结果=函数名(实参,...);
//其实return的本意退出函数,但是如果return后跟着一个数据,
//顺便将数据返回到函数作用域的外部,但return只负责返回,不负责保存
//就算省略return,默认也会return undefined;
//具体需不要得到函数的结果,看你自己
2、***作用域:2种
1、全局作用域:全局变量 和 全局函数,在页面的任何一个位置都可以使用
2、函数/局部作用域:局部变量 和 局部函数,在【当前函数调用时内部可用】
*变量的使用规则:优先使用自己的,自己没有找全局,全局没有报错
特殊:缺点:1、千万不要再函数中对着未声明的变量直接赋值 - 全局污染
2、局部可以用全局的,但是全局不能用局部的 - 解决:看上面return
3、***声明提前:
在程序正式执行之前
将var声明的变量(轻)和function声明的函数(重)
都会悄悄集中定义在当前作用域的顶部
但是赋值留在原地
声明方式创建的函数会完整的提前(第一种方式)
直接量方式创建的函数不会完整提前,只有变量部分会提前(第二种方式)
何时使用:永远不会自己使用,垃圾干扰我们判断 - 只会在鄙视中遇到,为什么平时开发根本不可能遇到它?
只要你遵守以下原则:
1、变量名和函数名尽量的不要重复
2、先创建后使用
3、如果鄙视时需要先试用后创建,多半都是在考你声明提前
4、***按值传递:两个变量之间赋值,分两种情况
如果传递的是原始类型的值:
修改一个变量,另一个变量是不会受到影响的,其实是复制了一个【副本】给对方
如果传递的是引用类型的对象:
修改一个变量,另一个变量是会受到影响的,引用类型其实根本没有保存到变量中,仅仅只是保存了一个地址值
两者用的是同一个地址值,所以会相互影响
2、预定义全局函数:前辈们提前定义好的,我们程序员可以直接使用的,在任何位置都可以使用
*parseInt/Float/isNaN/eval... 其实都是预定义全局函数,但是alert/prompt不属于我们现在学的范畴:确实也是全局预定义函数,只不过属于BOM
1、编码和解码
问题:url中不允许出现多字节字符(汉字,utf-8编码格式下,一个汉字占3字节),如果出现会乱码
解决:发送前,前端将多字节字符编码为单字节字符(数字、字母、符号)
发送后,后端将单字节字符在解码为多字节原文
如何:
编码:var 不认识=encodeURIComponent("大梵");
解码:var 原文=decodeURIComponent(不认识);
这个东西没有用,在某一次浏览器更新后,当前就被淘汰了,浏览器自带此功能 - 唯一的用处,现在就是玩了:悄悄话
2、isFinite(num):判断num是不是有效范围 - 垃圾并不能用于判断是不是NaN,因为有三个人会是false
哪些会为false:NaN,Infinity,分母为0
3、***分支结构:根据条件的不同,选择部分代码执行
1、if分支
2、三目&短路
3、switch...case...语法
switch(变量/表达式){
case 值1:
操作1;
case 值2:
操作2;
case 值3:
操作3;
default:
默认操作;
}
特殊:1、不具备隐式转换
2、问题:默认只要一个case满足后,就会将后面所有操作全部做一次
解决:break;
建议:每一个case的操作后都要跟上一个break
有的地方可以不加break:
1、最后一个操作default可以省略break
2、如果中间连续的多个操作,是相同的,也可以省略掉中间部分
面试题:if vs switch
1、switch:缺点:必须要知道最后的结果才能使用,不能做范围判断
优点:执行效率相对较高
2、if : 优点:可以做范围判断
缺点:执行效率相对较慢
建议:代码优化:尽量的将if替换为switch或者三目或短路
1、***循环结构:宏观几乎是一瞬间执行的,相同 或 相似的 代码
1、*var 循环变量=几;
while(循环条件){
操作;
变量变化;
}
2、do...while循环语法:
var 循环变量=几;
do{
操作;
变量变化;
}while(循环条件)
**面试题:while和do...while的区别?
只看第一次,如果大家都满足,则没区别
如果不满足,while一次都不执行,而dowhile至少会执行一次**
3、*for(var 循环变量=几;循环条件;变量变化){
操作;
}
4、*退出循环语句:
break - 退出整个循环
continue - 退出本次循环
5、死循环:while(true){} for(;;){}
forEach for in for of - 专门为遍历数组准备的
2、*****数组的基础:
1、什么是数组:一个集合可以保存多个数据
何时使用:多个相关的数据,都要集中的定义在一个集合中
为什么:因为一个好的数据结构,能够极大的提升我们程序员的开发效率
2、创建:2种
1、*直接量方式:var arr=[值1,...];
2、构造函数方式:var arr=new Array(值1,...);
坑:new Array(num); - 懂不起:以为你是创建了一个长度为num的空数组
3、访问:数组名[下标];
添加/修改:数组名[下标]=新值;
特殊:访问时,下标越界 - 返回undefined
添加时,下标越界 - 变为稀疏数组,导致下标不连续,导致以后遍历一定会得到undefined
4、数组三大不限制
1、不限制类型
2、不限制长度
3、不限制下标越界 - 不推荐
5、数组唯一的一个属性:数组名.length - 获取数组的长度
三个固定套路:
1、末尾添加:arr[arr.length]=新值
2、获取倒数第n个:arr[arr.length-n];
3、缩容:arr.length-=n;
6、遍历数组:对数组中的每个元素执行 相同 或 相似的操作
for(var i=0;i<arr.length;i++){
arr[i];//当前次元素
}
7、*如何释放一个引用类型:看清楚此引用类型有几个变量关联着,每个变量都要释放后,才能真正的释放干净
建议:我们的代码都要封装在一个函数中,函数中的一切变量都会自动释放
索引数组:下标都是由数字组成的数组
8、*关联(hash)数组:下标是可以自定义的数组
为什么:索引数组的下标无具体的意义,不便于查找
如何使用:
1、创建:2步
1、创建一个空数组:var arr=[];
2、为数组添加自定义下标并且赋值:arr["自定义下标"]=新值
2、访问:arr["自定义下标"]
3、强调:hash数组length永久失效,永久为0!
问题:hash数组不能使用for遍历,必须使用 for in循环遍历数组,语法:
for(var i in 数组名){
console.log(i);//自动获得当前数组的所有的下标,不需要我们去设置从哪里开始到哪里结束
console.log(arr[i]);//当前次元素
}
牛逼:不光可以遍历hash数组,也可以遍历索引数组:
建议:hash用for in,索引用for
4、*js中一切东西都是对象,万物皆对象,除了undefined和null,【一切对象的底层都是hash数组】
3、*****数组的API:数组的函数,前辈们定义好的,只有数组可以使用:
1、*****arr 转为 str:
1、语法:var str=arr.join("自定义连接符");
作用:
1、鄙视时:给你一个数组,将他无缝拼接在一起:
var arr=["h","e","l","l","o"];
var str=arr.join("");
console.log(str);
2、拼接为页面元素:
//以后从数据库中取出数据
var cities=["-请选择-","北京","南京","西京","东京","重庆"];
//拼接成页面元素后,innerHTML是识别标签的
sel.innerHTML="<option>"+cities.join("</option><option>")+"</option>";
2、*拼接数组:添加元素的新方式:
语法:var newArr=arr.concat(值1,arr1,...);
特殊:1、此方法不修改原数组,只会返回一个新数组
2、支持传入数组参数,悄悄的将我们传入的数组打散,不会变成二维数组
3、*截取子数组:取出数组中想要的某一部分组成的一个新数组
语法:var subArr=arr.slice(starti,endi);
特殊:1、此方法不修改原数组,只会返回一个新数组
2、含头不含尾
3、第二参数可以省略不写,截取到末尾
4、第一个参数也可以省略不写,如果两个参数都没写,从头截取到尾 - 深拷贝(复制了一份副本)
5、支持负数参数,-1代表倒数第一个
以上的API都不会修改原数组
以下的API都会修改原数组
4、*删除、插入、替换:
删除:var dels=arr.splice(starti,n);//n代表删除的个数
特殊:此方法其实也有返回值,返回的就是你删除的元素组成的一个新数组
插入:arr.splice(starti,0,新值1,....);
特殊:1、没有删除,也有返回值,返回的是一个空数组
2、原starti位置的元素以及后续元素都会向后顺移
3、不建议插入数组,会变得不伦不类
替换:var dels=arr.splice(starti,n,新值1,....);
特殊:删除的个数和插入的个数不必相同
5、反转数组:arr.reverse();
1、*****Array API
1、*****排序:
1、鄙视时:不允许使用数组的API - 冒泡排序:拿着数组中的每一个元素,
让前一个和后一个做比较,如果前一个>后一个,两者应该交换位置:固定公式
var arr=[32,14,43,453,6,58,56,531,5,57];
for(var j=1;j<arr.length;j++){
for(var i=0;i<arr.length-j;i++){
if(arr[i]>arr[i+1]){
var m=arr[i];
arr[i]=arr[i+1];
arr[i+1]=m;
}
}
}
console.log(arr);
2、数组的API:语法:arr.sort();
默认:悄悄的转为字符串,按位PK每个字符的unicode号,默认是按照字符串排序
问题1:希望按照数字升序排序
解决:
arr.sort(function(a,b){
return a-b;
});
原理:1、匿名函数回调,一般都是前辈们规定好的,我们只能学习怎么使用,自动调用,而且有多少对儿就会调用多少次
2、a:后一个数字 b:前一个数字
3、返回结果,如果是正数,说明后一个大
如果是负数,说明前一个大
如果是0,说明一样大
4、而我们的sort方法会根据你返回的正数负数0,来判断要不要交换位置
问题2:希望按照数字降序排列
arr.sort(function(a,b){
return b-a;
});
建议:开发中使用API排序,鄙视可能会碰到冒泡排序
强调:切记前端所有技术中:唯独只有数组可以排序,意味着以后如果网页中有一个排序功能,说明他的底层一定是一个数组
2、栈和队列:
栈:其实就是一个数组,只不过要求只能从一端进出,另一端是封闭的
何时:始终希望使用最新的数据时,现实中很少,代码中也很少
如何:
前进:arr.unshift(新元素,...) - 添加元素的新方式,建议不要添加数组
前出:var first=arr.shift(); - 删除元素的新方式,一次只能删除一个,而且是第一个
后进:arr.push(新元素,...) - 添加元素的新方式,建议不要添加数组
后出:var last=arr.pop(); - 删除元素的新方式,一次只能删除一个,而且是最后一个
队列:其实就是一个数组,只不过要求一端进,另一端出
何时:按照先来后到的顺序
如何:
前进:arr.unshift(新元素,...) - 添加元素的新方式,建议不要添加数组
后出:var last=arr.pop(); - 删除元素的新方式,一次只能删除一个,而且是最后一个
后进:arr.push(新元素,...) - 添加元素的新方式,建议不要添加数组
后出:var last=arr.pop(); - 删除元素的新方式,一次只能删除一个,而且是最后一个
2、二维数组:数组的元素,又引用着另一个数组
何时使用:在一个数组内,希望再次细分每个分类
如何使用
创建:
var arr=[
["杨杰",18,1200],
["周洁",19,1500],
["盛蕾",20,3500]
];
访问:arr[行下标][列下标];
特殊:列下标越界 - 返回undefined
行下标越界 - 报错:行下标越界确实会得到undefined,但是undefined没有资格再加[]
遍历二维数组:必然两层循环,外层循环控制行,内层循环控制列
for(var r=0;r<arr.length;r++){
for(var c=0;c<arr[r].length;c++){
console.log(arr[r][c]);
}
}
总结:ES3提供的数组,我们学习完毕了:
1、数组的基础(创建、访问、添加、length、遍历)
2、数组的API:10个(转字符串、拼接、截取、翻转、删插替、排序、栈和队列)
3、二维数组
3、*****String的概念:
1、什么是字符串:多个字符组成的【只读】字符【数组】:
1、只读:我们下周一要学习的所有的字符串的API,都不会修改原字符串,只会返回一个新字符串
2、数组:和数组有相同点:
1、可以使用下标得到某个字符
2、可以使用length获取字符串的长度
3、遍历字符串
4、数组不修改原数组的API,字符串也可以使用(拼接 - 垃圾还不如直接+运算,截取)
当然和数组也有很多的不同点,数组修改原数组的API,字符串一个都用不到,字符串也有十几个API等待我们学习
2、引用/对象类型:11个
*String Number Boolean - > 具有包装类型
*Array *Function Math(数学) Date(日期) *RegExp(正则表达式:验证)
Error(错误)
*Object(面向对象)
Global - 全局对象:在前端/浏览器端/客户端/js中被window代替了:功能:保存着全局变量和全局函数,只有window可以省略不写
3、***包装类型:专门用于将原始类型的值封装为一个引用类型的对象的(带来了属性和方法)
为什么:原始类型的值原本是不具备任何属性和方法的,但是前辈们发现我们程序员会经常操作到字符串
前辈们为了方便我们程序员,为三个原始类型提供了包装类型
何时使用:只要试图用原始类型的变量去用.调用属性和方法时,就会悄悄的用上包装类型变为对象
何时释放:方法调用完毕后,自动释放包装类型,并且返回数据(又会变回原始类型)
为什么undefined和null不能用. - 没有提供包装类型
1、StringAPI:只有字符串可以使用的函数,特点:只读!
1、转义字符:\
作用:
1、将字符串中和程序冲突的符号编译为原文
"\"" '\''
2、包含特殊功能的符号:
换行:\n
制表符:\t
*3、输出unicode编码的字符:
\uXXXX:第一个汉字:4e00 - ascii:19968
最后一个汉字:9fa5 - ascii:40869
2、*大小写转换:将字符串中的每个英文统一的转为大写 或 小写
何时:只要程序不区分大小写,就要【先统一】的转为大写 或 小写,再比较(验证码)
如何:
大写:var upper=str.toUpperCase();
小写:var lower=str.toLowerCase();
3、获取字符串中指定位置的字符:
str.charAt(i) 还不如直接 str[i]
4、获取字符串中指定位置的字符的ascii码:
var ascii=str.charCodeAt(i);
根据ascii码在转回原文:
var 原文=String.fromCharCode(ascii);
5、***检索字符串:检查索引:获取关键字的下标
var i=str/arr.indexOf("关键字",starti);
从starti位置开始,查找右侧【第一个关键字】的位置
特殊:
1、starti可以省略不写,从0开始查找
2、返回值:找到了,返回的第一个关键字的第一个字符的下标
*没找到,返回-1,我们不关心下标为多少,我只关心下标为不为-1
作用:判断有没有,以后如果不想有重复的,就一定要用上他
3、此方法不光字符串可以使用,数组也可以使用,后期才为数组添加上的,老IE上的数组就没有此方法
4、笔试题:默认只能获取到第一个关键字的下标,如何才能获取到所有的关键字的下标
var str="no zuo no die no can no bibi";
var i=-1;
while((i=str.indexOf("no",i+1))!=-1){
console.log(i);
}
6、*截取字符串:3种
*var subStr=str/arr.slice(starti,endi+1);//用法和数组的slice一摸一样
str.substring(starti,endi+1);//几乎和slice一致,不支持附属参数
*str.substr(starti,n);//n代表截取的个数,不必考虑含头不含尾
7、拼接字符串:var newStr=str.concat(新字符串,...);//还不如+运算
8、*替换字符串:本身强大,但是必须搭配正则表达式
var newStr=str.replace("关键字","新内容");
9、*****切割/分割字符串:
var arr=str.split("任意切割符");
作用:将字符串=>数组
特殊:1、切割后,切割符就不存在了
2、切割符"",切散每一个字符
扩展:如何使用JS生成元素:3步
1、创建空标签:var elem=document.createElement("标签名");
2、为此元素设置必要的属性 或 事件
elem.属性名="值";
elem.on事件名=function(){}
3、渲染页面,上DOM树:
父.appendChild(新);