本博客的js只讨论浏览器上的,可以开发网页的js,不考虑node.js
主要分为三个部分:
ECMAScript 也就是JavaScript语法
DOM 页面文档对象模型 对页面中的元素进行操作
BOM 浏览器对象模型 对浏览器窗口进行操作
后两者都是浏览器给js提供的api
js的hello world程序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
alert('hello world')
//这里可以用单引号 也可以用双引号表示
</script>
</body>
</html>
但是弹框是在真实项目中不会建议使用的,因为比较影响用户体验
js也有多种方式来和html来进行结合
内嵌式:吧js代码写到script标签中
内联式:把js代码放到标签的特殊属性中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<button onclick="alert('hello world')">这是个按钮</button>
<script>
</script>
</body>
</html>
外部式:把js代码写到单独的.js文件中,在html中引入这个js文件,使用script标签引入
这样可以把公共的js代码提取出来,方便多个页面来进行重复使用
但是当前学习还是以内嵌式为主,因为更为方便理解
注意:js里的注释支持使用 // 和 /* */
html注释:<!-- -->
CSS注释: /* */
js注释: // /* */
输出操作
console.log
类似于java的sout 使用的时候只需使用log就可以打出上述代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
console.log(hello);
</script>
</body>
</html>
这个hello在页面看不见 但是在控制台可以找到,因为这里的内容不是给普通用户看的,而是给程序员调试用的。
定义变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
var name = '张三';
let age = '19';
//这里的var let 都是关键字 表示后面的名字是一个变量 不表示一个类型
//只是var是老式写法 let是新式写法 使用后者let变量的各种特性就和java/c中的特性基本一致
//具体的类型是根据后面=的值的类型来区分的
//例如name就是string类型 age就是number类型
console.log(name);
console.log(age);
</script>
</body>
</html>
注意:js里面不区分整数和浮点数,统一都是number类型
而且js中的变量类型是动态的(动态是运行时 静态是编译期)也就是说运行过程中变量类型 可以发生改变
int num = 10;
num = "hello";
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
let a = 19;
console.log(typeof(a));
a = "hello";
console.log(typeof(a));
</script>
</body>
</html>
注意:类型能不能改 和是否使用类型自动推导语法无关,例如Java和C++都可以使用自动类型推导,但是仍然是“静态类型”
动态类型提供了更灵活的编程方式,写一段代码就可以同时支持多种类型的数据,相当于自带泛型,但是类型过于灵活,如果是大项目就显得不太合适
基本数据类型
js中的数字不区分整数还是浮点数,统一都是number
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
let a = 1;
console.log(a/2);
console.log(typeof(a/2));
</script>
</body>
</html>
特殊的数字值:
infinity 无穷大 大于任何数字 表示数字已经超过js表示的范围
-infinty 负无穷大 小于任何数字 表示数字已经超过js表示的范围
NaN 表示当前结果不是一个合法的数字
无穷大一般是浮点数除以零算出来的结果
字符串
js中字符串可以用单引号也可以用双引号
如果要输出有双引号或者单引号的字符串可以使用转义字符
或者在最外围使用单引号,在里面对引用的内容使用双引号
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
let name1 = "My name is \"LI\"";
let name2 = 'My name is "LI"';
console.log(name1);
console.log(name2);
</script>
</body>
</html>
字符串的长度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
let name1 = "张三";
console.log(name.length);
</script>
</body>
</html>
字符串的长度意思是里面有几个字符,而不是几个字节,一个字符里面可以包含多个字节
字符串拼接
使用+来进行拼接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
let a = "hello";
let b = "world";
console.log(a+b);
</script>
</body>
</html>
也可以数字和字符串混着相加,会把数字隐式转换成字符串
字符串比较
直接使用 == 来进行比较
布尔类型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js</title>
</head>
<body>
<script>
let a = true;
console.log(typeof(a));
console.log(a+10);
</script>
</body>
</html>
但是java中进行boolean和整数类型混合运算就无法编译,我们称其为强类型语言(有部分支持但不是全部)
向js这种比较支持隐式类型转换的语言我们就叫弱类型语言
类型强就是不同的数据区分度更高界限更明确,类型弱就是不同的数据区分度低,界限更模糊
undefined和null(特殊类型)
undefined只有一个值就是undefined null只有一个值就是null
前者表示你这个类型没有被定义,此时就是undefined(例如敲错了length这个单词)
后者表示访问的变量是存在的,但是这个值是空的
三等号
== 适用于隐式类现转换
===不会进行隐式类型转换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
</head>
<body>
<script>
let a = 10;
let b = '10';
console.log(a == b);
console.log(a === b);
</script>
</body>
</html>
&&和||
let a =10;
b = a || 0;
b = a && 0;
//第一行为左侧表达式为真(或者隐式转换为true)此时就把a值赋给b 反之赋值给b
//第二行为左侧表达式为假(或者隐式转换为faluse)此时就把a的值赋值给b 反之赋值给a
创建数组
<script>
let arr = new Array();
let arr2 = [];
</script>
两种方式都可以,创建的时候不需要声明长度因为js的数组长度是可以动态变化的,js的数组更接近于java的arraylist
创建数组的时候,可以同时指定初始值
let arr2 =[1,2,3,4];
js的数组允许里面存在不同类型的元素,而java则要求务必是相同类型
let arr3 = [1,'hello',true,[]];
<script>
let arr = ['老王','老李','老张'];
console.log(arr[1]);
console.log(arr.length);
console.log(arr);
</script>
在java中下标越界访问的时候,会抛出异常,但是在js中会获取一个undefined的结果,
<script>
let arr = ['老王','老李','老张'];
console.log(arr[4]);
</script>
<script>
let arr = ['老王','老李','老张'];
arr[4] = '老表';
console.log(arr[4]);
</script>
但是我们可以直接通过越界来赋值的方式去增添我们需要的元素,并且可以直接打印出来
<script>
let arr = ['老王','老李','老张'];
arr[6] = '老表';
console.log(arr);
</script>
当我们越过几个数组位置去赋值的时候,中间未被赋值的元素会变成empty
<script>
let arr = ['老王','老李','老张'];
arr['hello'] = '老师';
console.log(arr['hello']);
console.log(arr.hello);
</script>
js的数组不仅仅式数组,还有map这样的效果,上述的arr.hello就是把这个数组当成了一个对象,其中的hello就是键值对,js的对象是可以值运行的时候随意新增属性的。js中要访问成员,既可以使用.也可以使用[](arr.hello = arr['hello'])
对于js数组来说,只有[]中为非负整数的时候,才会把操作看成操作下标,如果式其他类型的值,都会认为式数组的自定义属性。
数组新增和删除元素
可以使用push方法进行尾插(类似于arraylist的add方法)
使用pop来删除末尾的元素
<script>
let arr = [];
for (let i =0;i<10;i++){
arr.push(i);
}
console.log(arr);
let ret = arr.pop();
console.log(ret);
let ret1 = arr.pop();
console.log(ret1);
console.log(arr);
</script>
数组中间位置的插入和删除
splice 既可以中间位置插入和删除,还可以进行元素的替换
<script>
let arr =[1,2,3,4,5];
//要在2和3之间插入一个元素‘hello’
arr.splice(2,0,'hello')
//第一个2为起始下标 第二个0为要取数组的长度 0就是不对数组原来的内容进行调整,也就是不删除 任何元素
//如果第二个数字 0 为 1 的话就是把3替换成hello,为2就是把3和4替换成hello
//第三个参数为要替换到数组指定范围的新的值
console.log(arr);
</script>
<script>
let arr =[1,2,3,4,5];
arr.splice(2,1,'hello','world')
console.log(arr);
</script>
<script>
let arr =[1,2,3,4,5];
arr.splice(2,1)
console.log(arr);
</script>
因为后面没有指定新的元素,这样就是值下标为2的开始处删除长度为1的元素,也就是删除3这个元素
函数
<script>
function add(x,y){
return x+y;
}
console.log(add('hello','world'));
console.log(add(10,20));
console.log(add(true,false));
</script>
js这样的动态类型的语言自带了泛型机制,也不需要函数重载这样的语法(js的一个函数就能支持不同个数的参数,不要求形参和实参个数匹配)
当实参比形参多的时候,多出来的实参就不能通过形参获取到了
当实参比形参少的时候,多出来的形参就是undefined了
<script>
function add(a,b,c,d,e,f,g){
return a+b+c+d+e+f+g;
}
let ret = 0;
ret = add(10,20);
console.log(ret);
ret = add(10,20,30);
console.log(ret);
ret = add(10,20,30,40);
console.log(ret);
ret = add(10,20,30,40,50,60,70,80);
console.log(ret);
</script>
解决方案:
<script>
function add(a,b,c,d,e,f,g){
if (a == undefined){
a = 0;
}
if (b == undefined){
b = 0;
}
if (c == undefined){
c = 0;
}
if (d == undefined){
d = 0;
}
if (e == undefined){
e = 0;
}
if (f == undefined){
f = 0;
}
if (g == undefined){
g = 0;
}
return a+b+c+d+e+f+g;
}
</script>
//或者
<script>
function add(a,b,c,d,e,f,g){
a = a || 0;
b = b || 0;
c = c || 0;
d = d || 0;
e = e || 0;
f = f || 0;
g = g || 0;
return a+b+c+d+e+f+g;
}
</script>
//或者
<script>
function add(){
let ret = 0 ;
//arguments这个数组就包含了调用add方法的所有实参的值
for(let i = 0; i <arguments.length; i++){
ret+=arguments
}
return ret;
}
</script>
js中,函数是可以像普通变量一样进行赋值的,还可以作为另外一个函数的参数家或者是另外一个函数的返回值
<script>
//先定义来一个变量,给变量进行赋值,赋的值式一个function,add的类型就是函数
//同时也就相当于定义来一个匿名函数(也就是lambda表达式)
let add = function(){
let ret = 0;
for(let i = 0;i<arguments.length;i++){
ret += arguments[1];
}
return ret;
}
</script>
js值代码中尝试访问一个变量的时候,会先查找到当前代码块,如果当前代码块中没有,就会继续往上级代码块中查找,一直找到全局的作用域。
js把上述变量作用域查找规则称为 作用域链
<script>
let num = 0;
function test(){
console.log(num);
}
test();
</script>
对象
<script>
let student = {
name:'cxk',
age: 20,
gender: 'none',
sing: function(){
console.log("ji");
},
dance: function(){
console.log("tsk");
}
};
console.log(student.name);
student.sing();
student.dance();
</script>
html中创建一个对象是不需要创建一个类的
构造函数
<script>
function Student(name,age, gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sing = function(singMsg){
console.log(singMsg);
};
this.dance = function(){
console.log(danceMsg);
};
}
let student1 = new Student('cxk',20,'male','jntm','tsk');
let student2 = new Student('cxkki',21,'female','jnbm','glgl');
</script>
使用构造函数可以起到对象图纸的效果,想要什么对象就直接创建一个对象出来
js虽然有类的概念,但是不能提供封装和继承以及多态的思想,因为js并不是一个面向对象的编程语言