JavaScript数组,对象,函数

JavaScript 数组,对象,函数基本知识

数组

概念:数组(Array) 就是将多个元素(可以是不同类型)按一定顺序排列放到一个集合中,这个集合就称为数组

创建数组

//创建一个空数组 这是一种字面量定义数组的方法
var arr = [];
// 带数据数组
var arr = [1,"a",null,undefined,[2,3]];
// 格式创建 这是调用数组构造函数生成的数组
var arr = new Array();

获取数组元素

数组可以通过一个index(索引,下标)去获取某一个值,下表都是从0开始计数

var arr = [a,b,c];
//arr[0] 的值就是 a
arr[0] = "d"; 
// 可以改变数组 0 下表的值为 d
// 超出数组大小的下标
arr[3] 的值是 undefined
2 4 6 8 14 22 36 
f(n) = f(n-1) + f(n-2)

数组长度

数组的 length 属性可以取到数组的长度

arr.length

  • 最后一项下标值是(arr.length - 1)
  • 数组的长度不是固定不变的,可以通过一些方法改变
    • 增加数组长度:arr.length = 比原来大的值
      • 给一个比原来最大下标大的下标一个值: arr[maxIndex + i] = "asd" 也能增加数组长度
    • 缩短数组长度:强制给 arr.length = 比原来小的值 缩小后的,之前超出长度的值会被删除,且不可还原数据,使用时应特别注意

数组遍历

var arr = [3,45,63,123,53,15,21];
for (var i = 0 ; i < arr.length ; i++) {
	console.log(arr[i]);
}

函数

又被称为功能,方法;函数可以将一段代码封装起来,重复使用。

函数的声明和调用

函数声明

函数声明又称为函数定义,函数必须先定义才能使用

//函数声明
function 函数名(参数) {
	代码块
}
// 函数名的组成:不能以数字开头,对大小写敏感,其他参照参数的命名规范

注意:声明函数的时候,函数并不会执行;只有函数调用的时候,才会执行函数

函数调用
function fn(a) {
	consloe.log(a);
}
//调用
fn(1);
  • 函数调用也叫函数执行,调用时会将函数内部所有代码依次全部执行。

  • 函数内部语句执行位置与函数定义位置无关,与函数调用位置有关。

  • 函数可以一次调用,多次执行

函数的参数

函数参数的本质就是变量,可以接受任意数据类型,导致函数执行结果依据参数不同,结果也不同。

  • 一个函数可以设置多个参数,参数之间用逗号分隔。

  • 形式参数:定义的()内部的参数,本质是变量,可以接受实参传过来的值。

  • 实际参数:调用的()内部的参数,本质就是传递各种各样类型的数据,传递给每个形参,简称实参。

    优点:通过API接口说明,告诉我们需要传什么样的参数,能够实现什么样的功能。

函数的返回值

用函数内部的一个 return 关键字设置函数返回的关键值

  • 函数的内部如果执行到一个 return 关键字,会立即停止后面代码的执行。
  • 可以 return 后面写空格,空格后面可以定义任意一个字面量或者是表达式
  • 函数返回值可以继续参与程序

注意:如果函数没有设置 return 语句,那么函数有默认的返回值 undefined,有 return 但是后面没有跟任何语句或值,也是 undefined

函数表达式

函数表达式是函数定义的另一种方式。

定义方法:

// 第一种
var fn = function sub(a,b) {
	return a + b;
};
fn(1,2);  //执行
//第二种 也称为匿名函数  没有函数名
var fn2 = function (a,b) {
	return a - b;
};
fn2(2,1)

注意:调用函数表达式,是变量名()执行,不是执行函数名() ,注意结尾要加分号

函数的数据类型

函数是一种单独的数据类型 Function

var fn = function (){
	console.log(1);
}
console.log(typeof(fn())); // Function
  • 函数是一种数据类型,可以参与其他程序

arguments 对象

  • arguments 对象中存储了所有函数传递的实参,arguments 是一个伪数组,因此可以进行遍历。
  • 函数的形参跟实参个数可以不一致,所有实参的存在 arguments 中
throw new Error("sdad")  //模拟控制台报错信息

