一、概述
1.浏览器执行
1)渲染引擎:用来解析html与css,俗称内核,chrome的调试工具
2)js引擎:js解释器,用来读取网页中的js代码,对其处理后运行,逐句解释,然后由计算机去执行
@ECMAScript
js @DOM:可以对页面中的各种元素进行操作
@BOM:可以与浏览器窗口进行互动
2.书写位置
1)行内
<input type="button" value = "点我" onclick="alert('hello world')">
- 可以将单行或少量代码写在html标签的事件属性(以on开头)
- js推荐单引号,另外两个双引号
- 多层嵌套匹配时,可读性差,容易弄混
- 特殊情况下使用
2)内嵌式
<head>
<script>
alert('hello');
</script>
</head>
3)外部式
<script>
src = " "
</script>
有利于html页面代码结构化,把大段js代码独立到html页面之外,也方便文件级别的复用
引用外部文件script标签中间不可以写代码
适合于代码量较大的情况
3.注意点
1)js严格区分大小写
2)多行注释不能嵌套多行注释
3)Fn + F12可启动chrome调试界面
4)要在js代码中输出,需要用到转义字符</script>
5)可以在chrome调试界面的控制台调试代码
6)chrome调试界面中的source界面可以进行断点调试
4.异步加载
为了尽可能减少加载对页面的影响,页面的下载和渲染等待脚本执行完成后才会继续,推荐将不需要提前执行的
5.输入输出语句
alert ()弹出警告框
console.log() 控制台输出信息
prompt() 弹出输入框
6.变量
1)声明变量,js是弱类型语言,不用提前声明变量的数据类型
var age;
声明后计算机会自动为其分配空间,可以通过变量名访问变量
采用驼峰命名
名字不能是关键字或保留字
2)变量赋值:以最后一次赋的值为准,可以保存各种各样的信息
3)变量的初始化
4)声明变量不赋值:undefined
不声明变量输出值:报错
7.数据类型
1)数字型(整形、浮点型)
2)布尔型(true,false)
3)字符型
4)undefined
5)null
6)object
8.进制
八进制 :开头加0
十六进制:0x
9.特殊值
NUMBER.MAX_VALUE
NUMBER.MIN_VALUE
无穷:Infinity - Infinity
NAN(非数字)
isNAN()
10.数据类型相关的
str.length:求字符串长度
str[index]:获取字符
typeof:求数据类型
console.log(typeof null); :结果是object
var a;
console.log(a);//undefined
console.log(a+'_');//undefined_
console.log(a+1);//NAN
var b = null;
console.log(b+'_');//NULL_
console.log(b+1);//1
console.log(b+true);//1
var age = prompt('请输入您的年龄');
console.log(age);
console.log(typeof age);
//输入的是整数或者字符串,即string,直接点取消,object
11.字面量
数字字面量:8、9、10
字符串字面量:‘hello’、"world’
布尔字面量:true、false
数组字面量:[1,2,3]
对象字面量:{name:‘小明’,age:18}
12.数据类型转换
1)转换为字符串类型
//先准备一个变量
var num = 3.14;
//方式1:利用+拼接字符串(最常用的一种方式)
var str =num + '';
console.log(str,typeof str);//输结果:3.14 string
//方式2:利用toString()转换成字符串
var str =num.toString();
console.log(str, typeof str); //输结果:3.14 string
//方式3:利用String()转换成字符串
var str=String(num);
console.log(str,typeof str); //输结果:3.14 string
提示:null和undefined无法使用toString()方式转换,且对于数字型的变量,可以在toString()的小括号中传入参数进行进制转换
num.toString(2);//输出结果为101
2)转换为数字型
//方式1:使用parseInt()将字符串转为整数
console.log(parseInt('78')); //输出结果:78
//方式2:使用parseFloat()将字符串转为浮点数
console.log(parseFloat('3.94')); //输结果:3.94
//方式3:使用Number()将字符串转为数字型
console.log(Number('3.94')); //输:394
//方式4:利用算术运算符(-、*、/)隐式转换
console.log('12'-1); //输出结果:11
在转换纯数字时,会忽略前面的0,如字符串“0123”会被转换为123。如果数字的开头有“+”,会被当成正数,“”会被当成负数。下面我们通过代码进行演示。
console.log (parseInt('03.14')); //输结:3
console.log(parseInt('03.94'))//输结:3
console.log(parseInt('120px'));//输结:120
console.log(parseInt('a120')); //输出:NAN
console.log(parseInt('-120px'));//输结果:-120
//使用parseInt()还可以利用第2个参数设置转换的进制,示例代码如下。
console.log(parseInt('f',16)); //输结:15
1.“计算年龄”案例
var year = prompt('请输人您的出生年份');
var age =2020 -parseInt(year);//由于year是字符串,需要进行转换
alert('您今年已经'+age+'岁了');
2.“简单加法器”案例
var numl = prompt('请输人第1个数:);
var num2 = prompt('请输人第2个数:');
var result = parseFloat(num1)+ parseFloat(num2);
alert('计算结果是:'+result);
3 .转换为布尔型
转换为布尔型使用Boolean(),在转换时,代表空、否定的值会被转换为false,如空字符串、0、NaN、null 和 undefined,其余的值转换为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
console.log(Boolean('小白')); // true
console.log(Boolean(12)); // true
13.运算
1)取模运算的符号取决于被模数的正负
2)===or !===不仅要比较值是否相等,还要比较类型是否相等
console.log(123 && 456);
console.log(0 && 456);
console.log(0 && 1+2 && 456-56789 );
console.log(123||456);
console.log(0||456);
var num = 0;
console.log(123 && num++);
console.log(num);
console.log(0||num++);
console.log(num);
var num = 0;
console.log(123 || num++);
console.log(num);
console.log(0||num++);
console.log(num);
14.数组(object)
1)创建数组
var arr1 = new Array('苹果','橘子','香蕉','桃子');
var arr2 = ['苹果','橘子','香蕉','桃子'];
2)访问数组
arr[index]
3)数组的长度
arr.length
4)保留多少为小数
avg.toFixed(index);
4)修改数组长度或元素
var arr1 = [1,2];
arr1.length = 4;
console.log(arr1);//[1,2,empty*2]
var arr2 = [1,2,3,4];
arr2.length = 2;
console.log(arr2);//[1,2]
console.log(arr1[3]);//undefined
var arr3 = new Array(4);
console.log(arr3[3]);//undefined
var arr1 = ['red','yellow','pink'];
arr1[3] = 'pink';
console.log(arr1);//['red','yellow','pink','pink'];
5)筛选数组
var arr = [2,0,6,1,77,0,52,0,25,7];
var newArr = [];
for(var i = 0;i < arr.length;i++ ){
if(arr[i] >= 10){
newArr[newArr.length] = arr[i];
}
}
6)当对数组类型的变量进行赋值时,会发生引用传递,不是发生值传递
var arr = [1,2];
var arr2 = arr;
arr2[2] = 3;
console.log(arr);//[1,2,3]
7)二维数组转置
var arr = [['a','b','c'],['d','e','f'],['g','h','i'],['j','k','l']];
var res = [];
for(var i = 0;i < arr[0].length;i++){
res[i] = [];
for(var j = 0;j < arr.length;j++){
res[i][j] = arr[j][i];
}
}
15.函数
1)无返回or有返回
function fn2(){
var year = prompt('请输入年份');
if(isLeapYear(year)){
alert('当前年份是闰年');
}
else{
alert('当前年份是平年');
}
}
function isLeapYear(year){
var flag = false;
if(year % 4 == 0 && year % 100 != 0||year % 400 == 0){
flag = true;
}
return falg;
}
fn2();
function fn(){
console.log(arguments);//[1,2,3,4]
console.log(arguments.length);4
console.log(arguments[2]);3
}
fn(1,2,3,4);
function reverse(arr){
var newArr = [];
for(var i = arr.length - 1;i >= 0;i--){
newArr[newArr.length] = arr[i];
}
return newArr;
}
var arr1 = reverse([1,3,5,6]);
console.log(arr1);
2)函数表达式
var sum = function(num1,num2){
return num1 + num2;
};
console.log(sum(3,4));//7
3)回调函数
function cal(num1,num2,fn){
return fn(num1,num2);
}
console.log(cal(45,50,function(a,b){
return a + b;
}));//95
console.log(cal(10,20,function(a,b){
return a * b;
}));//200
4)递归调用
function factorial(n){
if(n == 1){
return 1;
}
return n * factorial(n-1);
}
var n = prompt('求n的阶乘\n n是大于等于1的正整数');
n = parseInt(n);
if(isNaN()||n<1){
console.log('输入的n值不合法');
}else{
console.log(n+'的阶乘为:'+factorial(n));
}
16.变量的作用域
1)全局变量
不在任何函数内声明的变量或在函数内省略var声明的变量,在同一个页面文件中的所有脚本内都可以使用,得在浏览器关闭页面的时候才会摧毁,比较占用内存资源
2)局部变量
在函数体内用var关键字定义的变量,仅在函数体内有用,在函数执行完成之后就会销毁,比较节约内存资源
3)块级变量
ES6提供的let关键字声明的变量,仅在{}中间有效
4)作用域链
var num = 10;
function fn(){
var num = 20;
function fun(){
console.log(num);//20
}
fun();
}
fn();
fn()被调用,fun()函数内访问了num变量,由于fun()函数内部不存在num变量,所以向上级作用域(fn())中查找,在该函数中找到了num变量,输出为20
6)预解析
js解释器会对var变量声明和函数进行提前解析,然后再去执行其他的代码
console.log(num);//undefined
var num = 10;
console.log(num1);//num1 is not defined
执行过程如下
var num ;
console.log(num);
num=10;
console.log(num1);
fn();//fn
function fn(){
console.log('fn');
}
执行过程如下
fun();//fun is not a function
var fn = function(){
console.log('');
};
var a = 18;
f1();
function f1(){
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
执行过程如下
var a;
function f1(){
var b;
b =9;
console.log(a);//undefined
console.log(b);//9
var a;
a = '123';
}
a = 18;
f1();
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;
console.log(a);
console.log(b);
console.log(c);
}
f1();9 9 9
console.log(c);//9
console.log(b);//9
console.log(a);//undefined
17.引用类型
引用类型的特点:变量中保存的仅仅是一个引用的地址,当对变量进行赋值时,并不是将对象复制了一份,而是将两个变量指向同一个对象的引用。
案例1:实际是对同一个对象的操作
var obj1 = {name:'小明',age : 18};
var obj2 = obj1;
console.log(obj1===obj2);//true
obj2.name = '小红';
console.log(obj1.name);//小红
案例2:当两个变量指向了同一个对象,如果给其中一个重新赋值为其他对象,则另一个变量仍引用原来的对象
var obj1 = {name:'小梦',age:18};
var obj2 = obj1;
obj1= {name:'小红',age:17};
console.log(obj1===obj2);//false
console.log(obj1.name);//小红
结:当一个对象只被一个变量引用时,如果这个变量又被重新赋值,该对象没有被任何对象引用,会被js的垃圾回收机制自动释放
案例3:当引用类型的变量作为参数传到函数,其效果和变量之间的传递一样
function change(obj){
obj.name = '小红';
}
var stu = {name:'小明'};
change(stu);
console.log(stu.name);//小红
18.对象
1)造对象
var p2 = {};//造一个空对象
var p1 = {
color: '黑色',
height: 666,
size: 6.5,
call: function (num) {
console.log('打电话给' + num);
},
sendMessage: function (message) {
console.log('发' + message + '短信');
},
playVideo:function(){
console.log('播放视频');
}
};
console.log(p1.color);//黑色
console.log(p1.height);//666
console.log(p1.size);//6.5
p1.call(123);//打电话给123
p1.playVideo();//播放视频
p1.sendMessage('hello');//发hello短信
2)访问对象的属性和方法
console.log(stu.name);
console.log(stu['name']);
stu.hello();
stu['hello']();
注意:如果对象的成员中名含特殊字符,则可以用字符串来表示
var obj = {
'name-age':'小明-18';
}
3)对象具有动态性,可以手动赋值
var stu = {};
stu.name = 'jack';
stu.introduce = function(){
alert(this.name);
}
alert(stu.introduce);
4)利用new Object()创建对象
var obj = new Object();
obj.name = '小明';
obj.age = 18;
obj.gender = '男';
5)利用构造函数创建对象
new Object()就是一种利用构造函数创建对象的方法,object是构造函数的名字,创建的是一个空对象,构造函数的名称推荐首字母大写
function Student(name,age){
this.name = name;
this.age = age;
this.sayHello = function(){
console.log('你好,我叫'+this.name);
}
}
var stu1= new Student('小红',20);
var stu2= new Student('小明',17);
console.log(stu1.name);
console.log(stu2.age);
stu1.sayHello();
抽象:将一类对象的共同特征提取出来,编写成一个构造函数(类)的过程,称为抽象
实例化:new 构造函数的过程
实例:stu1是由Student构造函数创建的
6)静态成员:构造函数本身就有的属性和方法
function Student(name, age) {
this.name = name;
this.age = age;
this.sayHello = function () {
console.log('你好,我叫' + this.name);
}
}
Student.school = '大学';
Student.say = function () {
console.log('人会说话');
}
var stu1 = new Student('小红', 20);
console.log(stu1.school);//undefined
console.log(Student.school);//大学
Student.say();//人会说话
7)遍历对象的属性和方法
var obj = {
name:'小明',age:18,sex:'男'
};
for(var k in obj){
console.log(k);//name,age,sex
console.log(obj[k]);//小明,18,男
}
使用k来获取当前成员的名字,使用obj[k]获取对应的值
8)判断对象成员是否存在
var obj = {name:'小明',age:18};
console.log('age' in obj);//true
console.log('gender' in obj);//false
9)内置对象
1.math对象的使用
1)方法
console.log(Math.PI);//3.1415926
console.log(Math.abs(-8));//8
console.log(Math.abs('-8'));//8
console.log(Math.max(2, 6, 4));//6
console.log(Math.min(5, 9, 2));//2
console.log(Math.pow(2, 4));//16
console.log(Math.sqrt(9));//3
console.log(Math.ceil(3.5));//4
console.log(Math.floor(3.2));//3
console.log(Math.round(2.5));//3
console.log(Math.round(2.3));//2
console.log(Math.round(-2.3));//-2
console.log(Math.round(-2.6));//-3
2)封装自己的数学对象
var myMath = {
PI:3.1415926,
max:function(){
var max = arguments[0];
for(var i = 1;i < arguments.length;i++){
if(arguments[i] > max){
max = arguments[i];
}
}
return max;
}
}
console.log(myMath.PI);//3.1415926
console.log(myMath.max(4,2,5,0));//5
2.日期对象的使用:
1)造Date对象的方法
var date1 = new Date();
console.log(date1);//Sun Mar 20 2022 15:34:20
var date2 = new Date(2022,2,8,10,3,34);
//用传入的方式月的范围(0-11)
console.log(date2);//Tue Mar 08 2022 10:03:34
var date3 = new Date('2022-3-8 3:8:38');
console.log(date3);//Tue Mar 08 2022 03:08:38
2)方法
方法 | 作用 |
---|---|
getFullYear() | 获取表示年份的4位数字 |
getMonth() | 获取月份,范围为0~11(0表示一月,1表示二月,依次类推) |
getDate() | 获取月份中的某一天,范围(1~31) |
getDay() | 获取星期,范围为0-6(0表示星期日,1表示星期一,依次类推) |
getHours() | 获取小时数,范围为0~23 |
getMinutes() | 获取分钟数,范围为0~59 |
getSeconds | 获取秒数,范围为0~59 |
getMilliseconds | 获取毫秒数,范围为0~999 |
getTime() | 获取从 1970-01-01 00:00:00 距离 Date 对象所代表时间的毫秒数 |
set方法同上
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth();
var day = date.getDate();
var week = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
console.log('今天是' + year + '年' + (month + 1) + '月' + day + '日' + week[date.getDay()]);
//今天是2022年3月20日星期天
3)时间戳的使用
//方式一
var date1 = new Date();
console.log(date1);
console.log(date1.valueOf());
console.log(date1.getTime());
//方式二
var date2 = +new Date();
console.log(date2);
//方式三
console.log(Date.now());
var timestamp1 = +new Date();
for (var i = 1, str = ''; i < 900000; i++) {
str += i;
}
var timestamp2 = +new Date();
console.log('代码执行了' + (timestamp2 - timestamp1) + '毫秒');
案例:倒计时
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 + '秒';
}
var milli = countDown('2023-3-20 16:24:40');
console.log(milli);
3.数组对象
1)数组的检测
var arr = [];
var obj ={};
console.log(arr instanceof Array);//true
console.log(obj instanceof Array);//false
console.log(Array.isArray(arr));//true
2)添加或删除数组元素
var arr = ['x', 'y'];
console.log('原数组:' + arr);
var last = arr.pop();
console.log('在末尾移除' + last + '后数组为' + arr);
var len1 = arr.push('Tulip', 'p');
console.log('数组添加成功后长度为' + len1 + ',数组为' + arr);
var first = arr.shift();
console.log('在开头移除' + first + '后数组为' + arr);
var len2 = arr.unshift('b', 'c');
console.log('数组添加成功后长度为' + len2 + '后数组为' + arr);
/*
原数组:x,y
在末尾移除y后数组为x
数组添加成功后长度为3,数组为x,Tulip,p
在开头移除x后数组为Tulip,p
数组添加成功后长度为4后数组为b,c,Tulip,p
*/
3)筛选数组
var arr = [1500, 1200, 2000, 2100, 1800];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] < 2000) {
newArr[newArr.length] = arr[i];
}
}
console.log(newArr);
4)排序和反转数组
var arr = ['red', 'green', 'blue'];
arr.reverse();
console.log(arr);
var arr1 = [4, 2, 6];
arr1.sort();
console.log(arr1);//2.4.6
//定制排序,降序排
arr1.sort(function (a, b) {
return b - a;
});
console.log(arr1);//6,4,2
5)检索方法
var arr = ['red','blue' ,'green', 'blue'];
console.log(arr.indexOf('blue'));
console.log(arr.lastIndexOf('blue'));
6)数组去重
function unique(arr) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i]);
}
}
return newArr;
}
var demo = unique(['blue', 'green', 'blue']);
console.log(demo);
7)数组转换为字符串
var arr = ['a', 'b', 'c'];
console.log(arr.toString());
//使用join
console.log(arr.join());//a,b,c,join()默认使用,分割
console.log(arr.join('-'));
console.log(arr.join(''));
//当数组元素为undefined,null或空数组时,对应的元素会被转换为空字符串
8)方法
方法 | 作用 |
---|---|
splice() | 数组删除,[start,end],返回被删除的新数组 |
slice() | 截取数组,[start,end),返回被截取数组 |
concat() | 连接数组,返回一个新数组 |
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
console.log(arr1.concat(arr2));//1,2,3,4,5,6
console.log(arr1.slice(1, 2));//2
console.log(arr1.splice(1, 2));//2,3
console.log(arr1);//1
4.字符串对象
字符串的不变性:
生成的存储该值的那个空间不变,虽然看上去像是字符串变量内容修改了而已,但其实是已经新开辟了一个内存空间,原来的那个空间如果一直没有被引用就会被回收。
1)基本使用
var str = new String('hello');
console.log(str instanceof String);//true
console.log(typeof str);//object
var str2 = 'hello';
console.log(str2 instanceof String);//false
console.log(typeof str2);//string
2)根据字符返回位置
var str = 'hello world,hello js';
var index = str.indexOf('o');
var num = 0;
while (index != -1) {
console.log(index);
index = str.indexOf('o', index + 1);
num++;
}
console.log('o出现的次数是' + num);
3)根据位置返回字符
var str = 'Apple' ;
console.log(str.charAt(3));//l
console.log(str.charCodeAt(0));//65
console.log(str[0]);//A
4)字符串操作方法
方法 | 作用 |
---|---|
concat(strl,str2,str3…) | 连接多个字符串 |
slice(start,[end]) | 截取从 start 位置到end 位置之间的一个子字符串 |
substring(start[,end]) | 截取从 start 位置到 end 位置之间的一个子字符串,基本和 slice 相同,但是 不接收负值 |
substr(star,length]) | 截取从 start 位置开始到 length 长度的子字符串 |
toLowerCase() | 获取字符串的小写形式 |
toUpperCase() | 获取字符串的大写形式 |
split(separator,[limit]) | 使用separator 分隔符将字符串分隔成数组,limit用于限制数量 |
replace(strl,str2) | 使用 str2 替换字符串中的 strl,返回替换结果,只会替换第一个字符 |
var str = 'helloworld';
console.log(str.concat('!'));//helloworld
console.log(str.slice(1, 3));//el
console.log(str.substring(5));//world
console.log(str.slice(5));//world
console.log(str.substring(1, 3));//el
console.log(str.substr(5));//world
console.log(str.toLowerCase());
console.log(str.toUpperCase());
console.log(str.split('l'));//['he', '', 'owor', 'd']
console.log(str.split('l', 3));//['he', '', 'owor']
console.log(str.replace('world', '!'));//hello!
5)案例一:判断用户名是否合法,不允许出现任何admin的大小写形式
var name = prompt('请输入用户名');
if(name.length<3||name.length > 11){
alert('用户名长度不合格');
}else if(name.toLowerCase().indexOf('admin') !== -1){
alert('用户名不能包含admin');
}else{
alert('用户名符合规范');
}
6)案例2:统计最多出现的次数、字母
var str = 'Apple';
var o ={};
for(var i=0;i<str.length;i++){
var chars = str.charAt(i);//保存每一个字符
if(o[chars]){//把每一个不同的字符作为属性
o[chars]++;
}
else{
o[chars]=1;
}
}
console.log(o);//
var max = 0;
var v ='';
for(var k in o){
if(o[k]>max){
max = o[k];//统计最多出现的次数
v = k;//统计最多出现的字母
}
}
console.log(k + '出现最多次' + ',次数为' + max);
简单数据类型:栈
复杂数据类型:堆