一、JS 基础
- JavaScript 是一种运行在客户端上 的脚本语言。
2. JavaScript 不需要编译,运行过程中由JS解释器(JS引擎)逐行来进行解释并运行。
3. JavaScript 执行逻辑:解释一行后立刻执行一行,若出错则停止执行,不会继续解释下一行。
4. ECMAScript:规定了JS的编程语法和基础核心知识,即JS语法的工业标准。
5. 单双引号的使用:在HTML中推荐使用双引号,而JavaScript中推荐使用单引号。二、JS 输入输出语句
alert('msg');
浏览器弹出警示框,归属浏览器。
2.prompt('msg');
浏览器弹出输入框,用户可输入信息,归属浏览器。
【注意】利用 prompt(还有表单) 获取的值的类型为字符串型!
3.console.log('msg');
浏览器控制台打印输出信息,归属浏览器。三、JS 变量
- 更新变量:一个变量被重新赋值后,它原有的值会被覆盖,变量值以最后一次赋的值为准。
2. 同时声明多个变量,只需写一个 var ,多个变量名之间使用英文逗号隔开。
3. 变量只声明不赋值,则该变量的内容为 undefined 。
4. 变量不声明、不赋值且直接使用(输出),JS引擎报错。
5. 变量不声明(没加var)但直接赋值使用(输出),能正常使用,JS引擎不报错; 该变量变为全局变量 。
6. 变量命名规范
- 由字母、数字、下划线( _ )、美元符号( $ )组成。
- 严格区分大小写。
- 不能以数字开头。
- 不能是关键字、保留字,例如 var、for、if、else、while 等。
- 尽量遵守驼峰命名法:首字母小写,后面单词的首字母需要大写,例如 myFirstName。
- 特别注意,尽管 name 不是关键字或保留字,但尽量不要用它作为变量名,因为某些浏览器的 name 有特殊含义。
四、JS 数据类型
1. JS 数据是动态类型
- JavaScript 是一种弱类型语言,即变量在程序运行过程中,其类型会根据等号右边的值来确定。
- JavaScript 拥有动态类型,这意味着同一个变量可用作不同的类型(可变的)。
2. 简单数据类型
① number:数字型,包含整型值和浮点值,默认值为 0。
② boolean:布尔值类型,包含 true 和 false ,默认值为 false。
③ string:字符串类型,用(单 / 双)引号括住的值,默认值为 ‘’(空字符串)。
④ null:空值,var a = null;
声明了变量a为空值。
⑤ undefined:未定义,var a; 声明了变量a但是没有赋值,此时 a = undefined。
【特别注意】NaN,属于number型,它由数字型值与非数字型值运算后产生,意思是 Not a Number。
【判断方法】isNaN();
//判断变量或值是否为【非数字】,是则返回 true,否则返回 false。3. 数字进制
① 八进制:数字前面加 0 ,例如 var num1 = 012; //换算为十进制是10
② 十六进制:数字前面加 0x ,例如 var num2 = 0x12; //换算为十进制是184. 字符串转义字符【需要写在引号里】
① \n 换行符 newline
② \ 斜杠 \
③ \’ 单引号 ‘
④ \” 双引号 “
⑤ \t tab缩进
⑥ \b 空格 blank5. 字符串类型的相关方法
① 计算字符串长度:字符串变量.length(空格与标点符号都算一个字符)。
② 字符串拼接:使用加号 + 进行拼接,可拼接其他数据类型的变量或值,结果必定是字符串类型。
③ 拓展:若使用其他算术运算符( - * / )会使字符串类型的数字被系统视作数字型,然后进行运算。console.log('LJM' + 'SB'); // 'LJMSB'
console.log('LJM' + 22); // 'LJM22'
console.log('LJM' + true); // 'LJMtrue'
var age = 22;
console.log('LJM' + age +'岁'); // 'LJM22岁'
6. boolean【布尔型】
① 只有两个值 true 和 false。
② 布尔型和数字型进行四则运算时,true 的值视为1,false 的值视为0。7. undefined【未定义】
① undefined 与字符串相加,结果为字符串,例如undefined + 'pink' = undefinedpink
② undefined 与数字型 / 布尔型相加,结果为 NaN。8. null【空】
① null 与字符串相加,结果为字符串,例如null + 'pink' = nullpink
② null 与数字型相加,结果为数字型,例如null + 1 = 1
③ null 与布尔型相加,结果为数字型,例如null + true = 1
、null + false = 0
9. 检测变量的数据类型【typeof】
【特别注意】var ljm = null; console.log(typeof ljm); //输出结果为 object
10. 数据类型的转换
1)转换为字符串型【常用第③种】
①toString()
使用方法:变量.toString()
②String()
使用方法:String(变量或值)
③ 利用加号 + 拼接空字符串 ‘’,实现字符串转换效果
2)转换为数字型【常用①、②】
① parseInt(string)
使用方法:parseInt(字符串类型的变量或值)
parseInt('3.94'); //结果为 3,去掉小数取整,且不会进位
parseInt('120px'); //结果为 120,去掉'px'
parseInt('rem120px'); //结果为 NaN,因为字符串开头为字母而不是数字,系统无法识别
② parseFloat(string)
使用方法:parseFloat(字符串类型的变量或值)
parseFloat('3.94'); //结果为 3.94,保留小数部分
parseFloat('120px'); //结果为 120,去掉'px'
parseFloat('rem120px'); //结果为 NaN,因为字符串开头是字母而不是数字,系统无法识别
③ Number()
使用方法:Number(字符串类型的变量或值)
④ 利用算术运算符( - * / )进行隐式转换。
3)转换为布尔型:Boolean(变量或值)
① 代表为空的值或否定的值会转换为 false,例如 空字符串’’ 、 空值null 、 数字0 、 否定值NaN 、 undefined 。
② 其余的值都会被转换为 true。
五、JS 算术运算符
1. 运算符
加减乘除(+ - * /);还有取余数(又称取模),符号为 %
2. 浮点数
- 浮点数值的最高精度为17位小数,但在进行算术运算时会出现精确度的问题;
因此有以下结论:不能直接拿浮点数来比较是否相等,因为精确度不确定。
3. 自增自减
前置自增自减【++变量、—变量】
- 后置自增自减【变量++、变量—】
① 单独使用时,前置与后置效果一样,都是自增1或自减1。
② 其他情况下,例如输出、循环、判断、与其他变量运算时,前置与后置效果有所区别。
- 前置:先变量自增自减,后表达式返回变量值
var age = 10; console.log(++age + 10); //输出21
- 后置:先表达式返回变量值,后变量自增自减
var age = 10; console.log(age++ + 10); //输出20
var a = 10; var b = a++ + ++a; /* 计算表达式1:a++,后置自增,故表达式1的返回值为10,随后a自增1,a = 10 + 1 = 11; 计算表达式2:++a,前置自增,故a先自增1,a = 11 + 1 = 12,随后表达式2返回值为12; 计算 b = a++ + ++a = 表达式1 + 表达式2 = 10 + 12 = 22。 */ console.log(b); // 输出22
4. 比较运算符【 = 小结】
① = 作用:赋值;用法:把右边的值赋给左边
② == 作用:判断;用法:判断两边的值是否相等,但 会把字符串型的数据转换为数字型 再判断
③ === 作用:全等;用法:判断两边的值和数据类型是否完全一致, 不会转换数据类型5. 短路运算【逻辑中断】
1)原理:当有多个子表达式(值)同时进行逻辑运算时,若前面子表达式的值可确定整个表达式的值,则不再计算后面的子表达式的值(提高运算效率)
2)逻辑与运算【&&】
- 语法:
表达式1 && 表达式2
- 如果表达式1的值为真,则返回表达式2的值;
console.log( 123 && 456 ); //输出456
- 如果表达式1的值为假,则返回表达式1的值;
console.log( 0 && 456 ); //输出0
3)逻辑或运算【 || 】
- 语法:
表达式1 || 表达式2
- 如果表达式1的值为真,则返回表达式1的值;
console.log( 123 || 456 ); //输出123
- 如果表达式1的值为假,则返回表达式2的值;
console.log( 0 || 456 ); //输出456
6. 运算符优先级
① 小括号 ()
② 一元运算符 ++ — !
③ 算数运算符 先 * / % 后 + -
④ 关系运算符 > >= < <=
⑤ 相等运算符 == != === !==
⑥ 逻辑运算符 先 && 后 ||
⑦ 赋值运算符 =
⑧ 逗号运算符 ,六、JS 数组
1. 创建数组的方法
① 利用 new 关键字创建空数组:var arr = new Array();
② 利用数组字面量 [ ] 创建数组:
//创建空数组
var arr1 = [ ];
//创建带数组元素的数组,元素可以是任意类型的数据
var arr2 = [1, 2, 'LJM傻逼', true];
2. 数组索引
- 即数组下标,从 0 开始,用来访问数组元素的序号。
若访问数组元素时超过了索引上限,则访问的值变为 undefined。
3. 遍历数组
① for
最简单的一种循环遍历方法,也是使用频率最高的一种,可优化
var arr = [1, 2, 3, 4, 5, 6] for(var i = 0; i < arr.length; i++) { console.log(arr[i]) } // 1 2 3 4 5 6
优化:使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显
var arr = [1, 2, 3, 4, 5, 6] var len = arr.length for(var i = 0; i < len; i++) { console.log(arr[i]) } // 1 2 3 4 5 6
② for … in …
这个循环用的人也很多,但是效率最低(输出的 key 是数组索引)
var arr = ['我', '是', '谁', '我', '在', '哪'] for(var key in arr) { console.log(key) } // 0 1 2 3 4 5
③ for … of … (ES6)
性能要好于 for … in … ,但仍然比不上普通的 for 循环(输出的 key 是元素值,但不能循环对象)
var arr = ['我', '是', '谁', '我', '在', '哪'] for(var key of arr) { console.log(key) } // 我 是 谁 我 在 哪
④ forEach
数组里的元素个数有几个,该方法里的回调就会执行几次
- 第一个参数是数组里的元素,第二个参数为数组里元素的索引,第三个参数则是它自己
数组自带的遍历方法,虽然使用频率略高,但是性能仍然比普通循环略低
var arr = [1, 2, 3, 4, 5, 6] arr.forEach(function (item, idnex, array) { console.log(item) // 1 2 3 4 5 6 console.log(array) // [1, 2, 3, 4, 5, 6] (输出6次) })
⑤ map
遍历每一个元素并返回到新数组里(可以返回处理后的元素)
- 返回的新数组和旧数组的长度是一样的
使用比较广泛,但其性能还不如 forEach
var arr = [1, 2, 3, 4, 5, 6] var newArr = arr.map(function (item, idnex) { return item * item }) console.log(newArr) // [1, 4, 9, 16, 25, 36]
⑥ filter
遍历数组,过滤出符合条件的元素并返回一个新数组 ```javascript var arr = [ { id: 1, name: ‘买笔’, done: true }, { id: 2, name: ‘买笔记本’, done: true }, { id: 3, name: ‘练字’, done: false } ]
var newArr = arr.filter(function (item, index) { return item.done })
console.log(newArr) // [{ id: 1, name: ‘买笔’, done: true },{ id: 2, name: ‘买笔记本’, done: true }]
⑦ **some**
- 遍历数组,只要有一个以上的元素满足条件就返回 true,否则返回 false
```javascript
var arr = [
{ id: 1, name: '买笔', done: true },
{ id: 2, name: '买笔记本', done: true },
{ id: 3, name: '练字', done: false }
]
var bool = arr.every(function (item, index) {
return item.done
})
console.log(bool) // true
⑧ every
- 遍历数组,每一个元素都满足条件则返回 true,否则返回 false ```javascript var arr = [ { id: 1, name: ‘买笔’, done: true }, { id: 2, name: ‘买笔记本’, done: true }, { id: 3, name: ‘练字’, done: false } ]
var bool = arr.every(function (item, index) { return item.done })
console.log(bool) // false
⑨ **find (ES6)**
- 遍历数组,返回符合条件的第一个元素,如果没有符合条件的元素则返回 undefined
```javascript
var arr = [1, 1, 2, 2, 3, 3, 4, 5, 6]
var num = arr.find(function (item, index) {
return item === 3
})
console.log(num) // 3
⑩ findIndex (ES6)
- 遍历数组,返回符合条件的第一个元素的索引,如果没有符合条件的元素则返回 -1 ```javascript var arr = [1, 1, 2, 2, 3, 3, 4, 5, 6] var num = arr.findIndex(function (item) { return item === 3 })
console.log(num) // 4
<a name="uErDw"></a>
#### 4. 获取数组长度【数组名.length】
<a name="NSBBv"></a>
#### 5. 数组中添加元素
① 由于 length 属性是可读写的,所以可以通过修改它来实现数组扩容。<br />② 也可以直接追加数组元素,切记必须赋值。<br />③ 但是直接给数组名赋值的话,数组元素会被清空并覆盖。
<a name="zjHMv"></a>
#### 6. 数组冒泡排序算法
```javascript
var arr = [3,5,1,2,4];
// 从小到大排序
for (var i=0; i<arr.length; i++) {
for (var j=0; j<arr.length-i; j++) {
if (arr[j] > arr[j+1]) {
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = arr[j];
}
}
}
// 从大到小排序
for (var i=0; i<arr.length; i++) {
for (var j=0; j<arr.length-i; j++) {
if (arr[j] < arr[j+1]) {
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = arr[j];
}
}
}
七、JS 函数
1. 声明函数【关键字:function】
① 关键字声明函数
function 函数名(){
// 函数体
}
// 函数调用
函数名();
② 表达式声明函数(匿名函数,即没有函数名)
var fun = function(){
// 函数体
}
// 函数调用
fun(); // fun是变量名,不是函数名,所以fun可存储返回值
2. 函数形参与实参个数不匹配
① 函数的形参个数与实参个数可以不匹配,但结果难以预计。
② 若实参个数多于形参个数,不影响函数执行,多余的实参无效。
③ 若实参个数少于形参个数,缺少的形参的值默认为undefined,会影响函数最终结果。
3. 函数返回值【关键字:return】
① return只能返回一个值,且返回的是最后一个值,需要返回多个值的话用数组即可。
return num1, num2, num3; // 返回的是 num3
② return除了能返回数值,还有终止函数作用。
③ 若一个函数没有return,则默认返回undefined。
4. 总结【break、continue、return】
① break:结束当前的循环体(仅一层),或结束switch语句。
② continue:跳出本次循环(仅一层),继续执行下次循环。
③ return:在函数内,不仅可以退出循环(多层),还能返回一个值,并结束函数的运行。
5. arguments 对象【函数内置对象】
① arguments 对象中存储了传递的所有实参
② arguments 对象是一个伪数组,具有length属性和数组索引,但不能用真数组的一些方法。
6. 立即执行函数
【说明】不需要调用,一旦所属 js 文件被引用后立马就能自己执行的函数(立即执行函数之间需要使用 ; 隔开)
【作用】
- 能够独立创建一个作用域,在立即函数内部的所有变量都是局部变量;
- 不同的立即执行函数内的同名变量互不影响,系统也不会报错,避免了不同 js 文件之间的函数冲突;
- 函数执行完后,系统就能立即清除里面的所有局部变量,节省内存。
【写法1】(function(形参){ 函数体... })(实参);
(function(a,b) {
console.log(a + b); // 输出 3
})(1,2);
【写法2】(function(形参){ 函数体... }(实参));
(function(c,d) {
console.log(c + d); // 输出 7
}(3,4));
八、JS 作用域
1. 作用域
① 全局作用域:整个标签,或者是外部的一个单独的 js 文件
② 局部作用域:即函数内部的作用域。
【注意】:ES6开始,JavaScript才新增了块级作用域( if、for、while、switch的{ }内部 )
2. 变量的作用域
① 全局变量:在任何作用域下都能使用的变量;在全局作用域下 var 声明的变量就是全局变量。
② 局部变量:只能在局部作用域下(函数内部)才能使用的变量;函数的形参属于局部变量。
【注意】:在函数内部,没有 var 声明然后直接赋值的变量,属于全局变量!
3. 两种变量的执行效率
① 全局变量只有在浏览器关闭的时候才会被销毁,比较占内存资源。
② 局部变量在程序执行完毕后就会被立即销毁,比较节约内存资源。
4. 作用域链
根据内部函数可访问外部函数的变量的机制,JS用链式查找方式(就近原则)来决定内部函数访问的是外部的哪一个变量。
var num = 123; // 全局变量num
// 外部函数 f1
function f1() {
var num = 456; // 局部变量num
// 内部函数 f2
function f2 () {
console.log(num); // 输出结果:456(若删去局部变量num,则输出123)
}
f2();
}
f1();
九、JS 预解析
1. JS 解释器运行步骤
① 预解析:把 js 代码里所有的 var 和 function 提升到当前作用域的最前面。
② 代码执行:按照代码书写的顺序从上往下执行。
2. 预解析
① 预解析分为:变量预解析 和 函数预解析
② 变量预解析:又称变量提升,就是把所有的变量声明提升到当前作用域的最前面,但不提升赋值操作。
// 原代码
console.log(num);
var num = 123;
// 预解析后
var num;
console.log(num); // 输出结果 undefined
num = 123;
③ 函数预解析:又称函数提升,就是把所有的函数声明提升到当前作用域的最前面,但不调用函数。
【注意】必须弄清楚两种函数声明的预解析差异!
- 关键字声明函数的预解析:把整个函数声明提到当前作用域的最前。
- 表达式声明函数的预解析:只是把变量声明提到当前作用域的最前。
【综合案例1】
// 原代码
var num = 10;
fun();
function fun( ) { // 关键字声明函数
console.log(num);
var num = 20;
}
// 预解析后
var num;
function fun() {
var num;
console.log(num); // 输出的是局部变量num
num = 20;
}
num = 10;
fun(); // 输出结果 undefined
【综合案例2】
// 原代码
say();
var say = function( ) { // 表达式声明函数
console.log('函数表达式');
}
say();
function say( ) { // 关键字声明函数
console.log('函数声明');
}
say();
// 预解析后
var say; // 表达式声明函数的预解析,say的值为undefined
function say() { // 关键字声明函数的预解析
console.log('函数声明');
}
say(); // 输出:函数声明
say = function() { // 给say赋值新的函数
console.log('函数表达式');
}
say(); // 输出:函数表达式
say(); // 输出:函数表达式
【综合案例3】
// 原代码
f1( );
console.log(c);
console.log(b);
console.log(a);
function f1( ) {
var a=b=c=9;
console.log(a);
console.log(b);
console.log(c);
}
// 预解析后
function f1( ) {
var a;
a=b=c=9;
// 相当于 var a=9; b=9; c=9; 此时变量b和变量c被视为全局变量,而变量a是局部变量
// 集体声明 var a=9, b=9, c=9; 这种才符合规范,且a b c都是局部变量
console.log(a);
console.log(b);
console.log(c);
}
f1( );
console.log(c);
console.log(b);
console.log(a);
// 输出结果 9 9 9 9 9 报错(a is not defined)
十、JS 对象
1. 概念
- 定义:对象是一组无序的相关属性和方法的集合
-
2. 创建与调用方法
① 利用对象字面量 { } 创建对象
【例1】创建一个空对象var obj = { };
【例2】创建一个有属性和方法的对象【用冒号 : 赋值、相互之间用逗号 , 隔开】var obj = { uname: '笨比LJM' , age: 22 , sex: '男' , sayHi: function(){ console.log('hi~'); } }
② 利用 new Object 创建对象
【例1】创建一个空对象var obj = new Object( );
【例2】创建一个有属性和方法的对象【用等号 = 赋值、相互之间用分号 ; 隔开】var obj = new Object(); obj.uname = '笨比LJM'; obj.age = 22 ; obj.sex = '男' ; obj.sayHi = function(){ console.log('hi~'); }
③ 利用构造函数创建对象【这一过程称之为 对象的实例化】
【格式】function 构造函数名(形参) { this.属性名 = 值; this.方法名 = function(){} } var 对象名 = new 构造函数名(实参);
【注意】
构造函数名字首字母要大写
- 构造函数不需要写 return 也可以返回结果
- 每次调用构造函数都必须使用关键字 new
④ 创建 / 调用对象的属性
【例】obj.uname
或 obj['uname']
【注意】创建新属性时没有赋值的话,默认值为 undefined
【区别】
对象名.属性名
这里的 属性名 是静态数据,不能由变量来代替;对象名['属性名']
这里应该把 ‘属性名’ 看作一个整体,其本质是字符串,可由变量来代替,常用这种写法来动态创建新属性;- 数组表示法在存取属性值时会进行表达式运行;而点表示法是直接存取属性值,理论上执行效率会比数组表示法高。
⑤ 调用对象的方法【切记要加上小括号( ),不加则返回方法的定义】
【例】obj.sayHi()
或 obj['sayHi']()
3. [变量 & 属性] [函数 & 方法] 的区别
① 变量:可存储数据,单独声明,需要 var,需要赋值,使用格式为 变量名。
② 属性:可存储数据,依靠对象,不需 var,需要赋值,使用格式为 对象名.属性名。
③ 函数:可实现某种功能,单独声明,调用格式为 函数名( )。
④ 方法:可实现某种功能,依靠对象,调用格式为 对象名.方法名( )。
4. 遍历对象【for - in 语句】
【格式】for (变量 in 对象) { 循环体 }
for (var key in obj) { // key 是一个自定义的变量
console.log(key); // 输出变量 key,得到的是所有属性名 or 方法名
console.log(obj[key]); // 输出 obj[key],得到的是所有属性值 or 方法的定义
}
5. 内置对象
① JavaScript语言自带的一些对象,为开发者提供一些常用的功能(属性和方法)。
② 常见的内置对象:Math、Date、Array、String。
③ MDN文档查询【https://developer.mozilla.org/zh-CN/】
- 查阅该方法的功能
- 查看里面参数的意义和类型
- 查看返回值的意义和类型
④ Math 对象 【数学】
- Math 对象不需要 new 来调用,直接使用其属性和方法即可。
【例1】console.log(Math.PI);
// 调用Math对象的圆周率属性并输出
【例2】console.log(Math.max(1,99,8));
// 调用Math对象的求最大值方法,输出99
- 常用方法
Math.abs();
// 取绝对值,会把字符串型的参数转化为数字型,参数无意义则返回 NaNMath.floor();
// 向下取整,最终返回的是整数Math.ceil();
// 向上取整,最终返回的是整数Math.round();
// (正数)四舍五入、(负数)五入六舍,最终返回的是整数Math.random();
// 返回一个随机小数,范围 [0,1) ,不带参数
【拓展】获取两个整数之间的随机整数,包含两个整数在内
function getRandomInt(min, max){
return Math.floor( Math.random() * (max-min+1) ) + min;
}
// 可运用这个方法实现随机点名:array[getRandomInt(0, array.length-1)]
⑤ Date 对象 【日期 / 时间】
- Date对象必须要用 new 来创建(构造函数)。
- 创建方法:
var date = new Date();
- 如果不带参数,则返回系统的当前时间
- 带参数,字符串型,例如 ‘1998-12-12 20:33:41’【推荐写法】
- 带参数,数字型,例如 1998,12,12【不推荐,月份存在误差(0-11)】
- 常用方法
dateObj.getFullYear();
// 获取当前年份dateObj.getMonth();
// 获取当前月份(0-11)dateObj.getDate();
// 获取当前日期dateObj.getDay();
// 获取当前星期(周日0,周一到周六1-6)dateObj.getHours();
// 获取当前小时(24小时制)dateObj.getMinutes();
// 获取当前分钟dateObj.getSeconds();
// 获取当前秒钟
【拓展】封装一个函数,返回当前的年月日星期几,格式:2020年10月24日 星期六
function getDatesNow(){
var dateObj = new Date( );
var year = dateObj.getFullYear();
var month = dateObj.getMonth() + 1;
var date = dateObj.getDate();
var day = dateObj.getDay();
var dayArray = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
return '今天是' + year + '年' + month + '月' + date + '日 ' + dayArray[day];
}
【拓展】封装一个函数,返回当前的时分秒,格式:08:08:08
function getTimeNow(){
var time = new Date(); // 创建一个Date对象
var h = time.getHours();
h = h < 10 ? '0' + h : h; // 若时数小于10,则在前面补0
var m = time.getMinutes();
m = m < 10 ? '0' + m : m; // 若分钟小于10,则在前面补0
var s = time.getSeconds();
s = s < 10 ? '0' + s : s; // 若秒钟小于10,则在前面补0
return h + ':' + m + ':' + s;
}
- 获取日期的总毫秒数
【说明】Date对象是从1970年1月1日( 世界标准时间 )开始计算的毫秒数,利用毫秒数计算时间最精确
【用法】这个毫秒数又称“时间戳”,因为时间一直在流逝,所以这个毫秒数必定不会重复。
【写法一】
- 调用Date对象的方法:
dateObj.valueOf();
或dateObj.getTime();
【写法二】
- 常用的简单写法:
var dateMS = +new Date();
- 无参数,则返回当前时间的总毫秒数;
- 带参数,则返回参数所表示时间的总毫秒数。
【写法三】
- HTML5新增的写法:
console.log(Date.now());
【拓展】封装一个倒计时函数,由用户输入倒计时的日期。
function countDown(time){
var nowTime = +new Date(); // 返回当前时间的总毫秒数
var inputTime = +new Date(time); // 返回用户输入的日期的总毫秒数
var times = (inputTime - nowTime) / 1000; // times是时间差,并转换为秒数
if (times <= 0){
return '倒计时结束!';
}
else {
var d = parseInt(times / 60 / 60 / 24); // 天数
d = d < 10 ? '0' + d : d;
var h = parseInt(times / 60 / 60 % 24); // 时数(剩余不足一天的时数)
h = h < 10 ? '0' + h : h;
var m = parseInt(times / 60 % 60); // 分钟数(剩余不足一小时的分钟数)
m = m < 10 ? '0' + m : m;
var s = parseInt(times % 60); // 秒钟数(剩余不足一分钟的秒钟数)
s = s < 10 ? '0' + s : s;
return d + '天' + h + '时' + m + '分' + s + '秒';
}
}
console.log(countDown('2020-10-24 20:33:41'));
⑥ Array 对象 【数组】
- Array 对象可以使用 new 来创建(构造函数)
var arr1 = new Array();
// 创建了一个空数组,没有数组元素,数组长度为0var arr2 = new Array(2);
// 创建了一个空数组,有2个空数组元素,数组长度为2var arr3 = new Array(2,3);
// 创建了一个非空数组,有2个数组元素[2,3],数组长度为2
- Array 对象还可以使用数组字面量 [ ] 来创建(详情回看第六点)
- 检测是否为数组对象
- 运算符:
变量名 instanceof Array;
// 返回值 true 或 false - 方法:
Array.isArray( 参数 或 变量名 );
// 返回值 true 或 false;优先使用这种方法,IE9以上
- 运算符:
- 添加删除数组元素的方法
arrObj.push(参数);
// 在数组末尾添加一个或多个元素,返回新的数组长度arrObj.pop();
// 删除数组最后一个元素,使数组长度减1,无参数,返回所删除的元素值arrObj.unshift(参数);
// 在数组开头添加一个或多个元素,返回新的数组长度arrObj.shift();
// 删除数组第一个元素,使数组长度减1,无参数,返回所删除的元素值
数组排序的方法
arrObj.reverse();
// 翻转数组,返回新的数组(会改变原数组)arrObj.sort();
// 排序- 无参数,将元素转换为字符串,再按各个字符的Unicode位点排序,返回新的数组(会改变原数组)
- 带参数,实现传统排序的功能,示例如下
arrObj.sort(function(a,b) { return a-b; // 升序排列 return b-a; // 降序排列 });
数组索引的方法
arrObj.indexOf(元素);
// 查找给定元素的第一个索引,存在则返回索引号,不存在则返回-1arrObj.lastIndexOf(元素);
// 查找给定元素的最后一个索引,存在则返回索引号,不存在则返回-1
【拓展:数组去重算法】
【原理】遍历旧数组,拿着旧数组的元素去查询新数组,若不重复则把该元素 push 进新数组里。
【核心】利用 indexOf( ) 方法来判断元素是否重复
function unique(array) {
var newArr = [];
for (var i = 0; i < array.length; i++) {
if (newArr.indexOf(array[i]) === -1) {
newArr.push(array[i]);
}
}
return newArr;
}
- 数组转换为字符串的方法
arrObj.toString();
// 无参数,用英文逗号分隔每一项,返回一个字符串arrObj.join('分隔符');
// 用自定义的分隔符(无参数则默认逗号)分隔每一项,返回一个字符串
- 其他数组方法
arrObj1.concat( arrObj2[, arrObj3, ...] );
// 连接两个或多个数组,返回一个新数组,不影响原数组。arrObj.slice( [begin[, end]] );
- 提取数组元素,begin(包含) 与 end(不包含) 皆为数组索引,返回一个新数组,不影响原数组。
- 若 begin / end 为负数,则表示从原数组中的倒数第几个元素开始/结束提取。
- 若 begin 大于原数组的长度,则会返回空数组。
- 若省略 begin 和 end,则从索引0开始提取所有元素(即复制原数组)。
- 若省略 end,则会一直提取到原数组末尾。若 end 大于原数组的长度,也是会一直提取到原数组末尾。
arrObj.splice( start[, deleteCount[, item1[, item2 ...]]] );
- 可删除或替换现有元素,也可原地添加新的元素,返回被删除元素组成的数组(没有删除元素,则返回空数组),会改变原数组。
- start:指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容。
- deleteCount:整数,表示要移除的数组元素的个数。若是0或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
- item:要添加进数组的元素,从 start 位置开始。如果不指定,则 splice( ) 将只删除数组元素。
⑦ String 对象 【字符串】
基本包装类型:就是把基本数据类型包装成为复杂数据类型,使其拥有了属性和方法。适用基本包装类型的有:string、number、boolean。
// 平时常见的代码 var str = 'LJMsb'; console.log(str.length); // 按道理基本数据类型没有属性和方法,对象才有,但这两行代码能正常执行 // 这是因为JavaScript解释器会把基本数据类型包装成为复杂数据类型,过程如下: var temp = new String('LJMsb'); // 1. 生成临时变量,并使其变为复杂数据类型 str = temp; // 2. 再赋值给我们声明的字符变量 temp = null; // 3. 最后销毁临时变量
字符串的不可变
指的是值的不可变,虽然看上去可以改变某个字符串变量的值,实际上是地址变了,在内存中开辟了一个新的内存空间来放置新的字符串值,旧的还占着原本的内存。 故实际开发中要尽可能的减少字符串的修改或拼接行为,以免影响代码运行效率。
根据字符返回位置( 索引号 )
strObj.indexOf('要查找的字符'[, 开始查找的位置]);
// 返回指定内容在原字符串中的位置,若找不到则返回-1。开始查找的位置,可选,填的是索引号strObj.lastIndexOf('要查找的字符');
// 从后往前找,只找第一个匹配的,返回指定内容在原字符串中的位置,若找不到则返回-1
【拓展:查找字符串内某个字符的所有位置及其出现的次数】
var str = 'abcceocpuowojbk';
var times = 1; // 计算次数
var indexFind = str.indexOf('o'); // 查找第一个目标字符的位置
while (indexFind !== -1) {
console.log( '第' + times + '次:' + indexFind );
index = str.indexOf('o', index+1); // 从下一个字符开始继续查询
times++;
}
- 根据位置( 索引号 )返回字符
strObj.charAt(index);
// 返回指定位置的字符,index为索引号strObj.charCodeAt(index);
// 返回指定位置的字符的ASCII码,index为索引号- strObj[ index ]; // HTML5新增,返回指定位置的字符,index为索引号;IE8+支持
【拓展:判断一个字符串中出现次数最多的字符,并统计其次数】
【原理】把每个字符都存储为一个对象的属性。若对象没有该属性,则新建一个并赋值1;若属性存在则属性值+1。最后遍历对象即可获取出现最多的字符及其出现次数。
【核心算法】strObj.charAt( index ); 、for-in语句(用于遍历对象)
var str = 'abcceocpuowojbko';
var charObj = { }; // 创建一个空对象
for (var i=0; i<str.length; i++) {
var chars = str.charAt(i); // 获取索引号为 i 的字符
if ( charObj[chars] ) {
charObj[chars]++; // 该字符对应的属性存在,则属性值+1
} else {
charObj[chars] = 1; // 该字符对应的属性不存在,则新建一个并赋值为1
}
}
console.log(charObj); // 输出结果 { a:1, b:2; c:3, e:1, o:4, p:1, u:1, w:1, j:1, k:1 }
// 遍历对象
var max = 0;
var charFind = '';
for ( var key in charObj ) {
if ( charObj[key] > max ) {
max = charObj[key]; // 得到的是属性值
charFind = key; // 得到的是属性名
}
}
console.log('最多的字符是' + charFind); // 输出结果 最多的字符是o
console.log('出现次数是' + max + '次'); // 输出结果 出现次数是4次
- 字符串常用操作方法
strObj1.concat(strObj2[, strObj3 ...]);
// 拼接字符串,但实际开发中常用 + 拼接strObj.substr(startIndex, length)
; // 提取字符串,从索引号 startIndex 开始,提取长度为 lengthstrObj.replace('被替换的字符' , '替换成什么字符');
- 替换字符,只能替换符合要求的第一个字符,无法替换则返回-1
- 可利用循环语句
while(str.replace(...) !== -1)
来替换一个字符串内所有符合要求的字符
strObj.split('分隔符');
// 把字符串转换为数组(与arrObj.join();
相反),可把有规律的分隔符的字符串转换为数组strObj.toUpperCase();
// 转换大写strObj.toLowerCase();
// 转换小写十一、基本数据类型与复杂数据类型
基本数据类型:string、number、boolean、undefined、null【null是对象,空对象】
① 又称 简单数据类型 或 值类型,因为在变量中存储的是【值本身】。
② 当我们想创建一个对象但不知道给什么属性或方法时,可以先赋值 null。
③ 由操作系统自动分配、释放、存放函数的参数值、局部变量的值等,操作方式类似于【栈】。
④ 变量的值就直接存放于【栈】内。
复杂数据类型:Object、Array、Date 等
① 又称 引用类型,因为在变量中存储的只是用于引用属性或方法的【地址】。
② 通过 new 关键字创建的对象(系统对象、自定义对象)都属于复杂数据类型。
③ 一般由程序员分配释放,若程序员不释放,则由垃圾回收机制来回收内存空间,操作方式类似于【堆】。
④ 变量存放于【栈】内的数据是地址,通过这个地址才可以访问【堆】内的数据(值)。
【注意】由以上描述可知,复杂数据类型与C语言的指针相似,故以后遇到把复杂数据类型作为函数的实参进行传递时,传递给形参的是地址,那么在函数内进行的数据修改是直接作用于【堆】内的数据,所以说这个修改的效果是永久的。而把基本数据类型作为函数的实参进行传递时,是在【栈】内复制一份数据后再传给形参,那么在函数内进行的数据修改仅作用于形参,对实参无效。