function test (a,b) {
	console.log(arguments);
} 
test(1,2,3,4,5);
// arguments 值是 [1,2,3,4,5];

函数递归

函数内部,通过函数名调用自身的方式,就是函数递归现象。

  • 递归次数太多容易出现错误:超出计算机的计算最大能力

典例:斐波那契数列

function Fn (a) {
	if (a === 1 || a === 2) {
		return 1;
	} else {
		return Fn(a - 1) + Fn(a - 2);
	}
	
}

作用域

变量可以起作用的范围。

  • 如果变量定义在一个函数内部,只能在函数内部被访问到,外部不能使用这个变量。函数就是变量定义的作用域
  • 任何一对 {} 中的结构体都属于一个块,在这之中定义的所有变量在代码块外都无法使用,称之为块级作用域。
  • 在 ES6 之前没有块级作用域的概念,只有函数作用域。
全局变量

定义在全局的变量,作用域范围是全局,任何位置都能访问到

局部变量

定义在函数内部,只有函数内部能访问,外部无法访问

  • 函数的参数也是局部变量,只能在函数内部访问

  • 如果在函数内部定义一个函数,那么这个被定义的函数也是局部的。

    function f1() {
    	function f2() {
    		console.log(1);
    	}
    	f2();
    }
    f1();
    f2(); //错误
    // f2 只能在f1作用域调用
    
作用域链和遮蔽效应

只有函数可以制造作用域结构,只要是代码,至少存在一个作用域,即全局作用域。凡是代码中有函数,这个函数就构成一个新的作用域。函数再套函数,又会产生新作用域。

就这样将所有的作用域列出来,可以有一个结构:函数内指向函数外的链式结构,称为作用域链。

// 全局
var a = 1;
function f1() {
	// 二级作用域
	var a = 2;
	function f2() {
		//三级作用域
		var a = 3;
		console.log(a);
	}
	f2();  
}
f1();


/*
	一级链: a = 1  f1()
	二级链: a = 2  f2()
	三级链: a = 3  console.log(a)
	
*/
遮蔽效应

程序在遇到一个变量时,使用作用域查找顺序,不同的作用域可能有相同的变量,会优先从本作用域查找,依次往外,直到找到第一个变量定义。整个过程会发生内层变量遮蔽外层变量,这就是遮蔽效应。

不写 var 关键字的影响

在函数内部定义变量要是不加 var 关键字,那么变量就会被定义成全局变量,如果存在这个全局变量,就会改变全局变量的值,造成全局变量污染。

var a = 1;
function f1() {
	a = 2;
}
console.log(a);

预解析和声明提升

预解析
  • JavaScript 代码执行是由浏览器中的 JavaScript 解析器来执行的,分为俩个过程:预解析过程 和 执行代码过程。
  • 预解析过程:
    • 把变量声明提升到当前作用域最前面,只会提升声明,不会赋值。
    • 把函数声明提升当当前作用域最前面,只会提升声明,不会调用。
    • 先提升var 再提升 function
  • 执行代码过程:在预解析之后,按照新的代码顺序,从上往下执行
//正式代码
console.log(a);
function fn(){
	console.log(2);
}
var a = 3;
fn();
// 预解析
var a;   //变量声明提升
// 函数声明提升
function fn(){    
	console.log(2);
}
console.log(a);
a = 3;
fn();
变量声明提升

在预解析过程中,所有的变量声明提升到作用域组上面,将来代码执行,按照先后顺序执行新的顺序。

注意:变量声明提升,只提升声明,不会赋值,因此 js 中会出现一种现象,在前面调用后定义的变量,不会报错,但是值是 undefined

函数声明提升

在预解析过程中,所有定义的函数,都会将声明提升到当前作用域的最上面,将来代码执行,按照新的顺序。

因此,js中,在前面调用后面定义的函数,不会报错,而且能正常执行函数内部的代码

函数表达式的声明提升

在预解析的过程中,函数表达式进行的是变量声明提升,而不是函数声明提升。因此,这种定义在js中,如果在声明后调用函数,会报错

定义函数时,最好还是使用 function 关键字进行定义

提升顺序

先 var 后函数

  • 假如变量名和函数名相同,那么按照提升顺序来看,后提升的函数名,会覆盖先提升的变量名。
  • 尽量不要书写相同的标识符给变量名或函数名,避免出现覆盖
