此笔记是我在拉勾学习课程过程中的总结,文字原创,笔记里很多技巧和知识是老师总结的,如果有侵权,请联系本人!
一、数组
1、定义
一组有序的数据集合,可以存放多个数据,不限制数据类型,并且数组长度可以动态调整。
创建数组最简单的方式就是数组字面量方式
数组的字面量:[]
一般将数组字面量赋值给一个变量,方便后期对数组操作如果存放多个数据,每个数据用逗号隔开。
2、获取数据元素
数组可以通过index获取对应的数据,进行下一步操作
Index:从0开始,按照整数排序往后顺序排列
可以通过index获取某一项之后,使用或者更改数组项的值
调用数组:利用数组变量名后面直接加[index]方式
注意:
如果索引值超过最大项,相当于这一项没有赋值,返回undefined
更改数据:arr[index]调用这项数据,后面等号赋值更改数据
3、获取数组长度
数组有个length属性,记录数组总长度
变量名.length
数组长度与数组最后一项的下标存在关系,最后一项的下标等于数组length-1
数组长度可以发生改变,不是固定的。
增加数组长度:直接给length附一个值,大于原来长度
或者,给一个大于最大下标的项直接赋值,可以强制拉长
缩短:强制给一个length赋值,后面数据会被直接删除,删除不可逆。
<script>
// 创建包含多个数据的数组,数据类型不限制
var arr2 = [1,true,false,undefined,null,[7,7],"haha"];
// console.log(arr2);
// 获取元素的方法
console.log(arr2[0]);
console.log(arr2[1]);
console.log(arr2[2]);
//更改元素方法
arr2[2] = 5;
console.log(arr2);
// 获取最后一项数据
console.log(arr2[arr2.length-1]);
</script>
4、数组遍历
根据下标在0到arr.length-1之间,进行for循环遍历
// 定义一个数组
var arr = [1,2,3,4,5,6,77,885,33,22,55,55];
// 遍历数组
for (var i = 0; i <= arr.length-1 ; i++) {
console.log(arr[i]);
}
// 为每个数据加5
for (var i = 0; i < arr.length ; i++) {
arr[i] += 5;
}
console.log(arr);
二、函数基础
1、函数概念
也叫作功能、方法,函数可以将一段代码一起封装起来,被封装起来的函数具备某一项特殊的功能。
特点就是内部封装的一段代码作为一个完整的结构体,要执行就都执行,要不执行就都不执行。
2、函数声明
函数必须先定义后使用,函数声明的时候,函数体不执行,只有当函数调用的时候才执行。
特点: 函数声明的时候,函数体并不会执行,只有当函数被调用的时候才会执行。
命名规则:
函数名的命名规则:
1、可以使用字母、数字、下划线、$ ,数字不能作为开头
2、区分大小写,不能使用关键字和保留字
// 函数声明
function fun() {
console.log(1);
console.log(2);
console.log(3);
console.log(4);
}
3、函数调用
调用方法:函数名();
函数调用时会将函数内部封装的所有代码立即执行
函数内部语句执行的位置,与函数定义位置无关,与函数调用位置有关。
函数可以一次调用,多次执行。
// 函数调用
function fun() {
console.log(1);
console.log(2);
console.log(3);
console.log(4);
}
fun();
4、函数的参数
一个函数可以设置0个或者多个参数,参数之间逗号分隔。
函数的参数根据书写位置不同,名称也不同:
• 形式参数:本质是变量,可以接收实际参数传递过来的数据。
• 实际参数:本质就是传递的各种类型的数据,传递给每个形参。
// 定义一个而求和函数,传入两个数据
function sum(a,b) {
console.log(a + b);
}
// 调用函数中,给小括号内部添加数据
sum(3,4);
sum(4,5);
5、函数的返回值
函数能够通过参数接收数据,也能够将函数执行结果返回一个值。
利用函数内部的一个 return 的关键字设置函数的返回值。
作用1:函数内部结构体执行到return,会立即停止后面代码的执行。
作用2:可以在return后加空格,后面任意定义一个数据字面量或表达式,函数执行完自身功能之后,整体被return矮化成为表达式,表达式必须求出一个值继续可以参与程序,表达式的值就是return后的数据。
作用3:如果有返回值,执行结果可以当成普通数据参与程序
作用4:如果有返回值,可以作为普通数据赋值给一个变量,或赋值给其他函数的实际参数。
注意:如果函数没设置return语句,默认返回undefined,如果有return语句,但是return没有值,返回值也是undefined。
6、函数表达式
将函数的定义、匿名函数值给一个变量
函数定义赋值给一个变量,相当于函数整体矮化成了一个表达式。
调用函数表达式,方法是给变量名加()执行,不能使用函数名加()执行。
// 定义一个函数表达式
var foo = function name() {
console.log(1);
};
var foo2 = function () {
console.log(2);
};
// 调用函数时,只能用变量名调用,如果函数名不成功
foo();
foo2();
7、函数数据类型
函数是一种单独的数据类型: function
由于函数是一种数据类型。可以参与其他程序。
例如,可以把函数作为另一个函数的参数,被另一个函数调用。
或者可以把函数作为返回值从函数内部返回。
// 函数作为一种数据类型,可以当做其他函数的参数
setInterval(function () {
console.log(1);
},1000);
// 把函数当成另一个函数的返回值
function fun (b) {
var a = 10;
return function () {
alert(a + b);
};
}
8、arguments 对象
JavaScript中,arguments 对象是比较特别的一个对象,实际上是当前函数的一个内置属性。
也就是说所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有的实参。
arguments 是一个伪数组,因此及可以进行遍历。
函数的实参个数和形参个数可以不一致,所有的实参都会存储在函数内部的 arguments 类数组对象中。
案例
定义一个求和函数,如果传入 1 个参数,返回它自己,如果传入两个参数,返回他们的和,如果传入三个参数,先比较前两个的大小,大的与第三个参数求和返回,如果传入 4 个及以上,输出错误提示。
function sum(a,b,c ) {
// 条件分支语句,根据实参个数不同走不通分支
switch (arguments.length) {
case 1:
return a;
break;
case 2:
return a + b;
case 3:
return a > b ? a + c : b + c;
default:
// 模拟控制台,抛出异常
throw new Error("参数个数不能超过3个");
}
}
// 调用函数
console.log(sum(1));
console.log(sum(2,3));
console.log(sum(2,3,2));
9、函数递归
函数内部可以通过函数名调用函数自身
递归次数太多容易出现错误,超出计算机的最大计算能力。
1000项以上吧,我觉得还是不要再用递归了
案例
例如菲波那切数列中的一项。
// 函数如果传入的参数是1,返回1,如果传入的是1以上的数字,让他返回参数 + 函数调用上一项
function fun(a) {
if (a == 1) {
return 1;
}else {
return a + fun(a - 1);
}
}
// 调用函数、
console.log(fun(1));
console.log(fun(2));
console.log(fun(3));
10、作用域
变量可以起作用的范围
如果变量定义在函数内部,只能在函数内部被访问到,函数外部不能使用这个变量,函数就是变量定义的作用域。
任意{}中的结构属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为 块级作用域
在es5之前没有 块级作用域的概念,只有函数作用域,现阶段可以认为JavaScript没有 块级作用域。
// 定义函数
function name() {
var i = 1;
console.log(i);
}
name();
function name2 () {
console.log(i);
}
name2();//报错
全局变量和局部变量
局部变量:定义在函数内部的变量,只能在函数作用域内部被访问到,在外面没有定义的。
全局变量:从广义上来说,也是一种局部变量,定义在全局的变量,作用域范围是全局,在整个 js 程序任意位置都能够被访问到。
变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁
函数参数也是局部变量
函数参数本质是一个变量,也有自己的作用域,函数的参数也属于函数自己内部的局部变量,也只能在内部使用,外部没有定义。
// // 函数的参数也是局部变量
// function fun(a) {
// a = 2;
// console.log(a);
// }
// fun(1);
// console.log(a);
函数定义在另一个函数内部,如果外部函数没执行,相当于内部没写。
// 函数也有自己的作用域
function outer() {
var a = 1;
function inner () {
console.log(2);
}
// 函数内部调用子函数才能成功
inner();
}
// 调用函数
outer();
作用域链
查找变量的时候,都是从内往外查找
案例
案例2
var a = 1; // 0级
function outer(){
var a = 2; // 1级
function inner(){
var a = 3; // 2级
// 先查找自身作用域有没有a,没有就查找外层是否有啊a,没有就查找全局变量中是否有a,没有就报错 --- 作用域链
console.log(a);
}
}
在定义变量的必须写var关键字,否则会定义在全局,造成全局变量污染问题
// var a = 1;
function name() {
var a = 2;
console.log(a);
}
name();
console.log(a);
11、预解析和声明提升
过程:
1、 把变量的声明提升到当前作用域最前面,只会提升声明,不会提升赋值。
2、 把函数的声明提升到当前作用域最前面,只会提升声明,不会提升调用
3、 先提升var,在提升function。
JavaScript的执行过程:在预解析之后,根据新的代码顺序,从上往下按照既定规律执行js代码。
// // 预解析,吧变量声明部分提升到作用域最顶部
// var a;//a中存了一个underfined
// console.log(a);
// // 后定义变量
// // var a = 1;
// a = 1;
console.log(foo);
foo();//underfined
// 函数表达式提升,进行的是变量声明提升
var foo = function () {
console.log(3);
}
变量声明提升
所有定义的变量,都会将声明的过程提升到所在作用域的最上面,在将来的代码执行过程中,按先后顺序先执行被提升的声明变量。
提升时,只提升声明过程,而不进行赋值,相当于变量定义未赋值,变量内存储underfined值。
因此,在前面调用后定义的变量,不会报错,会underfined值
// 预解析,吧变量声明部分提升到作用域最顶部
console.log(a);
// 后定义变量
var a = 1;
//预解析过程
var a;//a中存了一个underfined
console.log(a);
// 后定义变量
// var a = 1;
a = 1;
函数声明提升
函数定义过程已经在最开始就会执行,一旦函数定义成功,后续就可以直接调用。
预解析过程中,先提升 var 变量声明,再提升 function 函数声明。
如果变量名与函数同名,后提升的函数名标识符会覆盖先提升的变量名,因此,后续代码调用标识符时,内部是函数定义过程,而不是underfined。
建议:不要书写相同的标识符给变量名或函数名,避免出现覆盖。
函数表达式
进行的是变量声明提升。提升后变量内部存一个underfined,在前面进行函数方法调用,会报错。
建议:定义函数时,最好使用function关键字方式,这样函数声明提升可以永远生效。
12、IIFE自调用函数
函数矮化成了一个表达式,后面加()运算符就可以立即执行
调用方式:函数名或者函数表达式的变量名后加()运算符
// 关键字定义的方式,不能立即执行
// function name() {
// console.log(2);
// }();
// 函数表达式方式
var foo = function () {
console.log(2);
}();
函数矮化成表达式,就可以实现自调用
数学运算符: + -()
逻辑运算符: !非运算
IIFE结构可以关住函数的作用域,结构外面不能调用函数。
IIFE最常用的就是()运算符,而且函数可以不写函数名,使用匿名函数。
// 通过函数前面添加操作符,可以将函数矮化成表达式
+ function name() {
console.log(2);
}();
- function name() {
console.log(2);
}();
(function name() {
console.log(2);
})();
// * function name() {
// console.log(2);
// }();不成功
// iife关住了函数的作用域,无法在外面调用
三、对象
1、对象可以自定义名称存储一系列的问题
JavaScript的对象是无序属性的集合。
其属性可以包含基本值、对象或函数。对象就是一组没有顺序的值。我们可以吧JavaScript中的对象想象成键值对,其中值可以使数据和函数
对象行为特征:
特征:用属性表示
行为:用方法表示
2、对象字面量
创建一个对象最简单的方式就是使用对象字面量赋值给变量,类似数组
语法:{}
每条数据都有属性名和属性值构成,键值对:k:v
K是属性名
V是属性值,可以存放任意类型数据,比如简单类型数据、函数、对象。
3、创建对象
new Object()创建对象
Object()构造函数是一种特殊函数,主要用来创建对象时初始化对象,即为对象成员变量赋初始值。
1、 构造函数用于创建一类对象,首字母大写
2、 构造函数和new一起使用才有意义。
// new Object()方法创建
var person1 = new Object();
// 添加属性和方法
person1.name = "zs";
person1.age = "19";
person1.sex = true;
person1.sayhi = function () {
console.log("hello");
};
console.log(person1);
New的执行做的四件事情
1、 new会在内存先创建一个空对象
2、 new会让this指向这个新的对象
3、 执行构造函数 目的是给这个对象增加属性和方法
4、 New会返回这个新的对象(执行完构造函数,返回这个对象赋值给变量)
工厂函数方法创建对象
如果创建多个类似对象,可以将new object()过程封装到函数里,将来调用函数就可以创建对象,相当于一个生产对象的函数工厂,简化代码。
// 工厂方法就是相当于对new object方法的一个封装
function createPerson (name , age , sex) {
// 创建一个空对象
var person = new Object();
// 给对象内部添加属性和方法
person.name = name;
person.age = age;
person.sex = sex;
person.sayhi = function () {
console.log("hello");
}
// 返回这个对象
return person;
}
// 调用工厂函数创建对象
var p1 = createPerson("zhangs" , 18 , true);
var p2 = createPerson("lisi" , 356 , false);
// 输出
console.log(p1);
console.log(p2);
自定义构造函数创建对象
自定义一个创建具体对象的构造函数,函数不需要new一个构造函数的过程,直接使用this代替对象进行属性和方法的书写,也不需要return一个返回值。
使用时,利用new关键字调用自定义的构造函数即可。
注意:构造函数的函数名首字母需要大写,区别于其他普通函数名。
//自定义一个构造函数
function Person (name,age,sex) {
// 不需要new一个新对象
// 用this替代将来创建的新对象
this.name = name;
this.age = age;
this.sex = sex;
this.sayhi = function () {
console.log("hei");
};
// 不需要return
}
// 用new关键字调用构造函数
var p1 = new Person ('ls',18,true);
console.log(p1);
4、遍历对象
For in循环也是循环的一种,专门用来遍历对象.
简单的循环遍历:输出每一项属性名和属性值。
循环遍历每一项
for(var k in obj){
console.log(k+"项的属性值是"+obj[k]);
}
5、简单类型和复杂类型
值类型:简单数据类型,基本数据类型,在存储时,变量中存储的是只本身,因此叫做值类型。
引用类型:复杂数据类型,在存储时,变量中存储的仅仅是地址(引用),因此叫做以引用数据类型。
- 栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。
- 堆(操作系统): 存储复杂类型(对象),一般由程序员分配释放, 若程序员不释放,由垃圾回收机制回收。
5、内置对象
JavaScript 包含:ECMAscript DOM BOM
• ECMAscript 包含:变量、数据、运算符、条件分支语句、循环语句、函数、数组、对象……
JavaScript 的对象包含三种:自定义对象 内置对象 浏览器对象
• ECMAscript 的对象:自定义对象 内置对象
• 使用一个内置对象,只需要知道对象中有哪些成员,有什么功能,直接使用
Math对象
// 获取随机数 0-1
// 参数:不需要传递参数
// 返回值: 0 <= < 1
Math.random()
function getRandom(min,max){
return Math.floor(Math.random() * ( max - min ) + min);
}
// 圆周率 3.14159
Math.PI;
//向下取整
Math.floor(123.4); // 123
// 向上取整
Math.ceil(123.2);//124
// 四舍伍入
Math.round(123.4); // 123
Math.round(123.5); // 124
// 绝对值
Math.abs(-5); // 5
// 最大值
Math.max(12,3,24); // 24
var arr = [12,3,24];
Math.max(...arr);
// 最小值
Math.min(12,3,24); // 3
// 次幂
Math.pow(3,4); // 3的4次方 81
// 平分跟
Math.sqrt(9); // 3
创建数组对象array
new Array()构造函数方法
// 数组也是对象,可以通过构造函数生成
// 空数组
var arr1 = new Array();
// 添加数据,可以传参数
var arr2 = new Array(1,2,3);
// console.log(arr1);
// console.log(arr2);
var a = {};
// 检测数组的数据类型
console.log(typeof(arr1));
// 检测某个实例对象是否属于某个对象类型
console.log(arr1 instanceof Array);
console.log(a instanceof Array);
6、数组方法
// 字面量方法创建数组
var arr = [1,2,3,4];
//toString()方法:转字符串
console.log(arr.toString());
// 字面量方法创建数组
var arr = [1,2,3,4];
//toString()方法:转字符串
// console.log(arr.toString());
// 收尾操作方法
// 尾推,参数是随意的,可以有一个或多个
// arr.push(5,4,56,4);
// arr.push([1,3,4,5,5]);
// console.log(arr.push(5,4,56,4));
// console.log(arr);
// 删除最后一项数据
// 不需要传参
// console.log(arr.pop());
// console.log(arr);
// 删除第一项数据,不需要传参
console.log(arr.shift());
console.log(arr);
// 首填,参数与push方法类似
console.log(arr.unshift(1,2));
console.log(arr);
// 字面量方法创建数组
var arr = [1,2,3,4];
// 合并方法
// 参数:数组、数组变量、零散的值
// 返回值:一个新的拼接后的数组
// var arr1 = arr.concat([5,6,7]);
// var ar = [5,6,7];
// var arr1 = arr.concat(ar);
var arr1 = arr.concat(11,12,13);
console.log(arr);
console.log(arr1);
//拆分
// 字面量方法创建数组
var arr = [1,2,3,4,5,6,7,8,9,10];
// 拆分方法
// 参数为证
/*Slice(start,end)
从当前数组中截取新的数组,不影响原来的数组,返回一个新数组,包含从start到end的元素。*/
// var arr1 = arr.slice(3,7);
// 参数为负数
var arr1 = arr.slice(-3,-7);
// 只写一个参数
var arr2 = arr.slice(-7,-1);
console.log(arr1);
console.log(arr2);
/*删除、插入、替换:
Splice(index,howmany,element1,element2……)
用于插入、删除或者替换数组元素
Index:删除元素的开始位置
Howmany:删除元素的个数,可以是0
Elemen1,element2:要替换新的数据。
注意:使用该函数之后,原有的长度会变短,如果是循环,需要用i--,来防止越过下一项
*/
// 字面量方法创建数组
var arr = [1,2,3,4,5,6,7,8,9,10];
// 删除功能
console.log(arr.splice(2,5));
console.log(arr);
// 替换功能,传三个以上的参数
arr.splice(2,5,"hahha","ghekke");
console.log(arr);
// 插入功能,传三个以上的参数,但是第二个参数必须为0
arr.splice(2,0,'hello');
位置方法
IndexOf() 查找数据在数组中最先出现的下标
lastIndexOf() 查找数据在数组中最后一次出现的下标
注意:如果没找到返回-1
// 字面量方法创建数组
var arr = [1,2,3,4,5,6,7,8,9,5,10];
console.log(arr.indexOf(4));
console.log(arr.lastIndexOf(5));
倒序和排序
Reverse()将数组完全颠倒,第一项变成最后一项,最后一项变成第一项。
// 倒序排列
console.log(arr.reverse());
sort()
默认根据字符编码顺序,从小到大排序
如果想根据数值大小排序,必须添加sort的比较函数参数。
该函数比较两个值,然后返回一个用于说明两个值相对顺序的数字。
比较函数应该具有两个参数a 和 b,根据a 和 b的关系作为判断条件,返回值根据条件分为三个分支,正数、负数、0;
返回值负数-1,a排在b前面
返回值1,a排在b后面
返回值0;a和b顺序保持不变
arr.sort(function (a,b){
if (a > b) {
return 1;
}else if (a < b) {
return -1;
}else {
return 0;
}
});
转字符串
转字符串方法:将数组的所有元素连接到一个字符串中。 join() 通过参数作为连字符将数组中的每一项用连字符连成一个完整的字符串
// 字面量方法创建数组
var arr = [1,2,3,4,5,6,7,8,9,5,10];
// 转字符串
var str = arr.join("*");
var str = arr.join("");
console.log(str);
清空数组
//方式1 推荐
arr = [];
//方式2
arr.length = 0;
//方式3
arr.splice(0, arr.length);
7、字符串
字符串是不可变的。由于字符串的不可变,在大量拼接字符串的时候会有效率问题
// 定义一个字符串
// 特点:字符串不可变
// var a = "abc";
// a = 'cde';
// 大量拼接字符串时,会有效率问题
var sum = '';
for (var i = 1; i <= 1000000 ;i++) {
sum += i;
}
console.log(sum);
字符串方法
// 字符串是不可变的,大量字符串拼接的时候会有效率问题
var str = 'abc,def,ghd,efi,gh';
// 1.长度
str.length; // 所有字符的总数 无论是空格还不是空格
// 2. charAt() 返回指定位置的字符
// 参数是 index
str.charAt(2); // c
// 3. indexOf() 返回字符串的值的在字符串中首次出现的位置
// 没有就返回-1
str.indexOf('def'); // 3
// 4. concat() 链接两个或多个字符串
str.concat('klfgfg');
// 5. split 分给字符串成数组
str.split(',');
// 6. toLowerCase 转小写
// toUpperCase 转大写
var str1 = str.toUpperCase();
// 7. slice() 截取字符串 返回新的字符串
var str1 = str.slice(3,7); // 包3不包7
// 8. substr() 从开始位置截取指定长度
// 不写第二个参数 就是开始到结尾
var str2 = str.substr(3,7); // 从3位置 截取 长度为7的字符串
//9. substring 截取两个下标之间的字符
// 顺序可以反, 从小的开始大的结束
// 只有一个参数截取到最后
var str3 = str.substring(4,8);
字符串所有的方法,都不会改变原有字符串,二是返回一个新的字符串。
长度属性:str.length
字符串长度指的是一个字符串中所有的字符总数。
charAt() 方法可返回指定位置的字符。
• char:charator,字符
• at:在哪儿
• 参数是 index 字符串的下标。也是从 0 开始。
• 表示返回指定的下标位置的字符。
IndexOf() 可以返回某个指定字符串再字符串中首次出现的位置。
找到指定的字符串再原有字符串中第一次的位置的下标。如果字符串在原字符串中没有,返回-1.
concat() 方法用于连接两个或多个字符串。
• 参数比较灵活,可以是字符串、或者字符串变量、多个字符串。
• 生成的是一个新的字符串,原字符串不发生变化。
split() 方法用于把一个字符串分割成字符串数组。
• 参数部分是分割符,利用分割符将字符串分割成多个部分,多个部分作为数组的每一项组成数组。
• 如果分割符是空字符串,相当于将每个字符拆分成数组中的每一项。
toLowerCase() 把字符串转换为小写。
toUpperCase() 把字符串转换为大写。
• 将所有的英文字符转为大写或者小写。
• 生成的是新的字符串,原字符串不发生变化
slice() 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。
• 语法:slice(start,end)
• 从开始位置截取到结束位置(不包括结束位置)的字符串。
• 参数区分正负,正值表示下标位置,负值表示从后面往前数第几个位置,参数可以只传递一个,表示从开始位置截取到字符串结尾。
Substr() 可以在字符串中抽取start下标开始的指定数目的字符
语法:substr(start,howmany)
从开始位置截取到指定长度的字符串。
·start 参数区分正负。正值表示下标位置,负值表示从后往前数第几个位置。
·howmany 参数必须为正数,也可以不写,不写表示从 start 截取到最后。
注意:使用该函数之后,原有的长度会变短,如果是循环,需要用i--,来防止越过下一项
substring() 方法用于提取字符串中介于两个指定下标之间的字符。
• 语法:substring(start,end)
• 参数只能为正数。
• 两个参数都是指代下标,两个数字大小不限制,执行方法之前会比较一下两个参数的大小,
会用小当做开始位置,大的当做结束位置,从开始位置截取到结束位置但是不包含结束位
置。
• 如果不写第二个参数,从开始截取到字符串结尾