P2M2:

188 阅读14分钟

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 代码的时候,分为两个过程:预解析过程和代码执行过程

预解析过程:

  1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
  2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
  3. 先提升 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

  1. 方法/函数的功能
  2. 参数的意义和类型
  3. 返回值意义和类型
  4. 写 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)

    参数:开始、结束位置,必须为正数,但不用区分大小的前后顺序