目录
前面已经将HTML和CSS都介绍过了,现在前端三剑客就只剩下JS了,那么今天我们就来聊一聊JS吧!!
一.初始JavaScript
1.什么是JavaScript
JavaScript简称JS,JS是世界上最流行的编程语言之一,JS也是一个脚本语言,通过解释器运行,
主要在浏览器上运行,现在也可以基于node.js在服务器上运行!!!
2.JS和HTML以及CSS的关系
前面学的HTML更像是一个"骨架"(静态页面),CSS更像是赋予了"一身好看的皮囊"(网页的表现),而JS就赋予了其"魂魄"(网页的行为),JS的出现让网页不再单一,不再像是一张报纸,就更像是一个与人交互的APP了!!!
3.JS的组成
●ECMAScript(简称ES):JavaScript核心语法
●DOM API:浏览器提供的一组操作页面元素的API
●BOM API:浏览器提供的一组操作浏览器窗口的API
二.第一份JS代码
既然JS也是运行在浏览器里面的,那么必然是离不开HTML的,因此JS的代码通常也是嵌入到HTML中来进行编写的,一般是放在script标签里面的
<script> alert("hello"); </script>
在script里面可以放很多种编译语言,而现在JS就是其默认的语言!!
上面通过alert就可以弹出一个对话框:
几种JS的书写形式
●内嵌式:把JS代码写到script标签中(也就是上面的写法);
●行内式:把JS写到html元素的内部
<button onclick="alert('hello 2')">行内式</button>
通过一个标签的点击事件来写
●外部式把JS写到一个独立的.js文件中,在html中通过script来引入
<script src="c.js"> //外部式 </script>
这种外部式也是开发中最常使用的!如果一个script标签里面既有外部式,又有内嵌式,那就会只执行外部式的,而不执行内嵌式的代码,因此想要都执行,只能分开来写!!
JS的输入输出
js与用户的交互不只有上面的一种弹框形式,输入我们可以使用prompt弹出一个输入框,这个不常使用就不具体介绍了,而输出不只有上面的alert弹框,患有另一种更常使用的console.log,这会在开发中工具里面的控制台打印一个日志,方便人们随时来查看
<script> console.log("hello log"); </script>
另外这个控制台也是有纠错功能的!!
那么接下来就主要来介绍一下JS的核心语法(这里主要介绍和Java差异的地方)和其相关的API
三.JS的核心语法
1.变量(几种类型)
JS中的变量和Java中的变量还是差异比较大的,JS中一般这样写:var 变量名 = 初始值(不论创建什么类型的变量,类型只有一个就是var,而具体的类型要看后面所赋予的值是什么类型的,那么这个变量就是什么类型的)
var num = 10;//创建了一个名为num的数字类型的变量 var str = 'hello';//创建了一个名为str的字符串类型的变量 var arrs = [];//创建了一个名为arrs的数组(这个数组里面啥都可以放)
类似于这样的就是JS中的变量,另外这个变量你在后续的改变过程中 也是可以任意改变的,既可以改为字符串,也可以改为数字...当改变成什么类型的值,这个变量也就是什么类型的变量了,这样的变量类型,我们一般称为"动态类型",而像Java这样的语言显然是不支持这样的,类似于Java的一般都称为"静态类型"的,C,C++,Java,Go,Rust都是这样的!
下面介绍一下JS中的几种数据类型:
1.1 number数字类型
在JS中数字类型是不区分整数和浮点数的,还有几个特殊的取值:infinity表示无穷大,超出了JS最大取值;-infinity负无穷大,超出了JS最小的取值范围;NaN表示当前结果不是一个数字
假如写这样的语句:console.log('hello' - 10);在Java中这样写是肯定会报错的,但是在JS中会输出这样的语句,就表示当前的值不是一个数字
1.2 boolean类型
true为真,false 为假,如果使用一个布尔类型的变量去参与运算的话,这里的是被当成1和0来使用的,true会被当成1来进行处理,这样的设定方式被称为"隐式类型转换"
let a = true; console.log(a + 1);
这样的结果就是,这种设定方式其实是不科学的,但是我们基本也不会这样使用,因此这个了解一下就好
补充一个小知识:如果一个编译语言,支持隐式类型转换,认为类型越弱 反之如果一个编译语言,不支持隐式类型转换,认为类型越强, 这里的 强类型/弱类型 和 静态类型/动态类型 是不一样的,像Java这样的语言就是强类型,静态类型的的语言,而JS是弱类型,动态类型的语言......
1.3 string字符串类型
JS中也是不区分字符串和字符的,剩下的都基本和Java类似了,另外由于这里的字符串不区分单双引号 因此如果一个字符串中有其他单双引号,外面单引号里面可以使用双引号,外面单引号里面可以使用双引号,如果一定要在双引号内部使用双引号的话 一定是要进行转义的\"类似于这样,单引号也是一样的,而且转义字符也有很多种\t,\n,\f......都是支持的!!!
另外求字符串的长度是通过length来得到,s.length就可以获得长度,而且这里的长度是按字符来进行计算的,一个汉字也是一个字符,另外字符串中也有很多的方法可以使用~
let s = "hello"; console.log(s.length); let s2 = "哈哈"; console.log(s2.length);
1.4 undefined:未定义的数据类型
undefined是唯一的值表示未定义的值,一个未初始的变量,就是一个特殊的值undefined类型也是undefined;
var w; console.log(w);
这样的写法其实是不合法的,在Java就会直接报错,但是JS不会,这是一种独特的数据类型!
1.5 null 空值类型
null表示唯一的值,表示空值,这个类型和上面的类型是不一样的,null是合法的,而undefined是不合法的!!
2.运算符
2.1 比较相等
在JS中 ==和!= 表示只比较两个变量的值,如果一个变量通过隐式类型转换可以得到另一个值那么这两个值就是相等的,=== 和!== 表示既要比较两个变量的值,又要比较两个变量的类型,如果有一个是不相等的那么这就表示不相等了
console.log(10 == '10'); console.log(10 === '10');
而说到比较:一般有三个维度的比较1.比较身份(是否为同一个对象) 2.比较值(对象里面存储的是否相同) 3.比较类型(两个对象是否是同一个类型), ==在这里比较的就是值,而===比较的就是值和类型
2.2 &&和||
在Java中 &&和|| 就只返回一个布尔类型:true或者false,但是在,JS中 &&和|| 会返回其中一个表达式的值
例如:c = a || b 如果a的值为真(非0),就会返回a的值,也就是c此时的值就是a的值,如果a的值为假,就会返回b的值,也就是c此时的值就是b的值
c = a && b 如果a的值为真(非0),就会返回b的值,也就是c此时的值就是b的值,如果a的值为假,就会返回a的值,也就是c此时的值就是a的值
基本就相当于只看前面一个值的结果就可以确定了,这个表达式应该是什么了
而这样就衍生出了JS的一种习惯用法:判断一个变量是否为空值 ,如果是空值就会赋予一个新的值:a = a || 0;
2.3 /
JS的除法和Java的也不太一样,在JS中不区分整数小数,因此1/2结果就是0.5而Java中是0,这是不一样的
2.4 其他
剩下的运算符就和Java的基本类似了,这里就不过多介绍了
3.条件语句
在JS中的if else 和三目表达式以及while,continue,break都是和Java基本一样的,不过在JS中的条件不一定得是一个能得到一个布尔值的表达式,其实只要是个表达式就是可以的,因为在JS中是存在隐式类型转换的,这一点和Java还是不太一样的!!
4.数组
JS的数组和Java的区别还是很大的
4.1 数组的创建
let arr = new Array(); let arr2 = []; let arr3 = [1,2,3];
这几种创建方式都是可以的,另外需要注意的是在JS数组中可以放任何类型(包括数组也可以)的数组,而且不能强制要求里面只能放一种类型
4.2 打印数组
直接通过 console.log(数组名) 就可以直接打印了
let arr = [1,2,3,'hello']; console.log(arr);
4.3 获取数组元素
这个和Java中的获取也是类似的,通过下标来获取,JS中数组的下标也是从0开始计算的
let arr = [1,2,3,'hello']; console.log(arr[0]); console.log(arr[1]); console.log(arr[2]); console.log(arr[3]);
而如果访问一个超出数组下标的值 是不会出现数组越界异常的,而是会得到undefined
let arr = [1,2,3,'hello']; console.log(arr[100]);
接下来的一系列操作反正我是被震惊到了:
let arr = [1,2,3,'hello']; arr[100] = 10; console.log(arr);
这种操作在Java中是会直接报错的,但是JS不会,这样非但不会报错,而且会得到一个更大的数组 前面有的元素还是不变的 ,而下标为100的值就是锁赋予的值,而中间的所有值都是空属性的也就是undefined
let arr = [1,2,3,'hello']; arr[-1] = 10; console.log(arr);
这样的操作也是不会报错的,此时的-1与其说是一个下标,不如说是一个'属性',这样的一一对应更像是一个键值对,放在了这个数组里面,而且这样的操作是不会影响到数组的长度的
let arr = [1,2,3,'hello']; arr['hello'] = 20; console.log(arr);
这个也是可以的 ,就像上面说的键值对一样,这个更能体现出键值对的效果,而且通过arr[hello]也是能够得到20的,因此JS中的数组,与其说是一个数组其更像是一个map,更准确的说这是一个对象,而且是可以在运行时,给对象新增属性的,arr.hello = 20;就像是给这个数组了一个属性,属性名字为hello,属性的值为20,而上面这些操作之所以会感到差异 主要还是"静态类型"和"动态类型"两个流派的碰撞,从而对我产生的冲击感!!
4.4 获取数组长度
通过数组名.length就可以,而且而且而且这个length是可以改的,假设原本为4 改成3就会删除掉最后一个元素,改成5就会多一个空属性(undefined)
let arr = [1,2,3,'hello']; console.log(arr); console.log(arr.length); arr.length = 3; console.log(arr); console.log(arr.length);
4.5 插入元素
最常见的就是push方法,类似于Java中ArrayList中的add方法
let arr = [1,2,3,'hello']; console.log(arr); arr.push(54); console.log(arr);
4.6 删除元素
splice方法,准确来说是针对数组中的某个片段,进行替换(既可以用来插入元素,也可以用来删除元素)
let arr = [1,2,3,'hello']; console.log(arr); arr.splice(1,2,'hi'); console.log(arr);
splice中第一个参数是起始位置,第二个参数表示多少个(从起始位置开始),后面的则为要替换的值(不写就表示删除)
另外JS的数组中也是有很多的方法的,这里就不具体介绍了
5.函数
在JS中是函数(function)而在Java中叫做方法(method) 这两个其实是同一个东西,通常情况下不去考量这两个概念的区别,但是如果非要考量,可以这样理解:函数是和对象独立开来的代码片段,而方法则是依托对象的代码片段,方法可以理解为成员函数~
5.1 函数的基本形式函数主要包括定义和调用:
●定义:
function 函数名(形参列表){
这里不必写返回值类型,而且形参列表里面也不用写具体的类型其实都是let类型的
函数实体
return 返回值
}
●调用: 函数名(实参列表)
例如:
function add(x,y){ return x + y; } let num = add(10,20); console.log(num); let num1 = add('hello',27); console.log(num1);//各种参数都是可以的只要能进行这种运算就可以
一般需要调用时传入的实参,个数和类型都是应该匹配的,但是实际上,JS并没有做出这样的限制,因此多个参数也是可以的
function add(a,b,c,d,e,f,g){ return a + b + c + d + e + f + g; } console.log(add(10,20)); console.log(add(10,20,30)); console.log(add(10,20,30,40));
这样写虽然没有报错但是其得到的结果不是一个整数是NaN,因为没有传入的参数此时是undefined, 因此还需要加以修改,这就用到了,前面讲过的判断一个变量是否为空值的语句
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; } console.log(add(10,20)); console.log(add(10,20,30)); console.log(add(10,20,30,40));
这样就可以得到正确的结果了
而如果实参比形参多了,多出来的实参其实就没有了,函数内部就拿不到了,这样的设定其实是JS的专属属性(所以我们自己写的时候尽量还是保证形参和实参的个数能够匹配,保证不会出现这样的问题)
5.2 函数表达式
在JS中,函数作为"一等公民"(函数就像一个普通的变量一样,可以被赋值给其他的变量,也可以作为另一个函数的参数,还可以作为另一个函数的返回值(这一般就被称为一等公民)),而这里的函数表达式其实就是把一个函数赋值给一个变量
例如:
function a(){ console.log("a"); } let f = a;
此时a虽然作为一个函数,但是后面没有带括号的话,这就是一个赋值操作,而不是函数调用,就是将a个函数赋值给了f这个变量,然后通过f()也是可以调用这个函数的;另外上面的操作也是可以合并的:
let f = function (){ console.log("a"); }
这就类似于Java中的lambda表达式,很多编译语言里面都是有这种操作的!!
5.3 作用域
在ES6(ES6是JS的版本就相当于Java的1.8版本地位也是差不多的,最经典的版本)之前其实是只有全局作用域和函数作用域的概念而没有块级作用域(var搞的鬼)的, 而在ES6之后JS引入了let,然后就有了块级作用域这个概念,但是块级作用域是{}内部无法访问到{}外部的,而在JS中这是可以做到的
let num = 0; { console.log(num);//这是可以做到的 }
另外定义在函数外部的变量,即使不传参也是可以访问到的
let num = 0; function hello(){ console.log(num); } hello();
在JS中的作用域是支持"逐级向上"查找的, 当在函数中尝试找到这个变量,但是函数中没有,就会往上寻找,找到外面,直到找到全局变量作用域,还是没找到的话就会报错了,因此这个是支持套娃的
let num = 10; function hello(){ function hello1(){ console.log(num); } hello1(); } hello();
这其实就是一个作用域链,而如果在作用域链不同节点上存在多个同名的变量,这是会从内向外找,找到第一个就结束(而如果想找到全局变量的这个变量可以使用window.变量来找,不过这样的操作还是最好用传参来找比较靠谱)
6.对象
对象就是一些属性和方法的集合,在Java中一般对象是依托于类的,有了类通过类的实例化才可以产生对象,而在JS中对象是不依托于类的 ,在JS所有的类都是Object类型;在JS中创建对象就直接通过{}就可以了,举个例子:
let student = { name: '张三', age: 20, weight: 130, height: 175, eat: function (){ console.log("吃饭"); }, sleep: function(){ console.log("睡觉"); }, }; console.log(student.name); console.log(student.age); console.log(student.weight); console.log(student.height); console.log(student.eat); console.log(student.sleep);
然后通过类名.属性 就可以进行访问了,而且在JS中一个对象有哪些成员,也是可以动态改变的另外JS中也是有一些现成的对象的,像数组,本质上就可以视为是一个对象,而JS虽然有对象,但是JS不算是一个面向对象的变成语言,因为其并没有封装继承(其实在JS中有一个"原型"其实可以实现,但是也是和Java中有差别的) 多态的面向对象的特征~~
四.DOM API
其实浏览器给JS提供的API是非常丰富的,其中包括DOM API ,BOM AP还有websocket API,canvas API而这些统称为Web API(这里主要介绍DOM API)
1.获取元素
获取元素(使用DOM的基础):想操作页面上的元素,就需要先拿到对应的JS对象,DOM其实提供了一组能获得页面元素的API,这里介绍两个最重要的: querySelector,querySelectorAll,这两个其实是document(页面中的全局变量,一个页面加载好了,就会自动生成一个全局变量,就叫document,这里面有一些属性和方法,就可以操作页面的内容)对象的属性
<div class="one"> hello </div> <script> let div = document.querySelector('.one'); console.log(div); </script>
querySelector的参数其实就是一个CSS的选择器(各种选择器都可以),通过这样就可以选中这个元素了
而如果选中的元素是有多个的,再使用querySelector就会选中第一个元素(匹配结果的第一个),
而想要全部选择就得使用querySelectorAll(会返回一个类似于数组的东西,准确的说返回的不是一个真正的原生数组,而是一个对象,不过这个对象有length,也能通过下标来访问内部元素,这样的对象使用起来其实和数组是一模一样的,这样的一般称为"伪数组")
<ul> <li>张三</li> <li>李四</li> <li>王五</li> </ul> <script> let l = document.querySelectorAll('li'); console.log(l); </script>
2.事件
JS中的很多代码都是通过事件来触发的,事件其实就是浏览器对于用户的操作行为进行的一个统称(准确的说事件也不一定全是用户操作产生的,但大部分都是的),因此JS做的主要工作就是在不同的事件中进行不同的处理.事件的三要素:1.事件源:哪个HTML元素产生的事件,2.事件类型:鼠标移动,鼠标点击,键盘事件(具体这个事件做了什么) 3.事件的处理程序:当事件产生之后,执行什么样的JS代码
例如点击事件:
<button>这是一个按钮</button> <script> let b = document.querySelector('button'); b.onclick = function(){ alert('hello'); } </script>
这个函数可以称为回调函数,会在合适的时机进行调用
3.操作元素
3.1 操作元素内容
通过对象里面的一个属性innerHTML来实现(元素里面包含的html代码是什么样的)
<div id="screen">hello world</div> <button id="btn">获取内容</button> <script> let btn = document.querySelector('#btn'); btn.onclick = function() { let screen = document.querySelector('#screen'); console.log(screen.innerHTML); // 里面是啥就可以获取到什么内容 } </script>
点击多次不会把同样的结果显示多次,而是显示了一个数字,这也是可以设置的,设置之后就可以显示多条了! 而想要修改元素里面的内容的话变量名.innerHTML = 要修改的内容,就可以直接进行修改了
3.2 操作元素属性
通过dom对象.属性名,就可以进行操作了
例如实现一个点击照片更换为另一个照片的案例:
<img src="dog.jpg"> <script> let img = document.querySelector('img'); img.onclick = function(){ let s = img.src; if(s.indexOf('dog.jpg') >= 0){//是否包含这个地址 img.src = 'b.jpg'; }else if(s.indexOf('b.jpg') >= 0){ img.src = 'dog.jpg'; } } </script>
另外需要注意的是:input是一个单标签,没有innerHTML属性,因此想要获得input里面的东西就要用其的value属性才可以!!
3.3 操作元素样式
style对应行内样式(直接把样式写到style里面) className/classList对应的内部样式/外部样式 应用了一个/一组CSS类名
例如实现一下夜间模式的效果:
<style> div{ height: 500px; width: 500px; } .light{ background-color: #fff; color: black; } .dark{ background-color: black; color: #fff; } </style> <div class="light">一段文字</div> <button id="btn">关灯</button> <script> // 夜间模式: let div = document.querySelector('.light'); let btn = document.querySelector('#btn'); btn.onclick = function(){ if(div.className == 'light'){//通过class来切换样式 div.className = 'dark'; btn.innerHTML = '开灯'; }else if(div.className == 'dark'){ div.className = 'light'; btn.innerHTML = '关灯'; } } </script>
另外在HTML中类名的属性是class,但是在JS中class(ES6中引入了类的概念)是一个关键字,因此就会把这个属性名改成className/classList
4.操作节点
其实是操作元素的属性,(元素本身没有发生改变) 而针对节点进行操作,主要是新增节点/删除节点
4.1 新增元素
新增节点1.创建新节点,2.把节点挂在dom树上
<div class="container"> </div> <script> //1.创建新节点 let newDiv = document.createElement('div');//通过这个createElement就可以创建一个新的div newDiv.id = 'newDiv'; newDiv.className = 'one'; newDiv.innerHTML = 'hello'; //2.把节点挂在dom树上 可以使用appendChild把节点插入到某个节点的子元素中 let container = document.querySelector('.container'); container.appendChild(newDiv);//这样就可以插入元素了
这样就可以将新元素的内容打印出来了
4.2 删除元素
删除节点:先拿到父节点然后在拿到待删除的子节点就可以进行删除了
<div class="container"> </div> <button id="btn"> 删除节点 </button> <script> let newDiv = document.createElement('div'); newDiv.id = 'newDiv'; newDiv.className = 'one'; newDiv.innerHTML = 'hello'; let container = document.querySelector('.container'); container.appendChild(newDiv);//这样就可以插入元素了 //通过removeChild就可以进行删除了 let btn = document.querySelector('#btn'); btn.onclick = function(){ container.removeChild(newDiv); }
点击删除按钮之后就删除了里面的节点,就可以实现删除节点的效果了~~
介绍到这儿,关于前端部分就基本介绍完了,我这里介绍的前端部分都是十分底层的语法知识,只是能实现一些基本的页面,而这对于一个后端的程序员来说其实已经足够了!!!