//正常代码书写
function fn(){
	console.log(1);
}
var fn = 2;
console.log(fn);
fn();
// 预解析
var fn;
function fn(){
	console.log(1);
}
//console.log(fn)  
fn = 2;
console.log(fn)  //2
fn();  //报错

IIFE 自调用函数

IIFE:immediately-invoked function express,叫做即时调用的函数表达式,也叫自调函数,表示函数在定义时就立即调用。

  • function 定义的函数,无法实现立即调用,函数表达式声明的函数可以实现;想要实现 IIFE 必须将函数声明矮化成表达式。
  • 函数矮化方式:给函数前面增加一些运算符:+,-,(),!
  • IIFE 结构可以关主函数的作用域
  • IIFE 最常用 () 运算符,可以不写函数名
//1 报错,不是正确形式
function fn() {
	console.log(1);
}();
//2 正确形式,立即执行
var fn = function () {
	console.log(1);
}();
//3  正确形式,立即执行 
(function fn() {
	console.log(1);
})();
//4 正确形式,立即执行 + - !
+ function fn() {
	console.log(1);
}();

对象

对象可以自定义名称,存储一系列无序的相关数据。

对象的概念

现实生活中:万物皆对象,对象是一个具体的事物,一个具体的事物就会有行为和特征。

JavaScript中的对象:就是对生活中对象的一个抽象,一个对象就会有属性和方法。

对象的创建

对象字面量创建

创建一个对象最简单的方式是使用对象字面量赋值给变量。内部可以存放多条数据,数据与数据之间用逗号分隔,最后一个不加逗号。每条数据都采用键值对写法,可以是任意类型的数据。

var girl = {
	name : "小李",
	sex : "female",
	age : 20,
	SayHi : function () {
		console.log("ni hao");
	}
};
区分方法和属性

属性:对象的特征描述,一般是名词,相当于定义在对象内部的变量。

方法:对象的行为和功能,一般是动词,定义存在于对象中的函数。

对象数据的调用与更改

用对象的变量名打点调用某个属性名,得到属性值;

在对象内部用 this 打点调用属性名,this 替代对象;

用对象变量名后加 [] 调用,[] 内部是字符串格式的属性名。

调用方法时,需要在方法名后加 () 执行。

var girl = {
	name : "小李",
	sex : "female",
	age : 20,
	SayHi : function () {
		console.log("ni hao");
	},
	ChangeAge : function () {
		this.age = this.age + 1;
	}
};
//1 调用属性
console.log(girl.name);
//2 调用属性
console.log(girl["name"]);
//3 改变属性值
girl.name = "小王";
//4 增加对象属性
girl.weight = 140;
//5 调用对象方法
girl.SayHi();
//6 删除一条属性
delete girl.weight;
通过 new Object() 方法创建一个对象

Object() 构造函数,是一种特殊的函数。主要用来创建对象时,初始化对象,即为对象成员变量赋初始值,与 new 运算符一起使用在创建对象的语句中。

  • 构造函数用于创建一类对象,首字母要大写。
  • 构造函数要和 new 一起使用才有意义。
// 创建
var girl = new Object();
girl.name = "张飞";
girl.age = 18;
girl.sex = "female";
girl.SayHi = function () {
	console.log("你好");
}
new 在执行时会做的四件事情
  • new 会在内存中创建一个新的空对象。
  • new 会让 this 指向这个新对象
  • 执行构造函数 : 给这个新对象加属性和方法
  • new 会返回这个新对象
工厂函数创建对象

如果要创建多个类似的对象,可以将创建对象的过程封装起来,将来调函数就能创建一个对象,简化代码

function CreatePerson (name,age,sex) {
	var person = new Object();
	person.name = name;
    person.age = age;
    person.sex = sex;
    person.SayHi = function () {
        console.log("你好");
    }
    return person;
}
var p1 = CreatePerson("lisi",18,"female");
自定义构造函数方法创建对象

自定义一个创建具体对象的构造函数,函数内部不需要new一个构造函数的过程,直接使用 this 代替对象进行属性和方法的书写,也不需要return一个返回值

