JS目录
- 前言
- 一、JS的介绍
- 二、变量和数据类型
- 三、数据类型的转换
- 四、常见运算符
- 五、分支语句
- 六、循环语句
- 作用域
- 面向对象OOP:
- 七、函数
- 八、对象
- 九. 标准库
- 十、类
- 十一、数组
- 1.1 一维数组
- 1.2 数组的方法
- 1.3 数组的遍历
- 1.4 数组的常用方法
- 1. join("分隔符")
- 2. concat(arr1,arr2,...) 合并多个数组
- 3. reverse() 颠倒数组元素
- 4. slice(startIndex,~~endIndex~~ ) 截取数组
- 5. forEach(function(item,index){}) 遍历数组
- 6. map(function(item,index){}) 遍历返回新数组
- 7. filter(function(item,index){return boolean}) 过滤数组
- 8. reduce(function(a,b){return num}) 依次遍历数组
- 9. sort(function(a,b){return num}) 数组排序
- 10. some(function(item,index,arr){return boolean}) 查询某一个元素是否符合(存在)条件
- 11. every(function(item,index,arr){return boolean}) 所有元素符合某个条件返回true
- 12. indexOf(element) 查看元素从前往后在数组中索引
- 13. lastIndexOf(element) 查看元素从后往前在数组中的索引
- 14.数组的链式操作
- 1.5 数组的深浅拷贝
- 十二、JSON
前言
一、JS的介绍
java script 脚本语言(简称js), 主要运行在浏览器上,主要用于控制html元素合作css样式,实现网页的各种交互效果。
js是前端的编程语言,是前端最核心的技术。js编程语言语法不难,主要是编程思维需要大量练习才能形成。
js语言的特点:
1.脚本语言: 指比较简单的,语法没有那么严格,并且不需要编译,是直接解释执行的编程语言(代码一般解析一边 执行)。
2.简单紧凑: 采用弱类型的变量类型,对使用的数据类型没有做出严格要求(声明变量不需要声明数据类型,系统自动识别)。
3.动态性: 采用事件(动作)驱动,不需要经过web服务器可以对用户的输入做出响应(js直接运行在浏览器上)
4.跨平台性: 不依赖操作系统,只要系统有浏览器,就可以运行js
5.安全性: 不允许访问本地的硬盘\对网络文档进行修改和删除等,只能通过浏览器实现信息浏览器或者交互特性。
6.大小敏感: 严格区分字母大小写
7.空格与换行: 程序会忽略程序中的换行,空格或制表符,除了一些表达式的一部分。
8.面向对象的编程语言
1.1网页引入js的方式
js只能运行在浏览器上,通过html的script 标签引入js代码,script标签可以写在html的任意位置,可以是在head或者body里。
1.script脚本标签
2.script 脚本引入外部js文件
// 1.script脚本标签 HTML5省略type属性,默认就是js脚本语言
<script></script>
//2.script 脚本引入外部js文件,src属性引入创建的01.js(src属性值可以是相当路径或者一个网络地址)
<script src="./js/01.js"></script>
script脚本虽然可以写在任意位置,由于html解析元素是由上到下,并且遇到script脚本会先执行js脚本,然后再往下解析。
推荐把script脚本写在body 结束标签之前。
1.2 编写JavaScript注意事项
- script必须是双标签元素
- 引入, 不要在里面写内容
- type属性, 省略
- 加载顺序 (后面覆盖前面)
- 严格区分大小写
数字,字母(大写,小写),下划线、-
不能以数字或者-线开头
见名知意
小驼峰 aNameZhangSan
下划线法 a-name-zhang-san
1.3 浏览器交互方式
- document.write 写入到浏览器上
- console.log 控制台输出
- alert 弹提示框:alert会显示括号里面的内容,会暂停alert后面的js代码执行
- prompt 输入内容:可以返回用户输入的内容
<script>
// document 是表示整个网页的,write就是向网页写入内容
document.write("hello js")
//在控制台输出日志(f12 打开发工具)
console.log("输出内容")
</script>
1.4 script 脚本异步加载 defer
默认script标签是同步加载,script标签会阻塞html元素的解析。浏览器解析的时候遇到script标签,会加载对应的js代码,等js代码加载完成,再往后面执行。
defer: script标签添加defer属性,实现异步加载js,浏览器解析到script标签会请求对应的js代码,一边请求,一边往后解析元素。相对于是同时加载js和解析元素,渲染速度更快。defer 是对src引入外部js文件有效。
加了defer属性的js文件是按引入顺序执行。
<script src="./js/02.js" defer></script>
二、变量和数据类型
1 变量的提升
js是解释型的语言(边编译,边执行),但是浏览运行js的时候会对js进行预编译,然后再计算进行运行。
浏览器预编译js的时候会先把var声明的所有变量提到js代码的最顶部。
console.log(age) // 变量未用var关键词声明就使用,会报错
console.log(name1)
var name1 // 浏览器预编译的时候会把var name1提升到代码最顶部
var age=10 // 把 var age提升顶部,并不会把赋值语句提升
b();
var a = 'zhangsan';
function b() {
console.log(a)
}
执行步骤:
1.先执行 var a
2.执行 声明函数 b()的调用
3.再执行变量赋值 a = ‘zhangsan’
1.1.变量的定义和命名
- 分成两个步骤:
- 变量声明
- 变量赋值
// 创建变量,var关键词后面可以给自定义的任意单词
var apple;
// 给变量赋值,把一个具体的值给变量
apple = "苹果"
// 在js代码中使用变量,在js代码解析的时候会显示变量引用的值
document.write(apple)
document.write(apple)
//声明变量并赋值,声明变量后直接赋值
var test1 = "测试1"
//可以同时声明多个变量用 , 区分
var name1,name2,name3;
name1 = 1;name2 = 2;name3 = 3;
变量的命名规则:
- 以字母,$ , _ 开头,后面可以是字母,数字,$,_,-的组合
- 变量要有一定的语义,如果是多个单词组成的变量需要驼峰命名法
大驼峰: 所有单词的首字母都大写 var BackgroundColor;
小驼峰: 从第二个单词开始,首字母大写,通常用小驼峰。 var backgroundColor; - js变量名是严格区分大小写
- js变量名不能用js内置关键词(var,if,else,switch…)
注意:
- 如果一个变量未声明就使用的话, 那么会报错
- 如果一个变量有声明, 但是没有赋值, 那么值undefined
- 不使用var也可以声明变量(不推荐)
1.2 常见的数据类型(8种)
给变量赋的值就叫数据,js的每一个值都属于一种数据类型。js有8中数据类型(包含ES6新增的数据类型).
由于值一般是赋值给变量,所以数据类型一般是指变量的数据类型。
- String (字符串)
- Number (数字 --包含整数、小数、数组)18, 1.75
- Boolean (true(是), false(否))
- Undefined 找不到
- Null 空
- Object 对象
- Bigint 大的数据
- Symbol 独一无二的数据
// 字符串 String
var a = '字符串';
console.log(typeof a);//查看字符串类型 string
// Uumber
var age = 18;
// Boolean
var bool = true;
// Undefined --以下打印都是 undefined
var under = undefined;
var und ;
console.log(under,und);
console.log(typeof under,typeof und);
// NUll
var n = null;
console.log(n) //null
console.log(typeof n) // object
// Object
var obj = {
name: 'Amy',
age: 18
}
// 大数据
// var big = 234567890123456789012345678901234567890n;
// Symbol
var s1 = Symbol();
var s2 = Symbol();
console.log(s1 === s2); // false
1.2.1 String 型
文本类型,必需要单引号或者双引号包裹。
单引号和双引号没区别,都是表示字符串。
如果字符串中包含双引号,外面只能用单引号包裹var name1 = ‘zhangsan""’
如果字符串中包含单引号,外面只能用双引号包裹var name2 = “li si’'”
- 字符串补充
- 长度: length
- +拼接字符串
// 1.双引号
var str = "双引号"
// 2.单引号
var str = '单引号'
// 3.模版字符串
var temp = `英文状态下,~`
// ${str}在模版字符串中添加变量
temp = `英文状态下,~${str}`
temp = `英文状态下,~${1 + 2}`
console.log(temp)
// 引号之间的嵌套关系
var say = 'Welcome "China"';
console.log(say); // Welcome "China"
var say = "Welcome 'China'";
console.log(say); // Welcome 'China'
//转义符
var say = 'Welcome'+ '\n China';
// 字符串属性和方法
var len = '字符 串长度'
console.log(len.length) //6 空格也会占一个字符
// 字符串拼接:只有两个都是数字型的时候才是加法,其它组合都是字符串拼接
var num = 1;
var str = '99'
console.log(num + str); //199
var num = 1;
var str = 99
console.log(num + str); //100
1.2.2 Number 型
就是数字,包括整数,小数,正数(js的正数省略+),负数。不能用单引号’ '或者双引号包裹" "
// 基础
var age = 18 // 整数
var height = 1.68 // 小数
// 特殊数值
var num = Infinity
var num2 = 1 / 0
console.log(num, num2)
// NaN: not a number (不是一个数字)
var num3 = 12 + '4' // 124
num3 = 12 - '4' // 8
num3 = 12 * '4' // 48
num3 = 12 / '4' // 3
num3 = 12 / 'abc'
// 进制表示方式
var num4 = 100 // 十进制
var num5 = 0x100 // 十六进制
var num6 = 0o100 // 八进制
var num7 = 0b100 // 二进制
// 数字可以表示范围
var max = Number.MAX_VALUE
var min = Number.MIN_VALUE
console.log(min,max) //5e-324 1.7976931348623157e+308
1.2.3 Boolean 类型
该类型只有两个值,true和false。true表示真(成立),false表示假(不成立)。主要用于条件判断。
1.2.4 Undefined 和 Null类型
- undefined:
- undefined 表示未定义,由于变量声明以后没有赋值。变量就是undefined的类型,默认值也是undefined
- Null:
- 对象类型初始化时, 可以赋值为null
- null 表示空值,null表示一个空的内存地址,一般用于清空对象。
undefined是未赋值的数据类型,null是赋的一个空值给变量
1.2.5 Object类型
对象数据类型(对象数据类型都引用数据类型),主要是各种值的组成集合,可以细分为:
- 狭义的对象(object)
- 数组(array)
- 函数类型(function)
var person = {
name: 'Amy',
sex: '女',
age: 21
}
console.log(person); // {name: 'Amy', sex: '女', age: 21}
// 取到对象中的某一个属性
console.log(person.name); // Amy
//赋值
person.age = 23
console.log(person.age); // 23
1.3 typeof 查看数据类型方法
查看变量的数据类型可以用typeof(变量)返回对应变量的数据类型
- 获取一个变量的类型
- typeof是操作符, 不是一个函数
document.write(typeof(num4)) // es6增加的查看类型方法
document.write(typeof num4) // 查看类型的关键词
var height = '180';
console.log(typeof height); //string
1.4 错误检查 try-catch
//检查错误
try {
console.log(c); // c is not defined
} catch (error) {
console.log(error);
}
//断点,用于调试
debugger;
三、数据类型的转换
1.1 String类型转换
- 隐式转换:(常用)
+操作, 只要有一个是字符串类型, 另外一个就会自动转成字符串类型 - 强制(显示)转换:
String() 把任意数据类型转字符串
toString() 数值类型转字符串可以用该方法,数值类型才有toString
// 隐式转换(使用的非常多)
var num1 = 1
var num2 = 3 + ''
console.log(num1 + num2); // 13
console.log(typeof(num1 + num2)); //string
// 显式转换: 强制转换
var num1 = String(1)
var num2 = 4
console.log(num1 + num2); // 14
console.log(typeof(num1 + num2)); //string
1.2 Number类型转换
- 隐式转换:
+数值运算符把其他类型转为数值类型,转失败则是NaN - 强制(显示)转换:
Number()
parseInt() 把数据转为整数,直接去掉小数点,其他和Number()一致
parseFloat() 其他类型转为数值类型,保留小数,和Number()一致
// 1.将字符串转换为数字
// 隐式
var num1 = '12'
var num2 = '3'
var res = num1 + num2; // 123
res = num1 * num2; // 26
res = num1 - num2; // 9
res = num1 / num2; // 4
console.log(typeof res, res) // Number 4
// 显示转换
var num3 = Number(num1)
console.log(typeof num3,num3); // number 12
// 2.其它类型转化成数字的规则:
console.log(Number(undefined)); // NaN
console.log(Number(null)); // 0
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number('true123')); // NaN
console.log(Number('123true')); // NaN
console.log(Number(' 123 ')); // 123
console.log(Number(' ')); // 0
a1 = parseInt("1.222") // 1
a1 = parseInt("a") // NaN
a1 = parseFloat("3.22") // 3.22
a1 = parseFloat("a") // NaN
1.3 Boolean类型转换
- 隐式转换:
直观上为空的内容, 转成Boolean类型就是false
0/" "/undefined/null/NaN
其他的值是true
123… - 显示转换:
Boolean()
在条件判断语句里面如果条件只有非boolean数据类型,会自动转为boolean类型,和Boolean()转的一致
if(null){} // null会直接转为false
// 隐式转换 -->通常跟分支语句一起使用
// 0 代表 false,其它代表 true
var str = true // true
var num = 1 // true
var str = 'zzz' // true
str = '' // false
str = ' ' // true
if (str) {
console.log('YES')
}
// 显式转换
var num1 = 123
console.log(Boolean(num1)) //true
// 其它类型转化成 Boolean
console.log(Boolean(undefined)) // false
console.log(Boolean(null)) // false
console.log(Boolean(NaN)) // false
console.log(Boolean('0')) // true
四、常见运算符
1.1 算术运算符
- +加法运算
- -减法运算
- *乘法运算
- /除法运算
- % 取余运算
- ** 指数运算(平方) ES7新增
// 运算符 + 加 、 -减 、 * 乘、 / 除
var num = 10
var num2 = 5
console.log(num + num2) // 15
console.log(num - num2) // 5
console.log(num * num2) // 50
console.log(num / num2) // 2
// %: 取余数
console.log(9 % 5) // 4
// **: 2**3 2的三次方
console.log(2**3); // 8
console.log(Math.pow(2,4)); // 16
1.1.1 + 数值运算符
- +数值运算符,可以表示一个正数,是一个一元运算符,可以把非number数值类型转为number类型
- -负值运算符,表示一个负数。可以把非number数值类型转为number类型,并带上-
//+数值运算符
console.log(+10)
console.log(+true) // 转为数字1
console.log(+false) // 转为数字0
console.log(typeof(+"34"),+"34") //转为number类型
console.log(+"abc") // 不能转为数字则是NaN值
//-数值运算符
console.log(-10) // 表示负数
console.log(-true) // 转为-1
console.log(-false) // 转为-0
console.log(typeof(-"34"),-"34") //转为number类型,34
console.log(-"abc") // 不能转为数字则是NaN值
1.2 赋值运算符
- = 赋值运算符
- +=、*=、/=、-=
// = 赋值运算符
var num3 = 123
console.log(num3) // 123
// 链式赋值
var num4 = num5 = num6 = 123
console.log(num3, num4, num5, num6) // 123 123 123 123
// *= += -= /=
var num = 10
num *= 10 // ---> num = num * 10 ---> 100
num += 10 // 20
num -= 10 // 0
num /= 10 // 1
num **= 2 // num 的平方 --> 100
console.log(num)
1.3 自增 ++ /自减 - -
- ++和- -
- 位置的区别
- i++/i-- 在后是:先赋值,再递增/递减
- ++i/–i 在前是:先递增/递减,再赋值
var index = 5
// 自增
index ++
console.log(index) // 6
// 自减
index --
console.log(index) // 5
// 自增/自减符号可以写在前面,也可以写在后面
-- index
console.log(index) //4
++ index
console.log(index) // 5
// 在运行表达式: ++、-- 写在数字后面先计算,再加加
// ++、-- 写在数字前面先加加,再计算
var res = 20 + index++
console.log(res, index) // 25 6
var res = 20 + ++index
console.log(res) // 27
1.4 比较运算符
优先级: ++或-- 大于 * / 大于 +或-
var num = 5;
// 第一步算 ++num 第二步再算3* 最后+2
var res = 2 + 3 * ++num
console.log(res) // 20
1.5 逻辑运算符
逻辑运算符产生的结果是一个布尔值(boolean数据类型)
1.5.1 == 和 === 的区别
- ==:比较两个值是否相同(只比较两个数据的值是否相同,不会比较数据类型),如果相同返回true,不相同返回false
- 在类型不相同的情况, 会对运算元进行隐式的转换
- 大部分情况下, 都是转成数字类型 toNumber()
- 对象类型相对比较特殊, 一般返回false
- ===: 比较数据类型和值,都相同返回true,不相同返回false
- 先比较类型, 类型不一致, 直接返回false
- 严格相等
var a = 10
var b = '10'
// == 运算符,类型不同时,会将运算元(变量,数)转换成Number的值,再进行比较
console.log(a == b) // true
// === 运算符,类型不同时,直接返回false
console.log(a === b) // false
//"33"被转为了number类型,和后面的33数值,类型都一致相同
console.log(+"33" === 33) // true
// undefined 它自己是一种单独类型
// null 会被默认成为一个对象或者null做比较
console.log(undefined == 'undefined') // false
console.log(null == 'null') // false
// Symbol每一个都是唯一的
console.log(Symbol() == Symbol()) // false
1.4.2 != 和 !== 的区别
和上面类似
var a = 10
var b = '10'
console.log(a != b) // false
console.log(a !== b) // true
1.4.3 数学里面的 >, <, >=, <=
console.log(13>10) // 13大于10 条件成立返回true
console.log(12<=12) // 12小于等于12条件成立,返回true
1.4.4 运算符 逻辑&&、||、!
&&:与运算符左边如果是false,不会执行右边的语句,如果是true会执行右边的语句
||:或运算|| 符号两边只要有一个是true,就返回true,只有同时是false才返回false
!:非运算 !, 取boolean的相反值
var height = 180
var age = 20
// ||逻辑或, 有一个条件满足就成立
if (height <= 175 || age <= 20){
console.log(true) // true
}
// &&逻辑与, 有一个条件不满足就不成立
if (height <= 175 && age <= 20){
console.log(true)
} else {
console.log(false) // false
}
// !逻辑非, 原来条件取反
console.log(!true) // 不是true,返回的是false
console.log(!false) // 不是false, 返回的是true
console.log(!(15!=="15")) //false
console.log(!!(15>12)) // 两次取反,其实就原状态。
短路:
|| 前面满足就不执行后面内容,后面短路
&& 前面不满足就不执行后面内容,后面短路
//&&
false && console.log("b") // 左边是false 右边语句不会执行
true && console.log("x") // 左边是true,右边语句会执行
console.log(true && true) // 只有两边是true才返回true
console.log(true && false) // 只有一个false,就返回false
console.log(13>12 && 13<=11) // 与运算两边有条件运算,先进行条件运算返回对应的bool值,再进行与运算
// ||
false || console.log("y") // 左边false会执行右边语句true ||
console.log("z") // 左边是true,不会执行右边的语句
// !
console.log(!true) // 不是true,返回的是false
console.log(!false) // 不是false, 返回的是true
console.log(!(15!=="15")) //false
console.log(!!(15>12)) // 两次取反,其实就原状态。
五、分支语句
按顺序从上到下 依次执行
块级作用域
使用{ } 来创建代码块,可以用来分组,同一个代码块中的代码就是同一组代码,要么都执行,要么都不执行
var 和 let 的区别
let声明的变量具有块作用域(在代码块中声明的变量无法在代码块中访问)
var声明的变量不具有块作用域(在代码块中声明的变量可以在代码块中访问)
1.在全局中使用var声明的变量,都会作为window对象的属性保存
2.使用function声明的函数,都会作为window的方法保存
3.使用let声明的变量不会存储在window对象中,会存储在别的地方
// var 和 let 的区别
// let 块级里面的访问不到
{
let a = 10
}
console.log(a) // 报错
// var 块级里面的可以访问
{
var b = 10
}
console.log(b) // 10
1.1 if…else…
// 苹果5元/斤,如果购买重量超过5斤,那么立减8元
var price = 5
var per = 6
var totalPrice = price * per
if (per > 5){
totalPrice -= 8
} else {
totalPrice = totalPrice
}
console.log(totalPrice); // 22
1.2 if… else if …else
// 注意条件的值 由大到小
var score = 92
// 如果满足条件就执行第一个{}内的代码 后面不再执行
if (score > 90) {
console.log('带着去游乐场~')
} else if (score > 80) {
console.log('去吃麦当劳~')
} else if (score > 70) {
console.log('去吃巧克力~')
} else {// 如果不满足条件就执行第二个{}内的代码
console.log('去上补习班~')
}
作用域链:
// 作用域链:先查找内容所在的作用域是否存在,如果没有就向上一级查找,
// 没有就向再上一级查找,如果都没有就会做出相应处理
var c = 18
{
var c = 16
console.log(c) // 16
}
console.log(c) //16
1.3 三元运算符
判断条件 ? 满足条件执行的语句一 : 不满足执行语句二
var num1 = 10
var num2 = 20
var res = num1 > num2 ? num1 : num2
console.log(res) // 20
1.4 switch语句
1.它更适合单个值的时候使用 不适合区间使用
2.注意 break 的使用
3.没有满足条件的会执行最后的 default 语句
var score = 70
switch (score) {
case 90:
console.log('带着去游乐场~')
break // break是停止后面代码运行
case 80:
console.log('去吃麦当劳~')
break
// 多个条件都执行一个语句,可以把多个条件写在语句前面
case 70:
case 60:
console.log('去吃巧克力~')
break
// 所有的case 条件都不满足,直接执行default后面语句
default:
console.log('去上补习班~')
break
}
六、循环语句
循环语句都可以用 break、continue
break 跳出当前整个循环
作用:有时循环语句不需要执行完成,找到需要的数据以后可以结束循环,提高性能。
break 只能终止一层当前最近的循环(break放在哪层循环,就终止那一层)
break 跳出多层循环
1.用标志+break跳出多层循环
var flag = false // false不跳出循环,true 跳出循环
for (var i = 0; i < 10; i++){
console.log("i"+i);
for (var j = 0; j < 10; j++){
console.log(i +"--"+j);
// 大于5 跳出循环
if (j > 4){
flag = true
break;// 跳出一层 for 循环
}
}
if (flag){
break // 如果flag为true则跳出当前for循环
}
}
2.(推荐使用)js可以给循环语句添加tag,用break tag可以让代码跳到tag位置,执行后面语句(排除break所在循环,不管多少层都会排除) —break不能省略
out1: // 循环语句前面添加tag
for (var i = 0; i < 10; i++){
console.log("i"+i);
for (var j = 0; j < 10; j++){
console.log(i +"--"+j);
if (j > 4){
break out1; // 跳出循环,并从out1 上面定义的tag位置开始执行代码(不会再执行break的循环语句)
}
}
}
continue 跳过此次语句的循环
作用:跳出当前这一次循环,继续执行后面的循环
遇到 continue 结束当前这一次循环(continue后面的语句不会再执行),执行下一次循环
1.1 while循环
// while循环 计算 0-99 累加和
var i = 0;
var res = 0;
while (i < 100){
res += i;
i ++
}
console.log(res); // 4950
1.2 do…while循环
// do-while
var count = 0;
do {
console.log('welcome china')
count ++
} while(count < 100)
while 和 do-while 循环的区别:
while循环 条件不成立,直接不执行
do-while循环 不管条件成不成立,至少都会执行一次
1.3 for循环 (重要)
// 计算 0-99 偶数和
var sum = 0;
for (var i = 0; i <= 100; i++){
if (i % 2 == 0){
sum += i;
}
}
console.log(sum); // 2550
// 算法的优化
var sum = 0;
for (var i = 0; i <= 100; i+=2){
sum += i;
}
console.log(sum);
1.4 for循环的嵌套
// 循环嵌套
var drink = ['Milk','coffe']
var cake = ['蛋糕','油条','饼干','面包']
for (var i = 0; i < drink.length; i ++){
for (var j = 0; j < cake.length; j++){
console.log(drink[i] + cake[j]); //打印 每一种搭配
}
}
1.5 数字内置对象
Math:数学常数属性和数学函数方法
随机数:Math.random()
随机到n之间的数:Math.random() * n
向上取整:Math.ceil(x)
向下取整:Math.floor(x)
四舍五入:Math.round(x)
最大值:Math.max([x[, y[, …]]])
最小值:Math.min([x[, y[, …]]])
绝对值:Math.abs(x)
作用域
作用域是一个变量的可见区域
1.全局作用域
1.全局作用域在网页运行时创建,在网页关闭时销毁
2.所有直接编写在script标签中的代码都位于全局作用域中
3.全局作用域的变量是全局变量,可以在任意位置访问
2.局部作用域(块作用域)
1.块作用域(局部作用域)在代码进入执行时创建,代码块执行完毕就销毁
2.只能在块内部访问,外部无法访问
3.函数作用域(局部)
1.函数作用域在函数调用时产生,调用结束后销毁
2.函数每次调用都会产生一个全新的函数作用域
3.在函数中定义的变量是局部变量,只能在函数内部访问,外部无法访问
var test1="test1" // 全局变量
// 全局变量和局部变量存放的内存地址不一样
function fa(){
var test2="test2" // 局部变量,只能在函数内部使用
var test1="xxx" // 声明的局部变量和全局变量重名,该值不会影响全局变量
console.log(test1) // xxx
}
fa()
面向对象OOP:
面向对象编程 (OOP:object oriented programming): 现在主流的编程范式。将现实世界中的各种复杂关系抽象为一个个的对象,用对象与对象之间的分工与合作,完成对真实世界的模拟。(用代码中的对象数据描述世间万物之间的关系和状态)
对象: 是一类属性和方法的集合
方法:就是函数,一般方法可以模拟动作。
属性:就是对象的一些静态属性。
面向对象编程的三个基本概念
- 类(class): 抽象的概念,相似对象的一个集合,产生对象的一个模版,类产生的对象都有类的特征。如人类就是一个类,人(对象)是人类这个模版产生的一个具体对象,人就有人类的特效。
- 对象(object): 是实体,对象是由类产生的带有类的属性和方法的实体(实例)
- 实例化: 由类产生对象(实例)的过程就实例化
七、函数
函数也是一个对象,属于复杂的数据类型 函数具有对象所有的功能,且能存代码,在需要时可以直接调用这些代码 语法: 函数对象()
使用typeof检查函数时返回 function注意点一:所有的函数都有返回值,如果没有写返回值,那么默认返回undefiend
注意点二:我们可以明确写上返回值,return是关键字
注意点三:我们使用return关键字时候,函数会立即停止执行,return后面的内容不再执行
注意点四:函数执行完后会释放内存,调用函数,里面的参数会重新传
函数的定义方式:
-----参数可省:在函数定义参数,相当于在函数内部声明了对应的变量
-----()里面的变量叫函数的参数(没有赋值的变量叫形参),表示函数有参数,函数内部可以不用参数
-----调用函数的时候可以给参数赋值(不一定每个参数都赋值),叫实参。
1.函数声明
function fn(参数) {
console.log(‘函数声明定义的函数’)
}
2.函数表达式
const fn2 = function(参数) {
console.log(‘函数表达式定义的函数’)
}
3.箭头函数
() => {
console.log(‘箭头函数定义的函数’)
}
或
() => console.log(‘箭头函数定义的函数’) //只有一条语句{}可省
const fn3 = ()=> {
console.log(‘箭头函数定义的函数’)
}
- 立即执行函数
// 立即执行函数:
// 是一个匿名函数,并且它只会调用一次,避免变量冲突的问题
//注意加 " ; " ,以免浏览器和后面的代码解析在一起
(function(){
let a = 100
console.log(a);
})();
函数的提升
函数名和变量一样,存在函数提升(预编译时会把所有的function函数提升到到代码顶部)
如果在函数声明前就调用函数,要使用函数声明创建的函数,它会在其他代码执行前被创建(提升)
fn() // 正常执行,会提升函数
function fn(){
console.log('qqqq');
}
fn1() // 会报错,只会提升var声明的变量,不会提升函数
var fn1 = function(){
console.log('qqqq');
}
函数的 严格模式
一般在写代码的时候都是正常模式,除了正常模式以外,还有一种严格模式,可以让js代码更严谨。是ES5引入的一种标准,是为js后面版本升级做的准备,一般开发用正常模式,产品环境用严格模式(一般第三方库自动修改)
它会禁止一些语法,更容易报错,提升性能
在开发中,应尽量使用严格模式,正常写代码还是遵循js严格模式规范。
//1. 开启严格模式,在js代码文件的开头添加"user strict",表示整个文件都开启严格模式
"use strict" // 全局 严格模式
//2. 在函数里面添加表示函数使用严格模式
function fn(){
"use strict" // 在函数中开启严格模式 只作用在当前函数中
var per="333"
// 不能删除变量或者函数
// delete per // 不能删除变量
}
//3. 严格模式下函数内部的this是undefined,正常模式下函数内部的this指向window。构造函数没有变化。
function f2(){
console.log(this)
}
f2()
1. 函数的 this
1.在执行函数时,JS解析每次都会传递一个隐含参数 this
2. this 会指向一个对象,所指对象会根据函数调用方式不同而不同:
在普通函数内部的this非严格模式下,this所指对象是 window
3. 以方法形式调用时,this指的是 调用方法的对象(哪个对象调用该方法,this就表示该对象)
4.在构造函数内部,使用了new 关键词实例化对象,this表示将要实例化的实体对象
注意:
5.箭头函数没有自己的this,它的this由外层作用域(函数)决定
箭头函数的this和它的调用方式无关
var cat={
name: "cat",
go: function(){
console.log(this)
}
}
// 由于cat直接调用go方法,go方法里面的this表示cat对象
cat.go()
var dog={
name: "dog"
}
dog.go=cat.go
// dog调用go方法,内部的this指向dog
dog.go();
改变this指向:
函数内部的this是动态切换的,有时需要固定this的指向。
1. call(object,param1,param2,…)
objcect 函数内部固定指向的对象,param1,param2…给函数传递的参数,多个参数用,分隔。
var obj1={
name: "obj1"
}
function f2(a,b){
console.log(this,a,b)
}
// 函数的call方法调用执行函数,函数内部的this固定指向obj1,后面参数则是给函数传递的参数
f2.call(obj1,1,2)
f2(1,2)// 直接调用指向 window对象
2. apply(object,[arguments])
apply方法也是改变函数内部this指向,和call一样的作用,区别是apply调用函数传递的参数都是放在一个数组里面。
var obj1={
name: "obj1"
}
function f2(a,b){
console.log(this,a,b)
}
// 执行f2函数,函数内部的this指向obj1,数组是调用函数传递的参数
f2.apply(obj1,["x1","y1"])
f2(1,2)// 直接调用指向 window对象
3. bind() 将函数内部的this绑定到某个对象
var cat1={
name: "cat1",
go: function(){
console.log(this)
}
}
var dog1={
name: "dog1"
}
// 把cat1对象绑定到go方法内部的this,并返回一个新内存地址的函数
dog1.go = cat1.go.bind(cat1)
dog1.go();
console.log(dog1.go === cat1.go) //false
2. return 带返回值的函数
// 调用函数会把return 后面的值返回到函数外面。
function f13(name, age){
var user={
name: name,
age: age
}
// 把user返回到外面
return user;
// return 会终止后面代码的运行
console.log("----------")// 不会运行
}
var res = f13('cat',10) // 执行完函数就得到return 返回的user 等价于 var res=user
console.log(f13('cat',10))
3. 构造函数
构造函数就是一个普通的函数,用来模拟类的,是产生对象的模版
构造函数内部使用this关键,this表示要产生的对象实体
构造函数实例化产生对象需要用new关键词
构造函数一般用大驼峰命名法(所有单词首字母大写)
constructor() 方法创建构造函数
// 用构造函数模拟类
function ClassPeople(name,age){
// this表示构造函数产生的实体(对象)
this.name=name
this.age=age
}
var zhangsan = new ClassPeople("zhang", 22) // new 关键词实例化 类,产生一个对象
// constructor()方法创建构造函数
class Person {
// 在类中添加一个 constructor() ---构造方法
// 构造方法在调用类时就执行
constructor(name,age,gender){
// 在构造函数中,this表示当前所创建的对象
this.name = name;
this.age = age;
this.gender = gender;
}
}
const p1 = new Person('Mike',19,'男')
console.log(p1);
1. new关键词
在构造函数内部使用new target
new target 使用了new关键词实例化可以指向当前的构造函数,否则是undefined
function ClassPeople(name,age){
// this表示构造函数产生的实体(对象)
this.name=name
this.age=age
// this 如果没有用new 实例化构造函数,this在非严格模式下指向的是window对象
// 如果使用了new, this指向的是要产生的实体对象
console.log(this)
}
var a = new ClassPeople("a",19)
4. arguments参数的使用
默认情况下,函数中有一个arguments变量,返回函数的实参,是一个类似数组对象,没有数组的属性和方法
- 变量中存储着所有传入的参数
- 对象类型;
- 通过索引获取某一个变量;
function f1(){
console.log(arguments);// 输出函数的所有实参
for (var i = 0; i < arguments.length;i++){
console.log(arguments[i]);
}
}
f1(1,2,"a")
5. 递归
函数内部调用自身函数
函数内部需要有结束调用函数的条件,不然就是死循环,会内存溢出,导致浏览器崩溃。
创建函数,在函数内部写出期望的逻辑代码
必需要有一个结束递归的条件
递归函数是从最里面(最后的一次函数调用开始执行)
缺点:性能较差(占用栈内存比较多)
优点:写出来代码简洁
空间内存,运行时间
6. 回调函数
把一个函数作为实参给传递函数,作为实参的函数就叫回调函数
回调函数(闭包):
1.函数作为另外一个函数的参数
2.函数作为另一个函数的返回值
//函数作为另外一个函数的参数
function request(callback){
var a = ['1','2','3','4','5']
callback(a)
}
request(function (res){
console.log('拿到的返回数据是',res)//拿到的返回数据是['1', '2', '3', '4', '5']
})
// 函数作为另一个函数的返回值
function fn2(){
console.log('这是fn2')
function fn3(){
console.log('这是fn2的返回值')
}
return fn3
}
var fn4 = fn2()
console.log(fn4) // 这是fn2
fn4() // 这是fn2的返回值
// 调用两次
fn2()() //这是fn2 这是fn2的返回值
7. 形参设置默认值
调用函数没有赋值,则使用默认值,调用函数传递了实参,则用实参值
//会以传递的实参为准
function f12(name="zhang",age=10){
console.log(name, age) // li 10
}
f12("li");
8. 函数的属性和方法
函数类型也是属于一种对象,他有自己的属性和方法。
// 对象的属性值可以是任意数据类型,可以是一个函数(这个函数就叫对象的方法)
var user = {
name: "li",
age: 10,
go:function(){ // user对象的go方法
console.log("go")
}
}
user.go() // 调用对象的方法
8.1 name 查看函数的原始名称
function f2(){
console.log("f2")
}
var f1 = f2
console.log(f2.name) //f2
// 创建f2的时候name已经写入,f1只是存了函数的内存地址,查看name还是显示f2
console.log(f1.name) //f2
var f3=function(){}
// 表达式创建的函数,使用匿名函数,函数名称就是变量名
console.log(f3.name) //f3
var f4=function xx(){}
// 函数名称是xx,它不是匿名函数
console.log(f4.name) // xx
8.2 length 返回函数形参的个数
function f5(a,b,c){ }
console.log(f5.length) // 3
8.3 toString() 把函数转为字符串
function f5(){ }
console.log(f5,typeof f5) // function
f5=f5.toString()
console.log(f5,typeof f5) // string
9. ()可以立即运行函数 – 匿名函数
匿名函数可以用() 立即执行
function fc(){
console.log("fc")
}
fc(); // 立即运行fc函数
// 注意:前面的函数结束需要加 ;
(function(){
console.log("匿名函数")
})() // 加() 立即运行匿名函数
10. 闭包
闭包就是:函数内部返回一个函数
函数调用完成以后,函数内存会自动释放,内部的局部变量内存也会跟着释放。
作用: 把函数内部的局部变量,持久的放入内存。
function fd(){
return function(){
console.log("闭包")
}
}
var fe=fd() // fe是fd函数的函数
fe() // 运行的是fd return后面返回的函数
function fx1(){
var num=0;
return function(){
num++
return num;
}
}
// fx1()运行完成,由于返回的函数还在使用局部变量num,
//所以num变量还会保留在内存,不会被释放。
console.log(fx1()()) // fx1() 是内部return返回的函数,第二个()是运行返回的函数
var fk = fx1()
console.log(fk()) // 1
console.log(fk()) // 2
八、对象
对象是一组数据的集合,对象可以存储多组数据。字符串或者number等类型只能是一个值,如描述一个人的信息,用字符串就很难实现。而对象则可以把人的所有数据都包含。
对象是JS中的一种复合数据类型,它相当于一个容器,在对象中可以存储各种不同类型的数据
1.添加对象的属性:对象.属性名 = 属性值 、 对象[“属性名”] = 属性值
2.读取对象的属性:对象.属性名 、 对象[“属性名”]
3.删除对象的属性:delete 对象.属性名 、 delete 对象[“属性名”]
//读取对象属性值
//1. 用object.key, .key的方式不能读取有空格等特殊字符的key名称
console.log(user.name,user.age)
// console.log(user.some address)
// 错误写法,只能用[key]方式读取
console.log(user["some address"])
//2. 用object[key],key需要用字符串类型
console.log(user["name"])
console.log(user["age"])
//修改对象属性值
//1. .key=value,给对应的属性赋值就是修改属性值
user.name="li si"
user.age=44
//2. [key]=value ,修改属性值
user["name"]="wang"
user["age"] = 3
//3. with 便捷修改对象属性(不推荐)
// with(object) with语句可以操作对象的多个属性,提高便捷性,性能没有.value修改性格高,存在一定的安全隐患
with(user){
name='a'
age=11
}
//delete 删除属性
// 1.delete objet.key
delete user.name;
// 2.delete object["key"]
delete user["age"]
console.log(user)
// 用{}创建对象, { }是在堆内存开辟空间存放数据,然后把该数据所在的内存地址赋值给了user变量
var user={
name: "zhang san",
age: 12,
good: true,
like: "movie,book",
// key的名称多个单词之间有其他的非数字,字母的符号不能自动转字符串,只能手动转
// 如果key的名称有空格或者其他特殊字符不能自动转字符串,需要收到转
"some address": "address"
}
//对象的属性值可以是任意数据类型,比如属值又是一个对象
var animal={
name: "猫",
age: 2,
peo: {
name: "zhangsan",
phone: "xxxxxxx",
address: {
province: "四川",
city: "成都"
}
}
}
注意:引用数据类型修改了数据,其他变量引用了该数据显示结果也会跟着变化
// cat 和animal都是引用的同一份数据,cat修改了数据其实就是cat和animal共同引用的那一份数据
var cat = animal
cat.name="small"
console.log(cat)
console.log(animal)
1.1 对象方法
对象名.方法
// 对象方法调用属性 对象名.方法
var name = 'Welcom China'
// 将字符串转换为数组(可以通过空格、逗号等划分)
console.log(name.split(' ')) // ['Welcom', 'China']
// 取一个字符 (下标从0开始)
console.log(name.charAt(4))
// 字符串的剪切 slice/substring/substr -->取一段字符区间
console.log(name.slice(7,9)) // Ch
// 正数表示从前往后取 负数表示从后往前取
console.log(name.slice(2,-3)) // lcom Ch
// 将字符转成 大写
console.log(name.toUpperCase())
// 将字符转成 小写
console.log(name.toLowerCase())
// 强转 --> 数字转为字符串类型
var num = 1992
console.log(num,String(num))
console.log(num,num.toString())
// 首字母大写处理
var name = 'welcom chiNa'
var arr = name.split(' ')
for (var i = 0; i < arr.length; i ++){
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1).toLowerCase();
}
console.log(arr)
// eval() 计算 -->转成数字型
console.log(eval('3'+'4')) // 数字 34
console.log(eval('3')+eval('4')) // 数字 7
// trim() 去掉首位空格
var name = ' anli '
console.log(name.trim()) // anli
// toFixed() 取小数点后几位 -->会四舍五入
var height = 1.55555
console.log(height.toFixed(2)) // 1.56
// indexOf() 检索字符串,看它是否包含另一个字符串
/*
如果包含,就会返回字符串所在的索引位置
如果不包含,就会返回 -1
*/
var message = 'Hello World'
console.log(message.indexOf('o')) // 4
console.log(message.indexOf('hoo')) // -1
// includes() 会返回 true和 false
console.log(message.includes('o')) // true
console.log(message.includes('hoo')) // false
// replace() 替换字符串
console.log(message.replace('llo','你好')) //He你好 World
// 定义一个函数
var newMag = message.replace('Hello',function(newMag){
return newMag.toUpperCase()
})
console.log(newMag) //HELLO World
// concat() 字符串拼接
var a = 'He'
var b = 'll'
var c = 'o'
console.log(a+b+c) //Hello
console.log( a.concat(b,c) ) //Hello
// startsWith() 以##开头 区分大小写
// endsWith() 以##结尾 区分大小写
console.log(message.startsWith('h')) // false
console.log(message.endsWith('hoo')) // false
1.2 可变类型和不可变类型在内存的存储
// 引用数据类型用 === 比较的时候是比较的内存地址是否相同
var peo = user;
console.log(peo === user)
1.2.1 不可变类型
原始值 属于不可变类型,创建之后无法修改,在内存中不会创建重复的原始值
1.2.2 可变类型
对象属于可变类型
1.对象创建完成后,可以任意的添加删除修改对象中的属性
2.两个对象进行比较时,比较的是对象的内存地址(两个对象存在两个不同的内存地址中)
let obj2 = Object()
let obj3 = Object()
console.log(obj2 === obj3) // false
let obj2 = Object()
let obj3 = obj2
console.log(obj2 === obj3) // true
3.指向同一个对象的变量,一个变量修改值时,另一个变量也会产生影响
let obj2 = {
name: 'Anna',
age: 20
}
let obj3 = obj2
obj3.name = 'Pet' // obj3的属性值被修改,对象obj2的也会被修改
console.log(obj2); // {name: 'Pet', age: 20}
4.修改变量
修改变量和修改对象的区别:
修改对象: 如果有其他变量指向该对象,则所有指向该对象的变量都会受到影响
修改变量: 只会影响当前的变量
let obj2 = {
name: 'Anna'
}
let obj3 = obj2
obj3.name = 'Tom' // 修改对象
obj3 = { } // 修改变量
1.2.3 const 的使用
以上当使用变量存储时,很容易因为改变变量所指的对象,提高代码的复杂度,通常情况下,声明存储对象时会使用 const
const 只是禁止变量被重新赋值,对对象的修改没有任何影响
// const 可以有效的避免变量的修改
const obj2 = {
name: 'Lili'
}
// 修改变量会报错
const obj3 = obj2
obj3 = { } // 报错
// 修改对象正常修改
const obj4 = obj2
obj4.name = 'Bob' // {name: 'Bob'}
1.4 in 运算符
in 运算符:in 判断对象中是否存在某个属性(key),存在返回true,不存在返回false
语法 :语法名 in obj
// 属性存在返回 true 不存在返回false
let obj = {name,age}
console.log("name" in obj) // true
console.log("sex" in obj) // false
1.5 枚举属性(for-in 语句)
枚举属性 : 将遍历对象中所有的属性全部获取
let obj1 = {
name: 'Anna',
age: 19,
gender: '女',
[Symbol()]: '测试属性' // 符号添加的属性是不能枚举的
}
// for-in语句 有几个属性就会执行几次,除了符号属性
// 每执行一次,都会将一个属性名赋值给定义的变量
for(let test in obj1){
console.log(test,obj1[test]) //获取 属性名,属性值
}
1.6 深浅拷贝(复制)数据
浅拷贝:引用数据类型,变量存放的是一个内存地址,拷贝数据的时候是拷贝的内存地址(叫浅拷贝), 两个变量用的同一个数据。修改一个变量的值,会影响其他变量。
深拷贝:可以新建一个引用数据,把数据的每个属性拷贝到新建的数据里面,这样两个数据的内存地址不一样,修改变量不会影响其他变量(深拷贝)
var cat={
name: "猫",
age:1,
peo: {
name:"zhangsan",
}
}
// 浅拷贝(拷贝内存地址)
var cat1 = cat;
cat1.name="xxx" // 其中一个被修改,两个变量中的值都会被修改
console.log(cat1 === cat) // true
// 深拷贝(拷贝新建的数据,内存地址不同)
cat1 = {}
// 遍历cat对象的每一个属性和数值添加到cat1
for (key in cat){
cat1[key] = cat[key]
}
console.log(cat1 === cat);// false
例题:
把数组和对象进行深拷贝
// 深拷贝(拷贝新建的数据,内存地址不同)
var person1 = {
name:"lisi",
age:10,
frend:["a1","a2","a3", {name:"lisi",age:10}], // frend属性数组是一个引用数据类型,对应的是一个内存地址
family:{ // family属性是引用数据类型,也是一个内存地址。
number:123,
address:"四川成都",
o1:{ // 思考,如果是多层次的引用数据类型嵌套,怎样拷贝?
o2:{
name: "a1"
}
}
}
}
// 对frend 和 family 进行深拷贝
// 把数组和对象拷贝过来加入到 user
var user = {} // 定义一个 user 对象
// 对person1遍历,key表示索引值
for (key in person1){
// 判断是否为数组
if (Array.isArray(person1[key])){ //如果是数组
var arr1 = [] // 建一个新数组
// 遍历person1[key]
for (var i = 0 ; i < person1[key].length;i++){//遍历person1[key]数组的值
arr1.push(person1[key][i]) // 把person1[key]数组的值加入到新建的数组中
}
user[key] = arr1; // 把新数组加入到 user 对象
} else if (typeof person1[key] === "object"){ //判断是否为 对象,如果是
var obj = {} //建一个新的对象
for (j in person1[key]){ //遍历person1[key]对象的值
obj[j] = person1[key][j]//把person1[key]对象的值加入到新建的对象中
}
user[key] = obj// 把新对象加入到 user 对象
} else {
user[key] = person1[key] // 其他属性直接添加到 user 对象
}
}
console.log(user === person1);//false 两个变量指向不同地址
console.log(user.frend === person1.frend);//false 深拷贝成功
console.log(user.family === person1.family);//false 深拷贝成功
console.log(user.name === person1.name); //true 但是修改user的name属性值不会影响person1的name属性值
// 递归函数方法:创建任意深拷贝(拷贝新建的数据,内存地址不同)
function copyObject(obj){
var o = ""; // 创建一个变量用来接收拷贝的数据
if (Array.isArray(obj)){ // 如果传入的obj是一个数组
o = []
for (var i = 0; i < obj.length; i++){
o.push(copyObject(obj[i])) // 需要递归判断数组里面还存在的引用类型
}
return o
} else if(typeof obj === "object"){
o = {}
for (key in obj){
o[key] = copyObject(obj[key])
}
return o
}
// 如果不是数组或对象 当作非引用数据类型 直接返回原始值
return obj
}
var user = copyObject(person1)
console.log(user === person1); // false
console.log(user.frend === person1.frend); // false
九. 标准库
一. Object 库
Object是一个js的对象,同时也是一个构造函数,Object对象提供了操作对象的属性和方法,也js对象的原型对象
Object() 作为普通函数使用
可以把其他数据类型转为一个包装对象(如果传入number或者string,可以把number或string转为包装对象)
var a = Object("x1")
var b = new Object("x1")
console.log(b)
//3. 不传递参数,可以创建一个空对象
var c = new Object() // 等价于 {}
1.Object.prototype.xxx 自定义原型方法
给所有的对象添加公共方法或属性:
Objet对象是所有对象的原型。对象可以用整个原型链的所有属性。
.
属性是先查看自身属性,如果没有则查看原型上的属性。
.
可以给Object对象的原型添加自定义方法或者属性,所有的对象就可以都有该属性
//在Object对象的原型上添加count方法
Object.prototype.count = function(){
console.log("自定义的count方法");
}
// 所有创建的对象都可以调用Object原型的count方法
var a = {name: "Anna"}
a.count() // a对象先查看自身是否有count方法,没有则从原型上查看
2. instanceof
instanceof 运算符返回一个bool值,表示对象是否为某个构造函数的实例(查看对象是否由某个构造函数产生)
function User(){
this.name = "AAA"
}
var u1 = new User()
console.log(u1 instanceof User); //true u1对象是由User构造函数产生的,返回true
var u2 = {name: "BBB"}
console.log(u2 instanceof User); //false u2对象不是有User构造函数产生的,返回false
//所有的对象都是Object构造函数的实例
console.log(u1 instanceof Object); // true
console.log(u2 instanceof Object); //true
3. Object对象的属性和方法
1. Object.getPrototypeOf(obj) 获取对象原型
Object.getPrototypeOf(obj) 返回参数对象的原型,也是获取对象原型的标准方向.
function User(){
this.name = "AAA"
}
User.prototype.go = function(){ }
var u1 = new User()
console.log(Object.getPrototypeOf(u1));//查看u1对象的原型,是User函数的原型
2. Object.setPrototypeOf(a,b) 设置对象原型
Object.setPrototypeOf(a,b) 设置a对象的原型为b对象
var cat = {name: "A"}
var dog = {name: "B"}
Object.setPrototypeOf(dog,cat) //把dog对象的原型设置为cat对象
console.log(dog);// 原型是cat
3. Object.create(a,b)
以对象a为原型,创建一个新的对象b。b对象需要使用对象属性描述方式。
var dog = {name: "B"}
var pig = Object.create(dog,{age:{value:12}}) // 创建一个新的对象,对象的原型是dog对象
console.log(pig) // 原型是dog
4. a.isPrototypeOf(b) 判断原型
a.isPrototypeOf(b) 判断a对象是否是b对象的原型(整个原型链上的都算) --顺序不可颠倒
var cat = {name: "A"}
var dog = {name: "B"}
Object.setPrototypeOf(dog,cat) //把dog对象的原型设置为cat对象
console.log(dog);// 原型是cat
var pig = Object.create(dog,{age:{value:12}}) // 创建一个新的对象,对象的原型是dog对象
console.log(pig) // 原型是dog
// pig的原型是dog对象,dog对象的原型是cat,所以pig的原型也是cat
console.log(cat.isPrototypeOf(pig)); //true
5. __proto__
返回对象的直接原型
var cat = {name: "A"}
var dog = {name: "B"}
Object.setPrototypeOf(dog,cat) //把dog对象的原型设置为cat对象
console.log(dog);// 原型是cat
var pig = Object.create(dog,{age:{value:12}}) // 创建一个新的对象,对象的原型是dog对象
console.log(pig) // 原型是dog
// pig的直接原型就是dog对象,
console.log(pig.__proto__); //dog
6. hasOwnProperty() 查看是否为自身属性
hasOwnProperty() 查看对象的属性是否为自身属性,true则是自身属性,false则是原型属性。
var cat = {name: "A"}
var dog = {name: "B"}
Object.setPrototypeOf(dog,cat) //把dog对象的原型设置为cat对象
console.log(dog);// 原型是cat
var pig = Object.create(dog,{age:{value:12}}) // 创建一个新的对象,对象的原型是dog对象
console.log(pig) // 原型是dog
// pig自身有 age 属性
console.log(pig.hasOwnProperty("age")); //true
// name是dog原型上的属性,返回false
console.log(pig.hasOwnProperty("name")); //false
7. Object.keys() 遍历对象自身所有属性
Object.keys() 遍历对象所有的自身属性,返回为一个数组(for…in 遍历对象开销比较大)。开发中一般用该方法遍历对象。
var cat1 = {
name: "Amy",
age: 4,
color: "brown"
}
//返回cat1的所有属性 放进数组
console.log(Object.keys(cat1)); //['name', 'age', 'color']
8. Object.values() 遍历对象自身所有属性值
Object.values() 遍历对象的所有属性值,返回为一个数组。
var cat1 = {
name: "Amy",
age: 4,
color: "brown"
}
//返回cat1的所有属性值 放进数组
console.log(Object.values(cat1)); // ['Amy', 4, 'brown']
9. 同时遍历 keys和values
同时遍历输出 属性和属性值
var cat1 = {
name: "Amy",
age: 4,
color: "brown"
}
//1.拿到key的数组-- ['name', 'age', 'color']
var key = Object.keys(cat1)
//2.遍历key数组-- 输出属性和属性值
key.forEach(function(item){
console.log("key:"+item,"value:"+cat1[item]);
})
10. a.toString()
a.toString() 把a对象转为字符串输出 [object Object]
第一个是对象数据类型,第二个是对象的构造函数
var dog = {name: "B"}
//第一个是对象数据类型,第二个是对象的构造函数
console.log(dog.toString()) //[object Object]
11. toString.call(param) 判断数据类型
toString.call(param)可以用于判断数据类型,比typeof判断数据类型更精准。
把传入的param 转为字符串(param是任意数据类型,param参数在系统运行时都是包装为对象,所以转字符串输出的都是object类型,生成包装对象的构造函数不同,根据不同的构造函数判断数据类型)
用call方法改变toString()方法内部的this,为传入的对象
console.log(Object.prototype.toString.call("a")) // [object String]
console.log(Object.prototype.toString.call(3)) // [object Number]
console.log(Object.prototype.toString.call(true)) // [object Boolean]
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call(["a"])) // [object Array]
console.log(Object.prototype.toString.call(function(){})) // [object Function]
var test = 111
if(Object.prototype.toString.call(test) === "[object String]"){
console.log("字符串")
} else {
console.log("非字符串")
}
4. 对象的属性描述对象
js提供了一个内部数据结构,用于描述对象的属性,控制属性的行为,如属性是否可读,是否可遍历等.
value: “”, 设置属性的属性值,默认是undefined
writable: true, 属性值是否可以改变,true是可以修改(默认),false是不能修改
enumerable: false, 属性是否可遍历,true可以遍历(默认),false不能遍历
configuratable: true, 属性是否可配置,控制整个描述对象的可写性。true可写,false不可
get: undefined, 值是一个函数,表示读取属性的getter(读取属性的时候触发该函数)
set: undefined, 值是一个函数,表示设置属性值的时候触发的setter
// 对象的属性描述对象
var pig = Object.create({},{
name: {
value:"Anna",
writable: false, // 不能被修改
enumerable: false // 不能被遍历
},
age:{
value:12
}
})
pig.name = "aa"// 不能被修改就没用
console.log(pig);// name = "Anna"
1. Object.getOwnPropertyDescription(obj, key)
Object.getOwnPropertyDescription(obj, key) 获取参数对象某个属性的描述对象(4个)
var user1={
name:"a1",
age: 12
}
console.log(Object.getOwnPropertyDescriptor(user1,"age")) // 查看user1对象 age属性的描述对象
2. Object.defineProperty(object,key,{})
Object.defineProperty(object,key,{})设置或者修改对象的某个属性的描述对象
var user1={
name:"a1",
age: 12
}
Object.defineProperty(user1,"age",{
// 修改user1对象的age属性描述信息
writable:false
});
user1.age = 15 // 设置age属性值不能修改,修改age值不成功
console.log(user1.age); //age: 12 不会变
二. String 库
String是一个字符串对象,同时也是一个构造函数,可以产生字符串对象。所有字符串类型在运行的时候会自动被String构造函数包装为String对象。
//1. 字符串在js运行的时候会被转为String包装对象
var str = "hello"
console.log(str[1]); // e
//2. String() 作为构造函数使用,返回字符串的包装对象
var str1 = new String("Css3")
console.log(str1);
console.log(str1[0]);// C
//3. String() 作为普通函数,把其他数据类型转为字符串string类型
console.log(String(123));
1. length 查看字符串长度
var str = "hello"
console.log(str.length); // 5
2. a.concat(b,c) 合并字符串
a.concat(b,c) 合并字符串,返回一个新的字符串。把b,c字符串合并到a字符,返回一个新的字符串。
var str = "hello"
var str1 = "JavaScript!"
// 把其他类型当做字符串合并
console.log(str.concat(" ",str1,"hhh"));//hello JavaScript!hhh
// 用一个空字符串添加
var stre = "".concat(str,str1)
console.log(stre); //helloJavaScript!
3. slice(startIndex,endIndex) 截取字符串
slice(startIndex,endIndex) 截取字符串
从startiIndex开始截取,截取到endIndex(不包含),返回新字符串,不会改变原来字符串
正数是从左往右,负数是从右往左截取
substring(startIndex,endIndex),
substr(startIndex,endIndex) 截取字符串,用法和slice一致
var str = "hello JavaScript!"
// 截取索引0到索引5的字符(不包含)
console.log(str.slice(0,5));// hello
// 省略第二个参数,从索引开始,截取完后面所有的字符
console.log(str.slice(6)); //JavaScript!
// 从倒数第4个截取到倒数第2个(不包含)
console.log(str.slice(-4,-2)); //ip
4. trim() 去掉字符串内的空格符
trim() 去掉字符串前后空格符
var str1 = " JAVA "
console.log(str1.length); // 10
console.log(str1.trim().length); // 4
5. indexOf(str)/search(str) 和 lastIndexOf(str) 返回字符串索引
indexOf(str) 返回字符在字符串中从左往右第一次出现的位置,没有包含字符则返回-1
search(str) 用于匹配字符在字符串中第一次出现的位置,如果没有则返回-1,和indexOf()用法一致
lastIndexOf(str) 和indexOf用法一致,顺序是从右往左开始找
var str = "hello JavaScript!"
// indexOf(str)匹配
console.log(str.indexOf("l")); // 2
console.log(str.indexOf("8")) // -1 不存在为-1
// 可以用于判断某个字符或字符串是否在当前字符串里面
str.indexOf("Javas")>-1?console.log("存在"): console.log("不存在");
// search(str)匹配
console.log(str.search("Java")) // 6
// lastIndexOf() 从右往左开始找
console.log(str.lastIndexOf("l")) //3
6. toLowerCase() 和 toUperCase() 字母大小写转换
toLowerCase() 把字母转小写,返回一个新的字符串;
toUperCase() 把字母转大写,返回一个新的字符串。
var str1 = "JAVA hello"
console.log(str1.toLowerCase()); // java hello
console.log(str1.toUpperCase()); // JAVA HELLO
7. split(分隔符)
split(分隔符) 字符串以某个字符为分隔符,形成一个数组
//分隔的字符串作为数组的元素
var str1 = "JAVA h-e-l-lo"
console.log(str1.split(" ")); // ['JAVA', 'h-e-l-lo'] 以空格分隔
console.log(str1.split("-")); // ['JAVA h', 'e', 'l', 'lo'] 以-为分隔符
8. replace() 替换字符
replace() 可以替换字符串中的某个字符
var str = "hello"
str = str.replace("l","-") // 替换str里面第一个l字符为 -
console.log(str); //he-lo
9. match(str)
match(str) 匹配字符串中是否有str字符,匹配成功立刻返回匹配字符串的数组,匹配不成功则返回null
var str1 = "JAVA h-e-l-lo"
console.log(str1.match("he")); // null
// 匹配到str里面的A 就返回匹配的字符串数组,只匹配一次
console.log(str1.match("A"));
10. String.fromCharCode(code) uncode编码
String.fromCharCode(code) // 返回uncode编码(码点)对应的字符串
console.log(String.fromCharCode(65,97)); // Aa 返回码点对应的字符,97->a
三. Number 库
是一个对象,同时也是一个构造函数。js运行时所有的数值类型都会被包装为Number对象。
//1. 作为构造函数使用,返回number包装对象
var num = new Number(3)
console.log(num); // num是Number包装对象
//2. 作为普通函数是把其他数据类型转为数值类型
console.log(Number("aaa")); //NaN
1. toFixed(num) 保留小数位数
toFixed(num) 设置保留小数的位数(num是0-20)
var num = 62.336224
var re = num.toFixed(2)
// 四舍五入保留2位小数,返回的是字符串类型
console.log(re); // 62.34
console.log(typeof re); //string
2. toString() 数值转字符串型
toString() 数值类型转字符串
var num = 62.336224
console.log(num.toString());
四. Math库
提供了各种数学计算的方法,只是一个对象,不是函数。
1. abs() 绝对值
abs() 返回数值的绝对值
var a = -1
console.log(Math.abs(a));//1
2. max() 和 min()
max(a,b,c,…) 返回给的参数中最大的数值
min(a,b,c,…) 返回给的参数中最小值
console.log(Math.max(2,5,30)); // 30
console.log(Math.min(2,5,30)); // 2
3. floor(num) 向下取整
floor(num) 返回小于或者等于num的最大整数(类似parseInt,地板值)
console.log(Math.floor(3.82)); // 3 正数的时候直接去小数点
console.log(Math.floor(-3.18)); // -4 负数有小数点则进一位
4. ceil(num) 向上取整
ceil(num) 返回大于或等于参数值的最小整数
console.log(Math.ceil(3.22)); // 4 正数有小数点则进一位
console.log(Math.ceil(-3.88)); // -3 负数有小数点则去掉小数点
5. round() 四舍五入
console.log(Math.round(3.82)); // 4
console.log(Math.round(3.33)); //3
console.log(Math.round(-3.18)); // -3
6. pow(num1,num2) 幂运算
pow(num1,num2) 幂运算 num1为底数,num2为底数的幂运算
console.log(Math.pow(2,3)); // 8
console.log(2 ** 3); //8
7. sqrt() 平方根
console.log(Math.sqrt(16)); // 4
8. random() 随机数
random() 产生一个0-1之间的随机数(可以是0,但是不会为1;0 <= num < 1 区间的随机数)
// 产生 0-10 的随机整数(不包含10)
console.log(Math.floor(Math.random()*10));
// 产生 20-30 的随机整数(不包含30)
console.log(Math.floor(Math.random()*10 + 20));
// 封装一个可以产生任意区间的随机数方法(包含max)
function random(min,max){
//max-min+1 这里+1是为了把最大值包含在内
return Math.floor(Math.random()*(max-min+1) + min)
}
console.log(random(50,100));
产生随机的4位数字的验证码:
// 封装一个可以产生任意区间的随机数方法(包含max)
function random(min,max){
//max-min+1 这里+1是为了把最大值包含在内
return Math.floor(Math.random()*(max-min+1) + min)
}
// 产生随机的4位数字的验证码的方法
function randomCode(){
//每一个随机数都放入这个空字符串中
var code = ""
for (var i = 0; i < 4;i++){
code = code.concat(random(0,9))
}
return code
}
console.log(randomCode());
产生随机的4位数字和字母组合的验证码:
// 封装一个可以产生任意区间的随机数方法(包含max)
function random(min,max){
//max-min+1 这里+1是为了把最大值包含在内
return Math.floor(Math.random()*(max-min+1) + min)
}
// 产生随机4位的数字字母组合的验证码
function randomCode(){
var code = ""
// 把所有数字和字母放在一个字符串里面,然后随机生成对应的索引,获取对应的字符
var str="0123456789abcdefghjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
for (var i = 0; i < 4;i++){
code = code.concat(str[random(0,str.length-1)])
}
return code
}
console.log(randomCode());
五. Date库
Date() 是一个构造函数,可以获取当前的系统时间作为一个对象(该对象有很多操作时间的方法和属性)
Date日期计算的开始时间(日期对象的零点时间)是1970年1月1日 00:00:00
//Date() 构造函数返回一个日期对象
var date = new Date()
//date显示的时候是输出的日期字符串格式
console.log(date);//Tue Jun 20 2023 10:10:58 GMT+0800 (中国标准时间)
1. now() 毫秒数(时间戳)
Date作为对象使用,now() 返回的是当前日期距离零点(1970年1月1日)的毫秒数(时间戳)
console.log(Date.now());
2. parse(date) 解析指定日期时间戳
Date.parse(date) 解析指定日期字符串,返回指定日期距离零点的时间戳.
console.log(Date.parse("2022-01-01 23:59:59"));
3. Date() 年月日周时分秒
Date()构造函数返回的实例相关的方法
var date = new Date()
console.log(date.getFullYear());// 获取年
console.log(date.getMonth() + 1);// 获取月份,从0开始计算,真实月份需要+1
console.log(date.getDate());// 当前月份的期日(号数)
console.log(date.getDay());// 周几,星期几,周日是0
console.log(date.getHours());// 获取时
console.log(date.getMinutes());// 获取分
console.log(date.getSeconds());// 获取秒
console.log(date.getTime());// 距离零点(1970年)的毫秒数(时间戳)
console.log(Date.now());
// 可自定义 日期的格式
console.log(date.getFullYear()+"-"+(date.getMonth()+1) +"-"+date.getDate());//2023-6-20
//可以传入日期字符串返回对应日期的对象
var date1 = new Date("2021-5-20 16:32:52")
console.log(date1.getFullYear()); // 2021
//可以用 set 方法修改对应的时间
date1.setFullYear("2018") // 修改日期年份
console.log(date1.getFullYear()); // 2018
案例: 获取验证码,1分钟内只能获取一次。
// 第一次获取验证码记录时间
// 第二次获取验证码先判断第二次的时间和第一次获取的时间差有超过1分钟没有。
var codeDate1 = new Date("2023-6-18 21:19:00") //第一次
var codeDate2 = new Date("2023-6-18 21:20:30") //第二次
// 用两个日期的时间戳相减,看差值是否符合需求
var time = codeDate1.getTime() - codeDate2.getTime()
if (time < 60 * 1000){
console.log("请稍后再试");
} else {
console.log("获取验证码成功");
}
六. 定时器库
定时器库是js内置的两个函数,可以指定在什么时间运行某个函数。
1. setTimeout() 定时器
一次性定时器,只能执行一次 setTimeout()
setTimeout(callback,time,arguments) 指定time(毫秒)运行callback一次
var i = 0
setTimeout(() => { // 等5秒会执行函数
i++
console.log(i);
}, 5000);
// 第三个参数是给定时器执行的函数传递的参数
var f1 = function (arg){
console.log(arg);
}
setTimeout(f1,3000,"aa")// 等3秒执行f1函数,并传递aa参数值
案例: 每隔1s就输出i的递增数,输出到10就停止
var i = 0
function f2(){
i++
document.write(i);
if(i < 10){
setTimeout(f2,1000)
}
}
setTimeout(f2,1000)
2.clearTimeout(index) 清除定时器
setTimeout() 会返回当前定时器的索引值index,可以用clearTimeout(index)清除定时器
var i = 0
// 定时器1
setTimeout(() => { // 等5秒会执行函数
i++
console.log(i);
}, 5000);
var f1 = function (arg){
console.log(arg);
}
// 定时器2
setTimeout(f1,3000,"aa")// 等3秒执行f1函数,并传递aa参数值
//setTimeout() 会返回当前定时器的索引值index,可以用clearTimeout(index)清除定时器
var index = setTimeout(() => { // 等5秒会执行函数
console.log("GOGO");
}, 5000);
console.log(index);
// 定时器3
clearTimeout(index)// 清除索引为index的定时器,这个定时器就不会执行了
3. setInterval() 间隔时间执行器
setInterval(callback,time,arguments) 每隔time(毫秒)时间执行一次callback函数。
// 每隔1s输出i的递增数
//返回定时器索引,根据索引清除定时器用clearInterval(index)
var i=0
var index1 = setInterval(function(){
i++
document.write(i)
if(i>9){ // 当i大于10,清除定时器
clearInterval(index1)
}
},1000) // 每隔1秒执行function函数
十、类
类自带 严格模式
在JS可以通过类(class)来创建对象,区分不同类型的对象
1.可以将对象中的属性和方法直接定义在类中,定义后,可以直接通过类创建对象
2.通过一个类创建的对象称为 同类对象
可以使用 instanceof检查一个对象是否是由某个类创建
如果是,则称为该对象的实例
1. 类的继承
继承是面向对象的一个非常重要的特征,一个类可以继承另一个类的所有属性和方法。es2015没有继承的关键词,需要用改变this指向的方式实现继承。
// 创建动物类
function Animal(name,age,color){
this.name = name
this.age = age
this.color = color
this.go = function(){
console.log("run run...");
}
}
// 创建猫类 (猫类属于动物类,应该有动物类的所有属性和方法--应该要继承Animal类的所有属性和方法)
function Cat(age,color){
// 可以用call()改变Animal内部this的指向,指向当前的Cat类创建的对象
Animal.call(this,"Anna",age,color)
this.move = function(){
console.log("爬树");
}
}
var cat1 = new Cat(4,"brown")
console.log(cat1);
2. 原型
实例化构造函数产生一个实例,每次产生的实例都是开辟的新的内存地址存放对象,内部的属性和方法也是新的内存地址。
.
一个类里面的方法或者属性,代码没变化的,如果每次实例化也去创建新的内存存放,会浪费内存空间
.
原型是一个原型对象,是一个共享(公共的)对象。每一个构造函数都有一个prototype属性,指向一个原型对象。
.
每一个对象都有原型对象,构造函数实例化的实例对象,原型对象就是构造函数的原型对象
// 创建动物类
function Animal(name,age){
this.name = name
this.age = age
// this.go = function(){
// console.log("run run...");
// }
}
// Animal.prototype 指向构造函数的原型对象,原型对象有默认的constructor方法,方法就是当前的构造函数
console.log(Animal.prototype);
// 把类里面公共的代码放到原型对象上
Animal.prototype.go = function(){
console.log("run run...");
}
// 构造函数的实例会自动继承原型的属性和方法(实例可以直接使用)
var a1 = new Animal("a1",4)
console.log(a1,a1.go,a1.constructor);
// a1和a2的go方法都是原型对象上的方法,是同一个内存地址
var a2 = new Animal("a2",6)
console.log(a1.go === a2.go); //true
1.1 原型对象的继承
call或者apply只能改变this指向,不能继承原型对象
// 创建动物类
function Animal(age){
this.age = age
}
// 把类里面公共的代码放到原型对象上
Animal.prototype.go = function(){
console.log("run run...");
}
// 创建猫类
function Cat(){
//继承Animal类的age
Animal.call(this,5)
}
var c1 = new Cat()
console.log(c1.go);// undifined 只会继承Animal的age,不会继承Animal的原型对象go方法
// 要实现原型上的属性和方法的基础,直接把父类需要的属性赋值给子类(地址的复制)
Cat.prototype.go = Animal.prototype.go // 指向同一个内存地址
console.log(c1.go); //会继承
1.2 原型链
所有的对象都是有原型对象的,原型对象可能还有自己的原型对象,这样就可以一直找下去,形成了一个找原型对象的链条,叫原型链。所有原型链的尽头是一个null,null表示一个空的对象。
对象可以直接使用整个原型链上的属性和方法。
1.2 实例属性和类属性
// 创建两个类
class Dog {
// 实例属性,可以通过实例访问
name = 'Anna'
age = 19
// 静态属性(类属性)只能通过 类名访问
static aa = 'aa静态属性'
}
class Person {
}
// 用构造函数创建对象
const d1 = new Dog()
// 访问实例属性和类属性区别:
console.log(d1.age);
console.log(Dog.aa);
// instanceof 检查它是不是当前类的实例
console.log(d1 instanceof Dog); // true
console.log(d1 instanceof Person); // false
1.3 类方法
注意:类方法中改变任意一个大类 所有的类方法都会被改变
类.方法
// 类方法 调用属性 类.方法
// 类方法中改变一个大类 所有的类方法都会被改变
// 小数类型
console.log(Number.MAX_VALUE)
console.log(Number.MIN_VALUE)
// 整数类型
console.log(Number.MAX_SAFE_INTEGER)
console.log(Number.MIN_SAFE_INTEGER)
// parseInt 强转整数 数字类型 -->不会 四舍五入
var num = '3.8999'
var num1 = 'aaa'
console.log(Number.parseInt(num)) // 3
console.log(parseInt(num)) // 3
// Number.parseInt() == parseInt() //true
console.log(Number.parseInt(num1)) // NaN
// parseInt 强转小数 数字类型
console.log(Number.parseFloat(num))
console.log(parseInt('0x11')) //17 (16进制)
十一、数组
数组也是属于一种对象类型,是一组数据的集合,没有key,只有value。引用数据类型
数组里面可以放任何类型元素
1.用typeof查看对象他是一个object类型
2.用isArray()判断是否一个数组,数组返回true,非数组返回false
3. length 可以查看数组元素的个数(length数组长度),空白位计算在里面
4.判断数组元素是否在数组里面不能用in关键词,in 是判断对象属性是否存在,在数组里面就是判断索引是否在数组
[ ] 创建数组,value放入里面,多个值用,分隔。value可以是任意数据类型.
数组里面的vaue叫元素,没有一个元素都对应一个key(叫索引,下标),系统自动添加的,从0开始。
如果数组位置没有数据,是空位,索引会被保留。
1.1 一维数组
// 1.创建数组
var foods = ['apple','banana','pear'] // 方式一
var arr = new Array() // 方式二
var arr1 = new Array('a',12)
// 只传入一个数字时,它会默认当成要创建的长度
var arr2 = new Array(3) // [empty * 3]
console.log(typeof foods) // object
// 数组里面可以添加任何类型
var other = [1,2,3]
var goods = [
{name: '冰箱',
price: 3889
},
888,
'Anna',
other
]
console.log(goods)
// 查看数组的长度
console.log(goods.length) // 4
1.1.1 数组的 增删改查
var foods = ['apple','banana','pear']
// 1.访问数组 --两种方式(有区别)
console.log(foods[0]) //apple
console.log(foods.at(0)) //apple
console.log(foods[-1]) // undefined
// 会从后面数第几个元素
console.log(foods.at(-1)) // pear
// 2.数组添加内容
//修改值如果对应的索引不存在,则是添加元素。中间跳过的索引会自动添加空白位
foods[3] = 'orange'
console.log(foods[6]) // 读取不存在的下标,返回的是undefined
foods[16]="yyy" // 索引为16的位置添加元素,中间会添加空白位填充
// 3.数组修改内容
foods[2] = 'orange'
// 4. 数组删除内容
//delete 删除数组元素,会保留位置,一般不用delete删除
delete foods[1]// 删除1号索引的元素,该位置就变为空白位了。
1.2 数组的方法
1.2.1 Array()创建数组
Array是系统内置的一个数组对象(包含了很多操作数组的属性或者方法),同时也是一个构造函数
var arr1 = new Array["a","b","c","d"] // 把数组元素放入Array函数
var arr2 = new Array(4) // 传入一个number值的是设置数组的长度
1.2.2 .toString()数组转字符串
var arrs = ["a","b","c"]
console.log(arrs.toString()); //a,b,c(默认用,隔开)
1.2.3 数组的增删改查
重要:splice(index,num,el1,el2…) 删除指定索引的元素,可以在删除位置插入元素
index 是索引号
num是从index开始删除多个元素
el1,el2…是删除元素后在删除位置index插入的元素(可以插入多个),会返回删除的元素数值
var foods = ['apple','banana','pear']
// 尾部
// push 在数组的尾部添加
foods.push('222',666)
// pop 在数组的尾部删除 --一次只能删除一个
foods.pop()
// 头部
// unshift 在数组的头部添加
foods.unshift(999,'0101')
// shift 在数组的头部删除
foods.shift()
//产生一个新数组 不会改变原数组
foods.slice(1,-1)
// 打印数组的位置索引
foods.indexOf('banana')
// splice() 删除/插入元素
arrs.splice(1,2)// 从1号索引开始,删除2个元素
arrs.splice(1,1,"k","j")// 从1号索引开始,删除1个元素,在删除元素后面添加对应的元素
arrs.splice(1,0,"5",6,7)// 从1号索引开始,删除0个元素,在删除元素后面添加对应的元素
// 1. splice() 只有一个参数,从这个参数往后开始删除,删除内容会形成一个新数组
var foods = ['apple','banana','pear']
foods.splice(2) // ['pear']
// 2. splice() 有两个参数,从第一个参数的索引开始,删除几个元素
foods.splice(1,2) // ['apple']
// 3. splice() 超过两个参数
// 第二个参数不为 0 就是替换
// 替换内容超过索引个数,也会全部添加进去
foods.splice(1,2,'orange')
console.log(foods.splice(1,2,'orange')) // ['banana', 'pear']
console.log(foods) // ['apple', 'orange'] --替换后的数组内容
// 第二个参数为 0 就是新增
foods.splice(1,0,'&&&','###')
console.log(foods.splice(1,0,'&&&','###')) // [ ]
console.log(foods) // ['apple', '&&&', '###', 'banana', 'pear'] --新增后的数组内容
1.3 数组的遍历
for 循环遍历数组
for in 遍历数组 (for in 遍历数组性能开销较大,一般不用for in遍历数组)
//for 循环遍历
for(var i=0;i<arr2.length;i++){
console.log(i+":"+arr2[i])
// 找出数组里面的c元素
if(arr2[i]==="c"){
break
}
}
// for in 循环遍历
// 数组是一种特殊对象,in遍历的是数组的索引
var arr2=["a","b","c","d"]
for(i in arr2) {
console.log(i+":"+arr2[i])
}
1.4 数组的常用方法
数组是一种特殊对象,数组有内置的方法,方便操作数组。如push(),splice()等
1. join(“分隔符”)
数组可以按指定分隔符转字符串(默认是逗号分隔)
var arr2 = [1,2,3,'a']
//元素之间没有分隔符转字符串
console.log(arr2.join("")) //123a
console.log(arr2.join("#")) //1#2#3#a
2. concat(arr1,arr2,…) 合并多个数组
合并以后返回一个新数组
var arr1 = ['c','g']
var arr2 = [1,2]
var arr3 = arr1.concat(arr2)
//arr1 和arr2数组合并,返回新的数组,arr1和arr2数组不受影响
console.log(arr3,["5"]) //['c', 'g', 1, 2]['5']
3. reverse() 颠倒数组元素
将原数组的元素倒序排列,原数组会被改变
var arr2 = [1,2,3,4]
var re = arr2.reverse()
// 会把原数组元素倒序,并且返回原数组
console.log(arr2) //[4, 3, 2, 1]
console.log(re) //[4, 3, 2, 1]
4. slice(startIndex,endIndex ) 截取数组
截取数组中的一部分,返回截取后的数组,原数组不变
startIndex 截取的开始索引
endIndex截取的结束索引(该索引可省)。
var arr2 = [1,2,3,4]
//从索引为1开始到索引为2结束,就截取1个元素
var re = arr2.slice(1,2)
console.log(re) //[2]
// 原数组不变
console.log(arr2) //[1, 2, 3, 4]
5. forEach(function(item,index){}) 遍历数组
遍历数组元素,遍历一个元素,就执行一次回调函数。item是当前遍历的元素,index是遍历元素的索引。该方法不能用break中断,它会直接遍历完整个数组。
var arr2 = [1,2,3,4]
arr2.forEach(function(item){
//item表示当前正在遍历的数
console.log(item) //1 2 3 4
})
6. map(function(item,index){}) 遍历返回新数组
map是遍历数组元素,遍历一次就执行一次该方法,item是遍历的每一个元素,index是遍历元素的索引。
map() 返回一个新数组
返回数组的元素是回调函数return的值
var arr2 = [1,2,3,4]
var re = arr2.map(function(item){
return item + "-"
})
console.log(re);//['1-', '2-', '3-', '4-']
7. filter(function(item,index){return boolean}) 过滤数组
遍历原数组,遍历一个元素执行一次回调函数。item是遍历的每一个元素,index是遍历元素的索引
filter() 返回新数组
新数组里,回调函数return true则保留数组元素,如果为return false则删除当前元素。
// 可用来判断 奇/偶数
var arr2 = [1,2,3,4]
var re = arr2.filter(function(item){
if (item % 2 === 0){
return true // 偶数返回新数组
}
return false // 新数组里面删除非偶数的元素
})
console.log(re);//[2, 4]
8. reduce(function(a,b){return num}) 依次遍历数组
第一次遍历: a 是数组第一个元素,b第二个元素
第二次遍历: a 是上一次回调函数return返回的值,b是遍历次数+1的元素
// 一般用于求数组数值元素累加的和
var arr2 = [1,2,3,4]
var re = arr2.reduce(function(a,b){
console.log("a:"+a,"b:"+b); // a:1 b:2; a:3 b:3; a:6 b:4
return a + b
})
console.log(re);// 10
9. sort(function(a,b){return num}) 数组排序
步骤:
-
会遍历数组元素,遍历一次,执行一次回调函数
-
a,b是相邻的两个元素, 返回大于0的值,说明a大于b
-
由小到大排序:则是第一个元素在第二个元素后面
-
由大到小排序:则是第一个元素在第二个元素前面。
-
内部元素排序完后返回排序后的新数组,返回的数组就是一个有序数组
-
在原数组进行排序,返回的是原数组
var arr2 = [1,8,5,6,9,2]
// 由小到大排序
var re1 = arr2.sort(function(a,b){
return a - b // 如果前数大于后数,大于0则会交换a,b的位置
})
console.log(re1);// [1, 2, 5, 6, 8, 9]
// 由大到小排序
var re2 = arr2.sort(function(a,b){
return b - a
})
console.log(re2);// [9, 8, 6, 5, 2, 1]
10. some(function(item,index,arr){return boolean}) 查询某一个元素是否符合(存在)条件
一个符合全都符合
item是遍历的元素,index是索引,arr是当前的数组。是要有一个元素返回true,整个some函数返回值就是true,否则返回false
var arr2 = [1,8,5,6,9,2]
var re = arr2.some(function(item,index,arr){
if (item === 10){ // 不存在返回 false
return true
}
})
console.log(re); //false
11. every(function(item,index,arr){return boolean}) 所有元素符合某个条件返回true
全部符合才符合
item是遍历的元素,index是索引,arr是当前的数组。所有元素返回true,整个every函数返回值就是true,否则返回false
var arr2 = [1,"8",5,6,9,2]
var re = arr2.every(function(item){
return typeof(item) === "number" //有一个不满足都是false
})
console.log(re); //false
12. indexOf(element) 查看元素从前往后在数组中索引
查看元素在数组中(从左往右数)第一次出现的索引,如果有则返回元素索引,没有返回-1
一般用于查询数组是否包含某个元素
var arr2 = [1,"8",5,6,9,2,6,6,2]
console.log(arr2.indexOf(6)); //3
console.log(arr2.lastIndexOf(6)); //7
13. lastIndexOf(element) 查看元素从后往前在数组中的索引
查看元素在数组中(从右往左数)第一次出现的索引,如果有则返回元素索引,没有返回-1
14.数组的链式操作
只要数组的方法返回的值是一个数组,可以用链式操作
// users 对象按age由小到大排序,选出age大于12的并加入sex属性
var users = [
{id:0,name:"li",age:13},
{id:1,name:"wang",age:11},
{id:2,name:"zhao",age:10},
{id:3,name:"chen",age:12},
{id:4,name:"liu",age:13}
]
var arr = users.sort(function(a,b){ // 传入的是两个对象
return a.age - b.age // 对age进行从小到大的排序
}).filter(function(item){
return item.age >= 12 // 选出age大于12的
}).map(function(item){
item.sex = "女" //对它们加入一个sex属性
return item
})
console.log(arr);
1.5 数组的深浅拷贝
…(展开运算符) :可以进行浅拷贝
structuredClone() 方法:可进行深拷贝
// 单层深拷贝
const arr = [1,2,"a","k",7]
// 当调用slice()时,会产生一个新的数组对象,从而完成对数组的复制
var re = arr.slice()
console.log(re === arr); //false
//...(展开运算符) 可以进行浅拷贝
var arr1 = [...arr]
console.log(arr1); //[1,2,"a","k",7]
console.log(arr === arr1);// false
// 多层深拷贝
const arr1 = [1,"a",{name:"Anna",age:4},7,{name:"Jone",age:9}]
var res = arr1.slice()
// 外层地址不同,但内层对象的地址还是相同的,修改对象变量时,会互相影响
console.log(res === arr1); // false
// 只进行了浅拷贝
console.log(res[2] === arr1[2]); //true 说明里层的对象深拷贝不成功
// structuredClone() 方法可进行深拷贝
var res1 = structuredClone(arr1)
console.log(res1 === arr1); // false
console.log(res1[2] === arr1[2]);// false 深拷贝成功
十二、JSON
json 数据结果是js的一部分,体积小,解析方便,是现在web数据传输的主流方式。
JSON 对象 是js内置的标准库,主要是操作json数据
json数据就是一个按照一定规范书写的字符串,json数据类似js的对象数据,由键值对构成(key:value)
json数据规范:
json数据按照key:value的结果书写,key必需放在""(双引号)里面
最后一个成员的后面不能添加,(逗号)
value 值是一个字符串,必需添加双引号
value值是: 字符串,数值,布尔值,null,或者json字符串(不能是NaN,undefined,Infinity,function)
json数据的格式:
1. json字符串的对象格式
var user = '{"name":"Anna","age":14,"fname":"AA"}'
console.log(user);
2. json字符串的数组格式
var list = '["a","c",{"name":"XXX",age:20}]'
console.log(list);
3. JSON.parse(json) json数据转js对象
JSON.parse(json) 把json数据转为js对象(json反序列化)
var user = '{"name":"Anna","age":14,"fname":"AA"}'
user = JSON.parse(user)
console.log(user); //{name: 'Anna', age: 14, fname: 'AA'}
4. JSON.stringify() js对象转json数据
JSON.stringify() 把js对象转为json数据(json的序例化,会丢弃不符合json数据规范的属性)
var peo = {
name: "Mike",
age: 22,
// 下面两个不符合json转的时候会被丢弃
go: function(){},
family: undefined
}
peo = JSON.stringify(peo)
console.log(peo); //{"name":"Mike","age":22}
5. JSON的深拷贝
JSON 深拷贝对象或者数组(不符合json规范的属性会被抛弃)
var peo = {
name: "Mike",
age: 22,
go: function(){},
family: undefined
}
// 先把js对象转成JSON数据,再转成js对象 就可以深拷贝
var peo1 = JSON.parse(JSON.stringify(peo))
console.log(peo === peo1);// false