基础知识(一)
JS的书写位置
与CSS类似,可以写在多个位置
- 行内式,也就是直接写在元素的内部(不建议使用)
- 内嵌式,写在head元素中(学习时常用)
- 外部式,即将代码写在外部的.js文件中(JS代码量大时使用)
JS的注释
和c、c++相同
- // 单行注释,快捷键ctrl + /
- /**/ 多行注释,快捷键shift + alt + a
JS常用输入输出语句
- prompt(info),浏览器弹出的输入框
- alert(msg),浏览器弹出的警示框,可输出信息
- console.log(msg),用于控制台打印信息
变量
变量的本质
变量是程序在内存中申请的一块用于存放数据的空间
变量的使用
声明变量
var name;
给变量赋值
name = 'Kobe';
声明变量时初始化
var name = 'Kobe';
同时声明多个变量
var age = 17, name = 'Kobe';
变量命名规范
- 变量名必须有意义
- 由字母、数字、下划线和$组成
- 不能以数字开头
- 不能是关键字或保留字
- 遵循驼峰命名法
JS数据类型
JS是动态语言,不需要提前声明变量的类型,这意味着同一个变量可以用作不同的类型
JS的数据类型分为两类
- 简单数据类型(Number、String、Boolean、Undefined、Null)
- 复杂数据类型(Object)
Number
数字型,包含整型和浮点型,默认值为0
特殊值
- Infinity,无穷大
- -Infinity,无穷小
- NaN,Not a Number,表示一个非数值
相关方法
- isNaN(),用来判断非数字,返回值为Boolean类型
String
字符串,默认为一个空的字符串
单引号和双引号在语法上都成立,不过由于HTML标签中的属性使用的是双引号,所以推荐对JS使用单引号
转义符
- \n,换行
- \\,表示单个\
- \',' 单引号
- \"," 双引号
- \t,tab缩进
- \b,blank空格
字符串长度
通过字符串的length属性来获取字符串的长度
var message = 'Hello, world!';
alert(message.length);//显示13
字符串拼接
通过 + 进行拼接
字符串 + 任意类型数据 = 新字符串,拼接前会把其他类型转换成字符串类型,然后进行拼接
字符串常与变量进行拼接
Boolean
布尔类型,true(1) & false(0),默认值为false
布尔类型和数字型相加时,实际参与的true的值为1,false的值为0
var flag = true;
console.log(flag + 1);//结果为2
Undefined
当声明了一个变量但是没有对其赋值时,变量值为Undefined
var str;
console.log(str);//结果为undefined
undefined类型与数字型相加时,结果为NaN
var variable = undefined;
console.log(variable + 1);//NaN
console.log(variable + true);//NaN
Null
空类型与数字型相加时,结果等于数字型的值
var variable = null;
console.log(variable + 1);//1
console.log(variable + true);//1
获取变量数据类型
利用typeof来获取数据所属类型
var num = 10;
console.log(typeof(num));//结果为number
var tim = null;
console.log(typeof(tim));//结果为object
数据类型转换
转换成字符串类型
toString()
var num = 1;
alert(num.toString());
String()强制转换
var num = 1;
alert(String(num));
隐式转换,通过加号拼接得到字符串
var num = 1;
alert(num + 'string');
转换成数字型
parseInt(string)函数,将字符串转换成整数类型
console.log(parseInt('3.14')); //取整,结果为3
console.log(parseInt('120px')); //去除px,结果为120
console.log(parseInt('rem120px')); //NaN
parseFloat(string)函数,将字符串转换成浮点数类型
//与parseInt()类似,只不过转换浮点数时不会取整
console.log(parseFloat('3.14')); //结果为3.14
console.log(parseFloat('120px')); //去除px,结果为120
console.log(parseFloat('rem120px')); //NaN
Number()强制转换
var str = '123';
console.log(Number(str)); //数字类型的123
隐式转换,利用算术运算 - * /实现
console.log('12' - 1); //11
console.log('123' - '1'); //122
console.log('123' * 1); //123
转换成布尔型
Boolean()函数,将其他类型转换成布尔类型
//代表空、否定的值会被转换成false,其余的值转换成true
console.log(Boolean('name')); //true
console.log(Boolean(12)); //true
console.log(Boolean('')); //false
console.log(Boolean(0)); //false
console.log(Boolean(NaN)); //false
console.log(Boolean(null)); //false
console.log(Boolean(undefined)); //false
运算符
算数运算符
- +
- -
- *
- /
- % 取余
在进行算数运算时,浮点数的精确度不如整数,会有精度缺失问题,所以无法直接判断两个浮点数是否相等
自增/减运算符
前置自增
var num = 0;
++num; //效果上等同于 num = num + 1;
var age = 20;
console.log(++age); //输出值21,先自增,后返回值
后置自增
var num = 0;
num++; //效果上也等同于 ++num 和 num = num + 1;
var age = 20;
console.log(age++); //输出值20,先返回原值,后自增
递减运算的规则类似,可参考递增运算
比较运算符
- <
- >
- <=
- >=
- == 判断值相等即可
console.log(1 == 1); //true
console.log(1 == '1'); //true,默认会转换数据类型,将字符串转换成数字型
- !=
- === 要求值和类型完全一致
console.log(1 === 1); //true
console.log(1 === '1'); //false
- !==
比较运算后会返回一个布尔值
逻辑运算符
- && 与
- || 或
- ! 非
短路运算(逻辑中断)
多个表达式或值进行逻辑运算时,当左边的表达式可以确定结果时,便不再运算右边的表达式
- 表达式1 && 表达式2
//如果表达式1为真,返回表达式2
//如果表达式1为假,返回表达式1
console.log(123 && 456); // 456
console.log(0 && 456); // 0
- 表达式1 || 表达式2
//如果表达式1为真,返回表达式1
//如果表达式1为假,返回表达式2
console.log(123 || 456); // 123
console.log(0 || 456); // 456
需要注意,短路运算会影响程序的运行结果
var num = 0;
console.log(123 || num++); // 123
console.log(num); // 0 程序没有进行num++操作便以中断
赋值运算符
- =
- +=
- -=
- *=
- /=
- %=
运算符优先级
优先级由高到低排列
- ()
- 一元运算符:++、--、! (! 的优先级很高)
- 算数运算符:先 * / %,后 + -
- 关系运算符:> < >= <=
- 相等运算符:== != === !==
- 逻辑运算符:先&& 后||
- 赋值运算符:=
- ,
分支结构
在使用switch时需要注意以下几点
- switch() 中的表达式常使用变量
- 表达式的值和case的值只有在全等(===)时才匹配,即值与数据类型都一致
- 每个case中需要加上break,如果没有break则在执行完当前case后会继续执行下一个case
循环结构
- for
- while
- do while
continue关键字
用于立即跳出本次循环,继续下一次循环(本次循环中continue之后的代码就不会再被执行)
break关键字
用于立即跳出整个循环体
需要注意的是,当存在多重循环时,break只能跳出最内层的循环体
数组
创建数组
使用new关键字来创建
var arr = new Array(); // 创建一个空的数组
使用数组字面量来创建
var arr = []; // 空数组 var arr1 = [1, '2', 3]; // 初始化数组,可存放各种类型的数据
获取数组元素
通过索引(数组下标)来获取元素,下表从0开始
数组长度
可以通过数组的length属性来获取数组的长度
var arr = [1, 2, 3];
alert(arr.length); // 3
length属性是可读写的
数组中新增元素
通过修改length实现
var arr = ['red', 'green', 'blue']; arr.length = 5; // 修改数组的length属性,在数组后新增了两个元素 console.log(arr[3]); // undefined console.log(arr[4]); // undefined
通过索引追加数组元素
var arr = ['red', 'green', 'blue']; arr[3] = 'black'; // arr数组后新增了一个元素'black' //需要注意的是,不可直接给数组名赋值 arr = '数组'; console.log(arr); // 操作台的输出结果不是arr的内容,而是'数组'
冒泡排序
基本思想:比较相邻的两个元素的大小,如果这两个元素顺序错误则交换两个元素的位置,重复这样的操作直到所有元素位置正确即完成排序。
function bubbleSort(arr) { //将元素按从小到大顺序排列
var len = arr.length;
for (var i = 0; i < len - 1; i++) { // 外层循环每执行一次便有一个元素完成排序,内层循环就可以少执行一次
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) { // 相邻元素两两对比
var temp = arr[j+1]; // 元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
函数
声明和调用函数
// 通过函数关键字自定义声明函数(命名函数)
function 函数名(形参1, 形参2, 形参3) {
// 函数体代码
}
// 通过函数表达式方法来声明函数(匿名函数,变量名不是函数名)
var 变量名 = function(){};
// 调用函数
函数名(实参1, 实参2, 实参3);
形参与实参的匹配问题
形参与实参的个数相等,正常输出结果
形参个数少于实参,则实参按顺序传递给形参
形参个数多余实参,则多余的实参被定义为undefined(形参可以被看成是一个不需要声明的变量,默认值为undefined)
function getSum(num1, num2) { console.log(num1 + num2); } getSum(1,2); // 3 getSum(1,2,3); // 3 getSum(1); // NaN (数字型加上一个undefined所得为NaN)
return的注意事项
- return只能返回一个值。如果return后接了多个值,则返回的结果为最后一个值。
- return具有终止函数运行的作用。函数中return之后的代码都不会被执行。
- 函数都有返回值。有return时返回return后的值;不含有return则返回undefined。
arguments
JS中的arguments是当前函数的一个内置对象,其存储了传递的所有实参。
arguments的展示形式是一个伪数组,其具有length属性、能按索引方式储存数据,但不具有push、pop等数组方法。
//arguments的使用
function fn() {
console.log(arguments.length); // 3
console.log(arguments[1]); // 2
}
fn(1, 2, 3);
作用域
作用域的使用能提高程序逻辑的局部性、增强程序可靠性并减少名字冲突。
JS中包含两种作用域类型(es6之前),作用域决定了变量的可访问性。
- 局部作用域与局部变量
函数内部声明的变量,会成为函数的局部变量,其作用域是局部的,只能从函数内部访问,从函数外部是不可访问的。
局部变量在代码块被执行时会被初始化,代码块运行结束后局部变量也会被销毁,更节省内存空间。
// 此处代码不可使用 age 变量
function fn() {
var age = 18;
// 此处代码可以使用 age 变量
}
- 全局作用域与全局变量
函数之外声明的变量,会成为全局变量,其作用域为全局的,网页中的所有脚本和函数都可以访问。
全局变量在声明后直到浏览器关闭时才会被销毁,期间一直占据着内存资源。
var age = 18;
// 此处代码可以使用 age 变量
function fn() {
// 此处代码也可使用 age 变量
}
预解析
JS代码是由浏览器中的JS解析器来执行的,分为两步:预解析和代码执行。
预解析又分为
- 变量预解析
把所有的变量声明提升到当前作用域的最前面,不提升赋值操作
- 函数预解析
把所有函数声明提升到当前作用域的最前面,不调用函数
// 例1
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
//程序相当于执行了以下代码
var num;
function fun() {
var num;
console.log(num); // 结果为undefined
num = 20;
}
num = 10;
fun();
// 例2
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9; // 相当于var a = 9; b = 9; c = 9; b 和 c是直接赋值,没有声明变量,所以可以看作是全局变量。
console.log(a);
console.log(b);
console.log(c);
}
// 等同于以下代码
function f1() {
var a;
a = b = c = 9;
console.log(a); // 9
console.log(b); // 9
console.log(c); // 9
}
f1();
console.log(c); // 9
console.log(b); // 9
console.log(a); // 报错,a为局部变量,未被声明
对象
JS中的对象是一组无序的相关属性和方法的集合
创建对象
利用字面量创建对象 {}
var obj = {}; // 创建了一个空对象 var obj = { name: 'Kobe', age: 17, sex: 'male', practice: function() { console.log('practicing'); } } // 对象中的属性和方法采用键值对的形式 属性名(键): 属性值(值) // 调用属性的两种方法:1、对象名.属性名;2、对象名['属性名'] // 调用方法的方法: 对象名.方法名()
利用 new Object 创建对象
var obj = new Object(); // 创建了一个空对象 obj.name = 'Kobe'; obj.age = 17; obj.sex = 'male'; obj.practice = function() { console.log('practicing'); }
利用构造函数创建对象
// 构造函数的语法 function 构造函数名() { this.属性 = 值; this.方法 = function() {} } new 构造函数名(); // 举例 function Player(name, age, sex) { // 构造函数名首字母要大写 this.name = name; this.age = age; this.sex = sex; this.practice = function() { console.log('practicing'); } } new Player('Kobe', 17, 'male');
new关键字的执行过程
- new 构造函数在内存中创建了一个空的对象
- this 会指向创建的空对象
- 执行构造函数中的代码,给空对象添加属性和方法
- 返回这个对象
遍历对象
for...in 语句用于对数组或者对象的属性进行循环操作
var obj = {
name: 'Kobe',
age: 17,
sex: 'male'
}
for (var k in obj) {
console.log(k); // 得到各属性名
console.log(obj[k]); // 得到对象的各属性值(需要注意写法)
}
内置对象
JS自带的一些对象,提供了一些基本且常用的功能给开发者使用。
Math对象
Math 对象可以用来执行数学任务。 Math 不是构造函数。 Math 的所有属性/方法都可以通过使用 Math 作为对象来调用,而无需创建它:
var x = Math.PI; // 返回 PI
var y = Math.sqrt(16); // 返回 16 的平方更
Math.floor(); // 向下取整
Math.ceil(); // 向上取整
Math.round(); // 四舍五入
Math.random(); // 返回一个随机小数
Math.floor(Math.random() * (max - min + 1)) + min; // 得到一个大于等于 min 且小于等于 max 的数
Date对象
Date对象用于处理日期和时间,通过 new Date() 来创建。
var d = new Date(); // 创建了一个Date对象,无参数时是获取当前的系统时间
var d1 = new Date('2021/11/23'); // 带参数的实例化
// 获取时间戳(总毫秒数)
new Date().getTime(); // 方法1
new Date().valueOf(); // 方法2
+new Date(); // 方法3
// 利用时间戳来创建倒计时效果
function countDown(time) {
var nowTime = +new Date(); // 当前时间的总毫秒数
var inputTime = +new Date(time); //输入时间的总毫秒数
var times = (inputTime - nowTime) / 1000; // 剩余时间的总秒数
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 + '秒';
}
数组对象
// 使用new Array()来创建数组
var arr1 = new Array(); // 创建了一个空数组
var arr2 = new Array(2); // 创建了一个长度为2的空数组
var arr3 = new Array(2, 3); // 等价于var arr3 = [2, 3]; 创建方式与使用字面量创建相同
检测是否为数组
instanceof 运算符
var arr = []; var obj = {}; console.log(arr instanceof Array); // true console.log(obj instanceof Array); // false
Array.isArray() 方法
var arr = []; var obj = {}; console.log(Array.isArray(arr)); // true console.log(Array.isArray(obj)); // false
增删数组元素
- push(参数...),在数组末尾增加一个或多个元素,返回值为新数组的长度
- pop(),删除数组最后的一个元素,并将该元素作为返回值
- unshift(参数...),在数组开头增加一个或多个元素,返回值为新数组的长度
- shift(),删除数组的第一个元素,并将该元素作为返回值
var arr = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4]
arr.unshift(0); // [0, 1, 2, 3, 4]
arr.pop(); // [0, 1, 2, 3]
arr.unshift(); // [1, 2, 3]
数组排序
reverse(),颠倒数组中的元素顺序
sort(),对数组元素进行排序(冒泡排序)
var arr = [13, 4, 77, 1, 7]; arr.sort(); console.log(arr); // [1, 13, 4, 7, 77]这样写时,元素按照转换为的字符串的各个字符的Unicode位点进行排序 arr.sort(function(a, b) { // function用来指定按某种顺序进行排列 return a - b; // 升序排列,b - a 则改为降序排列 }) // [1, 4, 7, 13, 77]
查找数组索引
- indexOf(),查找给定元素在数组中的第一个索引并返回索引值,否则返回-1
- lastIndexOf(),查找给定元素在数组中的最后一个索引并返回索引值,否则返回-1
数组转换成字符串
toString()
join('分隔符')
var arr = [1, 2, 3];
console.log(arr.toString()); // 1,2,3
console.log(arr.join()); // 1,2,3 默认分隔符是 ,
console.log(arr.join('-')); // 1-2-3
字符串对象
根据字符返回位置
- indexOf('要查找的字符', 开始的位置),从指定位置开始(未指定则从头开始)返回指定字符在字符串中的位置,不存在该字符则返回 -1
- lastIndexOf(),与上述类似,只是从后往前查找
根据位置返回字符
- charAt(index),返回指定位置的字符
- charCodeAt(index),返回指定位置字符的ASCII码
- str[index],获取指定位置处的字符
截取拼接字符串
- concat(str1, str2, str3...),用于连接字符串,等同于 +
- substr(start, length),从start位置开始截取长度为length的字符串
- slice(start, end),从start开始截取到end位置的字符串,不包括end
- substring(start, end),与slice基本相同,但不接受负值
替换字符
replace('被替换的字符', '替换成的字符') 只会替换遇到的第一个字符
字符串转换为数组
split('分隔符')
var str = '1, 2, 3';
console.log(str.split(',')); // [1,2,3]
简单数据类型和复杂数据类型
简单数据类型
在存储变量时存储的是值本事,所以又可以叫做值类型或基本数据类型。
string, number, boolean, undefined, null(返回一个空对象)。
当简单数据类型变量作为参数传递给函数的形参时,实际上是把变量在栈空间里的值复制了一份给形参,于是在函数内对形参做任何修改都不会影响到外部的变量。
复杂数据类型
在存储变量时存储的是地址(引用),又可以叫做引用类型。
包括通过 new 关键字创建的对象(自定义对象、内置对象),如Object、Array、Date等。
复杂数据类型变量传参时,实际上是把变量在栈空间里保存的堆地址复制给了形参,形参和实参保存的是同一个堆地址,所以操作的是同一个对象。