注意:构造函数名称,首字母必须大写,区别于其他普通函数

// 自定义构造函数
function Person (name,sex,age) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.SayHi = function () {
    	console.log("nihao");
	}
	// 不需要return
}
// 创建对象
var p1 = new Person("liz","nv",19);
console.log(p1);
遍历对象

使用 for…in,内部会定义一个 k 变量,循环时从第一个对象的属性名 或 方法名开始,一直到最后。

// 自定义构造函数
function Person (name,sex,age) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.SayHi = function () {
    	console.log("nihao");
	}
	// 不需要return
}
// 创建对象
var p1 = new Person("liz","nv",19);
console.log(p1);
// 遍历对象
for (var k in p1) {
    console.log(k + "的属性值是" + p1[k]);
}
简单数据类型和复杂数据类型

简单数据类型又叫基本类型,也称为值类型:数字,字符,布尔,null,undefined…这些都是。

复杂数据类型又称为引用数据类型:数组,function,对象都是复杂数据类型。

区别:值类型,变量在存储时,存储的是值;引用类型在存储时,存储的是地址

简单数据类型在内存中的存储
  • 变量中存储的是值本身,当把值赋值给另一个变量时,也是值赋值,值的改变互不影响。
复杂数据类型在内存中的存储
  • 如果将复杂类型的数据赋值给一个变量,复杂数据类型会在内存中创建一个原型,而变量中存储的是指向数据的一个地址,如果将变量赋值给其他变量,赋值的是变量中存储的地址,俩个变量存储的地址相同,当其中一个变量通过地址修改了原型数据,另一个变量通过地址取得的数据也会发生改变。
// 自定义构造函数
function Person (name,sex,age) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.SayHi = function () {
    	console.log("nihao");
    }
}
// 创建对象
var p1 = new Person("liz","nv",19);
var p2 = p1;
p1.name = "ers";
console.log(p1);
console.log(p2);
内置对象

JavaScript 的对象包含三种:自定义对象,内置对象,浏览器对象

ECMAscript 的对象:自定义对象 内置对象

内置对象就是 JavaScript 自带的一些对象:Math 等。

内置对象可以使用 MDN 网站来学习

Math 对象
  • Math.PI 圆周率
  • Math.random() 生成随机数 0-1 之间的浮点数
  • Math.floor() 向下取整
  • Math.ceil() 向上取整
  • Math.round() 取整,四舍五入
  • Math.abs() 绝对值
  • Math.max() 取一组数中的最大值
  • Math.min() 取一组数中的最小值
  • Math.sin() 正
  • Math.cos() 余
  • Math.pow(a,b) a 的 b 次方
  • Math.sqrt() 求平方根
数组对象的创建,判断复杂数据类型的方法
// 数组对象的创建
var arr = new Array(1,3,56);
判断复杂数据类型

instanceof : 检测某个实例是否是某个对象类型。

返回值:true / false

var arr = new Array(1,3,56);
console.log(arr instanceof Array);  //true
数组的常用方法
  • push() 在数组末尾添加一个或多个元素,返回添加后的数组长度

  • unshift() 在数组的开头添加一个或多个元素,返回添加后的数组长度

  • pop() 删除数组的最后一项,返回删除项

  • shift() 删除数组的第一项,返回删除项

  • concat() 将俩个数组合并成一个新的数组,原数组不受影响。参数可以是数组字面量,数组变量,零散的值。

  • slice(start,end) 从当前的数组中截取一个新的数组,不影响原来的数组,返回一个新的数组(从 start 到 end (不包含最后一位元素))

    • 参数区分正负,正值表示下标位置,负数表示从后往前数第几个位置,参数只传一个时,表示从开始位置到最后全部。
  • splice(index,howmany,e1,e2,…) 用于插入,删除或替换数组的元素,删除项返回值是删除的元素数组。

    • index : 操作元素的开始位置
    • howmany:操作元素的个数,插入元素时,个数是0
    • e:元素(插入或替换元素)
  • 位置方法

    • indexOf() 查找数据在数组中最先出现位置的下标,不存在时返回 -1
    • lastIndexOf() 查找数据在数组中最后出现位置的下标,不存在时返回 -1
  • reverse() 倒叙排列数组

  • sort() 排序

    • 默认情况下,根据字符编码(ASCII) 大小进行排序,从小到大。

    • 想要根据数值大小进行排序,必须添加 sort 的比较函数参数; 根据 a 和 b 的判断条件作为条件。

      var arr = [1,2,3,4,10,20,30];
      arr.sort(function (a,b) {
          if (a > b) {
          	return 1;   // a 排 b 的后面
          } else if (a < b) {
         		return -1;  // a 排 b 的前面
          } else {
          	return 0;   // 不做改变
          }
      });
      console.log(arr);
      
  • 数组转字符串

    • toString() 数组转成字符串用逗号链接。
    • join(链接字符) 参数为链接字符,通过链接字符转为字符串。
  • 清空数组

    • arr = []
    • arr.length = 0
    • arr.splice(0,arr.length)
