P2M2T1:数组
1. 数组概念
数组是一组有序的数据集合。
数组内部可以存放多个数据,不限制数据类型,并且数组的长度可以动态的调整。
创建数组:
var arr = [];
var arr = [1, null, undefined, 'text', [true, false]];
2. 获取数组元素
index:索引值/下标,从 0 开始。
选中数组内的元素:arr[1],可以对该元素直接进行赋值操作。
如果索引值超过了数组最大项,相当于这一项没有赋值,内部存储的就是 undefined,即返回 undefined。
3. 数组的长度
arr.length
常用:
获取数组的最后一项 arr[arr.length-1]
修改数组长度
- 对 arr.length 赋值
- 赋一个大于原来长度的值,数组会被拉长。拉长的部分是空的,读取表现为 undefined
- 赋一个小于原来长度的值,数组会被强制缩短。后面的数据会被直接删除,删除不可逆
- 对一个大于最大下标的项赋值。该项会被赋值,而中间部分没有数据,表现为 undefined
4. 数组的遍历
for (var i = 0; i <= arr.length-1; i++) {
console.log(arr[i]);
}
5. 数组应用案例
求一个数值数组各项的和,及其平均值
P2M2T2:函数
1. 函数概念
一次封装,多次调用
2. 函数的声明和调用
先得定义函数,才能调用。
function 函数名(参数){
封装的结构体
}
3. 函数的参数
接口:就是函数的参数,函数参数的本质就是变量,可以接收任意类型的数据
一个函数可以设置 0 个或者多个参数,参数之间用逗号分隔。
形式参数:定义的 () 内部的参数,叫做形式参数,本质是变量,可以接收实际参数传递过来的数据。简称形参。
实际参数:调用的 () 内部的参数,叫做实际参数,本质就是传递的各种类型的数据,传递给每个形参,简称实参。
调用函数时,发生了两次传递参数。 实际参数 → 形参 → 变量
4. 函数的返回值
return
-
函数内部如果结构体执行到一个 return 的关键字,会立即停止后面代码的执行。
-
return 后定义一个数据字面量或者表达式,作为返回值。
返回值可以当成普通数据参与程序,也可以作为一个普通数据赋值给一个变量,甚至赋值给其他函数的实际参数。
如果函数没有设置 return 语句,或者 return 后面没有定义值,该函数默认的返回值是 undefined
5. 函数表达式
将函数的定义(声明)赋值给一个变量。例如:
var foo = function fun(){
console.log(1);
}
此时,想调用函数fun(),需foo();
变量foo可以看作是函数fun,这也是一种函数的定义和调用方法。
6. 函数的数据类型
函数以一种特殊的数据类型 Function 存在,属于 Object
那么,作为一种数据类型,函数可以当作其他函数的参数或返回值。
7. arguments 对象
形参和实参的个数可以不同
-
实参少于形参,未指定的形参默认为undefined
-
实参多于形参,依照顺序写入形参。所有传入的实参都存储在函数内部的 arguments 类数组对象中。
以使用数组的方式使用 arguments
8. 函数递归
函数内部调用自身函数
实例:斐波那契数列(某一项的数值为前两项的和)
function fibo(a){
if (a===1 || a===2) {
return 1;
} else {
retrun fibo(a-1) + fibo(a-2);
}
}
9. 作用域
函数内部定义的变量,只能在函数内部访问,函数外部不能使用。即该变量的作用域为函数作用域。
同样的,{}块内部定义的变量的作用域限于块内。这称为,块级作用域。它在ES6被引入,暂且不表。
-
局部变量:定义在函数内部的变量,只能在函数作用域内部被访问到,在外面没有定义的。
-
全局变量:在整个 js 程序任意位置都能够被访问到。从广义上来说,也是一种局部变量,定义在全局的变量,作用域范围是全局。
变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁。
10. 参数和函数的作用域
函数也有作用域。
类似的,定义在某个函数内部的函数,也只能在该函数内部进行调用。
11. 作用域链
由于函数层层调用形成的层层包含的作用域。这样的一个由函数内指向函数外的链式结构,称作作用域链。
遮蔽效应: 程序要使用一个变量时,会沿作用域链从本层开始由内向外查找变量,更内层的变量会遮蔽外层的变量。
12. 不写 var 关键字的影响
不写 var 直接对一个“变量”赋值,也能实现定义、赋值,区别在于这样的变量声明相当于全局变量。
如果这样的声明在某个局部作用域内,且全局也有相同的标识符,那么全局变量会被其影响,局部变量污染全局变量。
要求:定义新变量时,必须加 var
13. 预解析和声明提升
JavaScript 解析器执行 JavaScript 代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:
- 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
- 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
- 先提升 var,再提升 function。
预解析后,根据新的代码顺序,从上到下执行代码。
注意:
- 经常地,变量的声明和赋值在同一语句,但预解析后只有变量的声明被提升。因此,在变量的声明赋值前调用变量,不会报错,会得到 undefined 值,因为执行调用时,变量尚未得到赋值。
- 而对函数来说,不论是在函数定义前还是后调用函数,能够正常调用,没有任何问题。
- 函数表达式进行的是变量声明提升,因此不能随意位置调用。
- 同名的变量和函数,因为预解析后函数提升在变量后面,所以该标识符存储的是函数。要求:避免变量和函数同名。
14. IIFE 即时调用函数
immediately-invoked function expression 即时调用函数表达式,也常被称为 自调用
调用函数时,()其实是运算符
函数名定义的形式不能实现立即执行自调用,函数使用函数表达式形式可以实现立即执行。例如:
var foo = function() {
console.log(1);
}();
原因是因为函数表达式定义过程中,将一个函数矮化成了一个表达式,后面加()运算符就可以立即执行。
另外,令函数参与一些运算也可以将其矮化为表达式,有:+、-、()、!。
IIFE 结构关住了函数的作用域,在结构外不能调用函数。
常用的 IIFE 函数是一次性的、随取随用的:
(function (a) {
console.log(a);
})(1);
P2M2T3:对象
1. 对象的概念
2. 对象字面量
字面量 {}
内部可以存放多条数据,以逗号隔开
键值对写法 k:v
var obj = {
k:v,
k:v,
k:v
};
3. 对象数据的调用和更改
对象名.属性名 或 对象名["属性名"]
调用方法则需要加上(),如:obj.fun();
在对象内部用 this 替代对象,即 this.prop
更改数据:调用并赋值 添加数据:直接添加并赋值 删除数据:delete obj.prop;
4. 使用 new Object() 方法创建对象
构造函数 Object(),与 new 搭配使用。
创建一个新的空对象:
var obj = new Object();
new 在执行时会做四件事情:
• new 会在内存中创建一个新的空对象
• new 会让 this 指向这个新的对象
• 执行构造函数 目的:给这个新对象加属性和方法
• new 会返回这个新对象
5. 工厂函数方法创建对象
需要创建多个类似的对象时,可将 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("Jack",12,true);
var p1 = createPerson("Rose",13,false);
6. 自定义构造函数创建对象
自定义一个创建具体对象的构造函数,替换 Object() 的角色。
(更为常用的方法)
function Person(name,age,sex) {
// 用 this 替代将来创建的新对象
this.name = name;
this.age = age;
this.sex = sex;
this.sayHi = function () {
console.log("hello");
};
// 不需要添加 return
}
// 用 new 关键字调用构造函数
var p1 = new Person("Jack",18,true);
var p2 = new Person("Rose",17,false);
7. 遍历对象方法
for in 循环专门用于对象,循环内即包含一个变量 k ,代表对象内从第一个开始的属性名。
for (var k in objName) {
console.log(objName[k]);
}
8. 简单数据类型和复杂数据类型
-
值类型:简单数据类型,基本数据类型,在存储时,变量中存储的是值本身,因此叫做值类型
-
引用类型:复杂数据类型,在存储时,变量中存储的仅仅是地址(引用),因此叫做引用数据类型
-
栈:存储简单数据类型,由操作系统自动分配释放,比如函数的参数值、局部变量的值等
-
堆:存储复杂数据类型(对象),一般由程序员分配释放, 若程序员不释放,由垃圾回收机制回收
9. 简单数据类型在内存中的存储
简单类型
变量地址存储的是变量值本身。
如果将变量赋值给另一个变量,是将内部的值复制一份给了另一个变量。两个变量对应两个地址。此时二者除值相等外,无相互关联
10. 复杂数据类型在内存中的存储
复杂类型:数组、函数、对象
变量存储的是指向原型的地址,位于 栈 中,而对象原型存储在 堆 中。
如果将变量赋值给另一个变量,相当于将地址复制一份给了新的变量,两个变量指向的地址相同。无论通过哪个变量更改了原型数据,两个变量的值都发生变化。
11. 内置对象
JavaScript 的对象包含:自定义对象、内置对象、浏览器对象
ECMAScript 的对象包括:自定义对象、内置对象
我们使用内置对象,只需知道对象中有哪些成员、有什么功能
12. 查阅 MDN
- 方法/函数的功能
- 参数的意义和类型
- 返回值意义和类型
- 写 demo 进行测试
15. 数组对象创建、判断数据类型
new Arra();
使用typeof()判断数组,只能得到object
要检测某个实例对象是否属于某个对象类型,比如数组、函数,需要使用 instanceof 运算符
比如:
console.log(arr instanceof Array);
它会返回 true 或者 false
16. 数组方法:首位操作方法
通过构造原型创建的数组,自带有方法可以调用,调用方法形如:arr.function();
-
toString()
数组转为字符串
-
push()
尾添:在数组末尾添加一个或多个元素
参数:可以是一个或多个,以逗号隔开
返回值:数组添加后的长度
-
pop()
尾删:删除数组的最后一项数据
不需要参数
返回值:删掉的那一项的值
-
shift()
首删:删除数组的第一项
不需要参数
返回值:删掉的那一项的值
-
unshift()
首添:在数组开头添加一个或多个元素
参数:一个或多个
返回值:添加后的数组长度
17. 数组首尾操作案例
将第一项移至最后一项:
arr.push(arr.shift());
18. 数组的拆分和合并
-
concat()
合并:将两个数组合并成一个新的数组,原数组不受影响。
参数:可以是一个数组字面量、数组变量、零散的值。
返回值:合并后的新数组
-
slice(start,end)
截取:从当前数组中截取一个新的数组,不影响原来的数组
参数:
-
start:开始的项,包括该项;
-
end:结束的项,不包括该项;
正值表示下标位置,负值表示从后面往前数第几个位置
开始、结束的前后顺序搞错的话,会返回空数组
仅传一个值表示start,截取至末尾
返回值:截取的数组
-
19. 数组的插入、替换、查找
-
splice(index, howmany, element1, element2, ...);
index:操作起始位置(下标,包含该元素)
howmany:删除元素的个数,为 0 即为插入功能
element:新插入的数据
无element参数,即为针对具体位置的删除功能;howmany参数为 0 ,即为插入;有删除有插入,即为替换。
-
indexOf() 查找数据在数组中最先出现的下标
lastIndexOf() 查找数据在数组中最后一次出现的下标
如果没找到返回-1
20. 数组的倒序和排序
-
reverse()
将数组倒叙排列(改变原数组)
参数:无
返回值:倒叙后的数组
-
sort()
默认将数组按照字符编码顺序,从小到大排序
参数:sortby(一个函数)
返回值:排序后的数组
21. 数组转字符串
-
join()
转字符串,默认逗号连接数组各个元素
参数:一个字符串,规定链接各元素的符号(要用引号包裹)
返回值:字符串
清空数组的方法:
arr = [];推荐arr.length = 0;arr.splice(0, arr.length);
22. 基本包装类型
我们知道,
基本类型的数据,没有属性和方法
对象类型的数据,有属性和方法
但是字符串也可以调用一些属性和方法,比如:str.slice(3,5);
基本包装类型:基本类型的数据在进行一些特殊操作时,会被暂时包装成一个对象,操作完成后再销毁此临时对象。
字符串也可以通过构造函数创建:
var str = new String();
这样得到的字符串是对象类型的。
销毁对象方法:
obj = null;
23. 字符串的特点
字符串是不可变的。
因此,在大量拼接字符串的时候会有效率问题。
而所有字符串的方法,都不会修改字符串本身,操作完成会返回一个新的字符串。
24-25. 字符串方法
-
length()
返回字符串中所有的字符总数
-
charAt()
参数:index,下标
返回值:该下标位置的字符
-
indexOf()
参数:string,要查找的子字符串(引号包裹)
返回值:指定的子字符串在原字符串中第一次出现的位置的下标,没找到返回-1
-
concat()
连接两个或多个字符串(数组、字符串通用)
参数:字符串
-
split()
把一个字符串分割成字符串数组,类比数组的方法join()
参数:分割符,一个字符串
例如
"a,b,c,d".split(',');得到的结果是一个字符串数组 ["a","b","c","d"]分割符是空字符串
''时,相当于将每个字符拆分成数组中的每一项,包括原字符串中的空格。返回值:字符串数组
-
toLowerCase() 转换为小写字符
toUpperCase() 转换为大写字符
字符串的三种截取方法:
-
slice(start,end)
截取(数组、字符串通用)
-
substr(start,howmany)
截取,适用于确定截取长度的情况
参数:start,开始位置下标,区分正负;howmany,截取的长度
-
substring(start,end)
参数:开始、结束位置,必须为正数,但不用区分大小的前后顺序