基本包装类型

基本数据类型没有属性和方法,那么为什么一个字符串可以使用截取方法呢

var str = "abcdef";
var str2 = str.slice(2,5);
console.log(str2);

字符串在使用方法时,被转换成了 String 类型的临时对象,用完后就销毁了

var str = new String("abcdef");
var str2 = str.slice(2,5);
console.log(str2);
str = null;   //销毁
字符串

字符串的特点:字符串是不可变的,当一个字符串有初始值后,重新赋值时,原有的值会占据一块内存,而新值会重新开辟一块内存,直到 js 解析器用完,进行垃圾回收会清理内存。因此,在大量拼接字符串时,会有效率问题。

字符串所有的方法,都不会修改字符串本身,操作完成会返回一个新的字符串。

字符串方法:

  • charAt(下标) 返回指定位置的字符串
  • indexOf() 返回某个指定的字符串在字符串中首次出现的位置,没有就返回-1
  • concat() 拼接另一个字符串
  • split() 把一个字符串分隔成数组,参数是分隔符
  • toLowerCase() 把字符串转小写,生成新字符串,原来字符串没有变化
  • toUpperCase() 把字符串转大写,生成新字符串,原来字符串没有变化
  • slice()
    • 参数: slice(st , ed) 开始位置,结束位置,若是只有一个参数,那就是从开始位置到字符串末尾
    • 参数区分正负,正数表示下标位置,负数表示从后往前第几个
  • substr() 在字符串中抽取 st 下标开始到指定长度的字符串
    • substr(st , howmany) st : 开始位置 , howmany : 截取长度
    • start 区分正负,正数表示下标位置,负数表示从后往前第几个
    • howmany : 参数必须是正数,不写表示,从start 截取到最后
  • substring() 用于提取字符串,介于俩个下标之间的字符。
    • substring(start , end)
    • 参数只能为正数,俩个参数大小不限制,系统会根据大小自动来选取开始位置和结束位置,如果不写第二个参数,那就是从开始提取到末尾。

字符串时,会有效率问题。

字符串所有的方法,都不会修改字符串本身,操作完成会返回一个新的字符串。

字符串方法:

  • charAt(下标) 返回指定位置的字符串
  • indexOf() 返回某个指定的字符串在字符串中首次出现的位置,没有就返回-1
  • concat() 拼接另一个字符串
  • split() 把一个字符串分隔成数组,参数是分隔符
  • toLowerCase() 把字符串转小写,生成新字符串,原来字符串没有变化
  • toUpperCase() 把字符串转大写,生成新字符串,原来字符串没有变化
  • slice()
    • 参数: slice(st , ed) 开始位置,结束位置,若是只有一个参数,那就是从开始位置到字符串末尾
    • 参数区分正负,正数表示下标位置,负数表示从后往前第几个
  • substr() 在字符串中抽取 st 下标开始到指定长度的字符串
    • substr(st , howmany) st : 开始位置 , howmany : 截取长度
    • start 区分正负,正数表示下标位置,负数表示从后往前第几个
    • howmany : 参数必须是正数,不写表示,从start 截取到最后
  • substring() 用于提取字符串,介于俩个下标之间的字符。
    • substring(start , end)
    • 参数只能为正数,俩个参数大小不限制,系统会根据大小自动来选取开始位置和结束位置,如果不写第二个参数,那就是从开始提取到末尾。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值