封面画师:Nengoro(ネんごろぅ) 封面ID:80965079
1. 什么是JavaScript
JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的高级编程语言。虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。
那么Java与JavaScript有关系吗?就像老婆与老婆饼的关系,所以…
JavaScript是一门世界上最流行的脚本语言,所以你还不学吗?一个合格的后端程序人员,必须要会JavaScript,所以你还不学吗?
参考链接:JavaScript的起源故事
ECMAScript,可以理解为JavaScript的一种标准。最新版本已经到ES6 版本,但是大部分浏览器还只停留在支持ES5 的代码上,这就导致了开发环境与线上环境版本不一致。
2. 快速入门
2.1 引入JavaScript
内部标签
1 2 3 < script >
...
</ script >
外部引入
myjs.js:
test.html:
1 < script src = "myjs.js" ></ script >
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <! doctype html >
< html >
< head >
< meta charset = "utf-8" >
< title ></ title >
<!-- 外部引入 -->
<!-- 注意:script标签必须成对出现 -->
< script src = "js/myjs.js" ></ script >
<!-- 可以不用显式定义type,默认就是javascript -->
< script type = "text/javascript" ></ script >
</ head >
< body >
</ body >
</ html >
myjs.js:
2.2 基本语法入门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!-- JavaScript严格区分大小写 -->
< script >
/* JavaScript中,语句后可以不写分号,但是打包时没有分号会合成一行
因此依旧建议写上分号!
*/
// 1. 定义变量:变量类型 变量名 = 变量值;
var score = 1 ;
//alert(score);
// 2. 条件控制
if ( 2 > 1 ){
console . log ( score ); //打印到控制台
alert ( "true" );
}
</ script >
浏览器F12调试常用选项:
2.3 数据类型
数值、文本、图形、音频、视频…
变量
使用var进行定义变量。
变量命名与Java语法类似。比如:
1 2 3 4 var _sa = 1 ;
var $a = "2" ;
var 我爱 = "中国" ;
...
number
JS中不区分小数和整数,统一使用number定义。
1 2 3 4 5 6 123 //整数
123.1 //浮点数
1.123e3 //科学计数法
- 99 //负数
NaN // not a number
Infinity //表示无限大
字符串
比如:“abc” ‘abc’ …
布尔值
true 、 false
逻辑运算
比较运算符
1 2 3 = //赋值
== //等于(类型不一样,值一样,也会判断为true)
=== //绝对等于(类型一样,值一样,结果才是true)
建议 要求 在JS中进行比较时不 使用 ==
注意:
NaN === NaN,结果为false。NaN与所有数都不相等,包括自己。😱
只能通过isNaN(NaN)来判断这个数是否是NaN。😎
浮点数的问题:
1 console . log (( 1 / 3 ) === ( 1 - 2 / 3 )); //结果打印为false
尽量避免使用浮点数进行运算,存在精度问题 !😵
我们可以用绝对值来进行浮点数的比较:👍
1 console . log ( Math . abs ( 1 / 3 - ( 1 - 2 / 3 )) < 0.000000001 );
null 与undefined
数组
Java的数组必须是一系列相同类型的对象,但是在JS中不需要这样:
1 2 3 // 为了程序的可读性,尽量使用[]表示数组
var arr = [ 1 , 2 , 3 , 4 , 5 , 6 , 'hello' , null , true ];
new Array ( 1 , 12 , 3 , 4 , 5 , 'hello' );
使用数组时,如果数组下标越界,将会显示undefined。
对象
对象使用大括号{ },数组使用中括号[ ]。
JS中的对象每个属性之间使用,隔开,最后一个不需要添加。
1 2 3 4 5 var person = {
name : "mofan" ,
age : 18 ,
tags : [ 'Java' , 'Web' , 'JS' , '...' ]
}
取对象的值:
1 2 3 4 person . name
> "mofan"
person . age
> 18
2.4 严格检查模式
在JS中,使用 i = 1定义一个名为 i 的变量时,这个 i 是一个全局变量,如果导入的多个JS文件中都使用了 i ,那么这时候会产生无法预料的后果💥,因此我们需要一种方法来检测这种定义方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 <!--
使用"use strict";的前提编译器支持ES6语法
"use strict";严格检查模式,预防JS的随意性导致产生一些问题
"use strict"; 必须卸载JS的第一行。
局部变量建议使用 let 定义。
-->
< script type = "text/javascript" >
"use strict" ;
// 全局变量
i = 1 ;
// ES6 中我们一般使用let定义局部变量
let a = 2 ;
</ script >
要想在编译器内直接看到错误提示,我们需要对编译器设置支持JS的ES6规范。
使用"use strict";时,这条语句必须 放在JS的第一行 !
3. 数据类型详解
3.1 字符串
正常的字符串我们使用单引号' '或者双引号" "进行包裹。
注意转义字符 \ 的使用;
1 2 3 4 5 \ '
\ n
\ t
\ u4e2d //Unicode字符编码 \u####
\ x41 //Ascll编码
\'表示一个点。
多行字符串编写。使用反引号将字符串包裹起来。
1 2 3 4 var msg = `你好,
JavaScript!` ;
// 反引号位于Tab键上方
// 使用这种方式,可以将换行和制表符显示出来,而不需要使用\n或\t
模板字符串
1 2 3 4 5 let name = "mofan" ;
let age = 18 ;
let message = `你好, ${ name } ` ; //这里的字符串是使用反引号包裹起来的
console . log ( message );
// 打印结果为:你好,mofan
字符串的属性与方法
1 2 3 4 5 6 7 8 9 var stu = "stuDEnt" ;
console . log ( stu . length ); // 打印结果为7
console . log ( stu [ 0 ]); // 打印结果为s
console . log ( stu ); // 打印结果为student
console . log ( stu . toUpperCase ()); // 字符串转换为大写
console . log ( stu . toLowerCase ()); // 字符串转换为小写
console . log ( stu . indexOf ( "D" )); // 获取字符串中"D"的下标
console . log ( stu . substring ( 1 )); // 截取字符串下标是1及其以后的所有字符
console . log ( stu . substring ( 1 , 3 )); // 截取字符串下标是1到3的所有字符,不包含下标3。范围是[1,3)
浏览器打印结果:
字符串不可变(Java也有这样的特性)
我们在浏览器中进行以下测试(在编译器中测试会直接报错):
3.2 数组
Array可以包含任意的数据类型。
1 2 3 4 var num = [ 1 , 2 , 3 ]; //通过下标取值和赋值
console . log ( num );
num [ 0 ] //下标取值
num [ 0 ] = 0 ; //下标赋值
数组长度测试
1 2 3 4 5 6 7 8 9 10 11 var arr = [ 1 , 2 , 3 , 4 , 5 , 6 ];
console . log ( arr );
console . log ( arr . length );
arr [ 0 ] = 0 ;
console . log ( arr );
arr . length = 10 ;
console . log ( arr . length );
console . log ( arr );
console . log ( arr [ 7 ]);
arr . length = 2 ;
console . log ( arr );
打印结果:
注意:如果先定义了一个数组,再给这个数组的length属性进行赋值,数组的长度就会发生变化。数值超过原始长度,多出的数据以undefined填充;数值小于原始长度,数据就会丢失。
indexOf() 通过元素获取下标索引
1 2 3 4 5 var arr = [ 1 , 2 , 3 , 4 , 5 , 6 ];
console . log ( arr . indexOf ( 3 )); //获取元素3的下标索引
var arra = [ 1 , 2 , 3 , 4 , 5 , 6 , "1" , "2" ];
console . log ( arra . indexOf ( 1 )); //打印结果为0
console . log ( arra . indexOf ( "1" )); //打印结果为6
字符串中的 “1” 和数字 1 是不同的。
slice() 截取Array的一部分,返回一个新的数组,类似于String中的substring()。
1 2 3 4 5 var arra = [ 1 , 2 , 3 , 4 , 5 , 6 , "1" , "2" ];
console . log ( arra . slice ( 3 ));
// 结果为:[4, 5, 6, "1", "2"]
console . log ( arra . slice ( 1 , 5 ));
// 结果为: [2, 3, 4, 5]
push()、pop()
push : 压入元素到尾部; pop : 弹出尾部的一个元素
1 2 3 4 5 6 7 var arra = [ 1 , 2 , 3 , 4 , 5 , 6 , "1" , "2" ];
arra . push ( "3" , "4" );
console . log ( arra );
// 结果为:[1, 2, 3, 4, 5, 6, "1", "2", "3", "4"]
arra . pop ();
console . log ( arra );
// 结果为:[1, 2, 3, 4, 5, 6, "1", "2", "3"]
unshift()、 shift()
unshift : 压入元素到头部; shift : 弹出头部的一个元素
1 2 3 4 5 6 7 var arra = [ 1 , 2 , 3 , 4 , 5 , 6 , "1" , "2" ];
arra . unshift ( 0 , - 1 );
console . log ( arra );
// 结果为:[0, -1, 1, 2, 3, 4, 5, 6, "1", "2"]
arra . shift ();
console . log ( arra );
// 结果为:[-1, 1, 2, 3, 4, 5, 6, "1", "2"]
排序 sort() 默认从小到大排序
1 2 3 4 var arra = [ 3 , 2 , 1 , 5 , 9 ];
arra . sort ();
console . log ( arra );
// 结果为: [1, 2, 3, 5, 9]
元素反转 reverse()
1 2 3 4 var arra = [ 1 , 2 , 3 , 5 , 9 ];
arra . reverse ();
console . log ( arra );
// 结果为:[9, 5, 3, 2, 1]
元素拼接 concat()
1 2 3 4 5 var arra = [ 9 , 5 , 3 , 2 , 1 ];
arra . concat ( "11" , "22" , "33" );
// 拼接后为:[9, 5, 3, 2, 1, "11", "22", "33"],但是元数组并没有改变
console . log ( arra );
// 结果为:[9, 5, 3, 2, 1]
注意:concat()并没有修改原数组 ,只是返回了一个新的数组!😮
连接符 join()
使用特定的连接符将数组内每个元素连接起来形成一个字符串。当然,原数组也没有发生改变。☺️
1 2 3 4 5 var arra = [ "A" , "B" , "C" ];
arra . join ( "-" );
// 拼接后形成: "A-B-C"
console . log ( arra );
// 打印结果为: ["A", "B", "C"]
多维数组
1 2 3 var arra = [[ 1 , 2 ],[ "3" , "4" ],[ "a" , "b" ]];
console . log ( arra [ 1 ][ 1 ]);
// 打印结果为:4
3.3 对象
若干个键值对。对象格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var person = {
属性名 : 属性值 ,
属性名 : 属性值 ,
...
属性名 : 属性值
}
// 定义了一个person对象,它有四个属性
var person = {
name : "mofan" ,
age : 18 ,
gender : "男" ,
score : 100
}
JS中的对象,{…} 表示一个对象,键值对描述属性及属性值,多个属性之间使用逗号,隔开,最后一个属性不需要加逗号,。
JS中所有的键都是字符串,值是任意对象!😳
对象赋值
1 2 3 4 5 console . log ( person . name );
// 打印结果为: mofan
person . name = "默烦" ;
console . log ( person . name );
// 打印结果为: 默烦 , 原对象也会发生改变
使用一个不存在的对象属性并不会报错! 会显示 undefined
1 2 console . log ( person . height );
// 打印结果为: undefined
动态删减属性
1 2 3 4 delete person . name
// 返回true
console . log ( person );
// 打印结果为: {age: 18, gender: "男", score: 100}
动态添加属性
1 2 3 person . weight = 120 ;
console . log ( person );
// 返回结果为: {age: 18, gender: "男", score: 100, weight: 120}
判断某个属性是否在这个对象中,继承的属性也算。 使用 in 关键字
1 2 3 4 5 console . log ( 'age' in person );
// 返回结果为: true
// 继承
console . log ( 'toString' in person );
// 返回结果为: true
判断某个属性是否是这个对象自身拥有的 hasOwnProperty()
1 2 3 4 console . log ( person . hasOwnProperty ( 'age' ));
// 打印结果为: true
console . log ( person . hasOwnProperty ( 'toString' ));
// 打印结果为: false
3.4 流程控制
if 判断
1 2 3 4 5 6 7 8 9 10 11 < script type = "text/javascript" >
"use strict"
var age = 3 ;
if ( age < 3 ){
alert ( "小于3" );
} else if ( age > 3 && age < 5 ){
alert ( "大于3,小于5" );
} else {
alert ( "范围未知" );
}
</ script >
循环
while 循环, 避免死循环
1 2 3 4 5 6 7 8 9 10 var age = 3 ;
while ( age < 100 ){
age = age + 2 ;
console . log ( age );
}
// 区分
do {
age = age + 2 ;
console . log ( age );
} while ( age < 100 )
for 循环
1 2 3 for ( let i = 0 ; i < 100 ; i ++ ){
console . log ( i );
}
forEach 循环(ES5.1的特性 )
1 2 3 4 var arr = [ 1 , 12 , 34 , 25 , 66 , 775 , 34 ];
arr . forEach ( function ( value ){
console . log ( value ); //遍历数组元素
});
for … in … 循环 (不建议 使用这种方式遍历数组)😵
1 2 3 4 5 6 7 8 9 10 11 var arr = [ 1 , 12 , 34 , 25 , 66 , 775 , 34 ];
for ( var num in arr ){ // num 是数组下标
if ( arr . hasOwnProperty ( num )){
console . log ( arr [ num ]); //遍历数组元素
}
}
arr . name = "345" ; //早起的漏洞
for ( var x in arr ){ // num 是数组下标
console . log ( x );
}
// 打印结果为:0 1 2 3 4 5 6 name
3.5 Map和Set
这些是 ES6 的新特性!
Map
1 2 3 4 5 6 7 8 9 10 11 12 // ES6 Map
"use strict"
var map = new Map ([[ 'Tom' , 100 ],[ 'Jerry' , 90 ],[ 'Spike' , 80 ]]);
var name = map . get ( 'Tom' );
map . set ( 'Butch' , 60 ); //新增或修改
console . log ( name );
// 打印结果为: 100
console . log ( map );
// 打印结果为: Map(4) {"Tom" => 100, "Jerry" => 90, "Spike" => 80, "Butch" => 60}
map . delete ( 'Spike' );
console . log ( map );
// 打印结果为: Map(3) {"Tom" => 100, "Jerry" => 90, "Butch" => 60}
Set
无需不重复 的集合。
1 2 3 4 5 6 7 8 9 10 11 12 //ES6 Set
var set = new Set ([ 3 , 2 , 1 , 1 , 1 , 1 ]);
console . log ( set );
// 打印结果为: Set(3) {3, 2, 1}
set . add ( "2" );
console . log ( set ); //添加
// 打印结果为: Set(4) {3, 2, 1, "2"}
set . delete ( "2" );
console . log ( set ); //删除
// 打印结果为: Set(3) {3, 2, 1}
console . log ( set . has ( 3 )); //是否包含某个元素
// 打印结果为: true
3.6 iterator
ES6的新特性! for … of … 循环
遍历数组:
1 2 3 4 var arra = [ 1 , 2 , 3 , 4 , 5 ];
for ( var x of arra ){
console . log ( x ); //遍历数组元素
}
遍历Map:
1 2 3 4 var map = new Map ([[ 'Tom' , 100 ],[ 'Jerry' , 90 ],[ 'Spike' , 80 ]]);
for ( let x of map ){
console . log ( x ); //遍历Map
}
遍历Set:
1 2 3 4 var set = new Set ([ 3 , 2 , 1 , 1 , 1 , 1 ]);
for ( let x of set ){
console . log ( x ); // 遍历Set
}
4. 函数
4.1 定义函数
定义方式一
绝对值函数:
1 2 3 4 5 6 7 function abs ( x ){
if ( x >= 0 ){
return x ;
} else {
return - x ;
}
}
一旦执行到 return 代表函数结束,就返回结果!
如果没有执行 return ,函数执行完也会返回结果,返回结果是undefined。
定义方式二
1 2 3 4 5 6 7 var abs = function ( x ){
if ( x >= 0 ){
return x ;
} else {
return - x ;
}
}
function(x){…} 是一个匿名函数,但是可以把结果赋值给abs,通过abs就可以调用函数。
方式一和方式二的效果是等价的!
调用函数
调用时的参数问题:
JS中调用函数时可以传入任意个参数,也可以不传入参数。
假设不存在参数,应该怎么规避呢?手动抛出异常👇:
1 2 3 4 5 6 7 8 9 10 11 var abs = function ( x ){
// 手动抛出异常
if ( typeof x !== 'number' ){
throw 'Not a Number' ;
}
if ( x >= 0 ){
return x ;
} else {
return - x ;
}
}
arguments
arguments 是JS的一个内置属性(JS免费赠送的关键字)。
arguments代表传递入函数的所有参数,是一个数组 。
1 2 3 4 5 6 7 8 9 10 11 var abs = function ( x ){
console . log ( "x=>" + x );
for ( var i = 0 ; i < arguments . length ; i ++ ){
console . log ( arguments [ i ]);
}
if ( x >= 0 ){
return x ;
} else {
return - x ;
}
}
问题:arguments包含了所有的参数。但我们有时候会使用定义以外的参数来进行附加操作,就需要排除定义的参数,使用arguments却十分麻烦。
如:现有一个函数 function(a,b,c,d,e),但我在使用时只想传入参数c、d,不使用a、b,即:function(c,d)。那么我需要进行参数位置的判断,如果使用arguments,我将会从a开始遍历判断,这显得十分臃肿麻烦,那么有其他的方式获得定义以外的参数吗(直接从c开始遍历判断)?rest解决了这个问题。
rest
ES6新特性! 获取除了已经定义的参数的所有参数。
ES6之前的方式:
1 2 3 4 5 if ( arguments . length > 2 ){
for ( var i = 2 ; i < arguments . length ; i ++ ){
...
}
}
ES6引入新特性,可以获取定义参数之外的所有参数:
1 2 3 4 5 function abc ( a , b , ... rest ){
console . log ( "a=>" + a );
console . log ( "b=>" + b );
console . log ( rest );
}
rest参数只能写在最后的参数位置,必须用…标识。
4.2 变量的作用域
在JS中,var 定义的变量是有作用域的。
👇假设在函数体内使用 var 定义了一个变量 x ,那么在函数体外是不可以使用 x 的。
1 2 3 4 5 function ab (){
var x = 1 ;
x = x + 1 ;
}
x = x + 2 ; // Uncaught ReferenceError: x is not defined
👇如果在两个函数中使用 var 定义了相同的变量名,只要在函数内部,就不会产生冲突。
1 2 3 4 5 6 7 8 function ab (){
var x = 1 ;
x = x + 1 ;
}
function abc (){
var x = "A" ;
x = x + 1 ;
}
👇内部函数可以访问外部函数成员,但外部函数不能访问内部函数。
1 2 3 4 5 6 7 8 9 function ab (){
var x = 1 ;
// 内部函数可以访问外部函数成员
// 但外部函数不能访问内部函数
function ab2 (){
var y = x + 1 ; // 2
}
z = y + 1 ; // Uncaught ReferenceError: y is not defined
}
👇内部函数变量和外部函数变量重名:
1 2 3 4 5 6 7 8 9 10 11 function ab (){
var x = 1 ;
function ab2 (){
var x = 'A' ;
console . log ( 'inner:' + x ); // outer:1
}
console . log ( 'outer:' + x ); // inner:A
ab2 ();
}
ab ()
JS中函数查找变量是从自身函数开始的,由“内”向“外”查找,假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量。
提升变量的作用域
1 2 3 4 5 6 function ab (){
var x = "x+" + y ;
console . log ( x );
var y = "y" ;
}
ab ();
打印结果为:x+undefined
说明:JS执行程序时,自动提升了 y 的声明,但是不会提升变量 y 的赋值。
1 2 3 4 5 6 7 // ab()等价于ab2()
function ab2 (){
var y ;
var x = "x" + y ;
console . log ( x );
y = "y" ;
}
这个是JS建立之初就存在的特性。
❗养成规范:所有变量都定义在函数的头部 ,不要随意放置,便于代码维护。如:
1 2 3 4 5 6 function abc (){
var a = 1 ,
b = a + 1 ,
c , d , f ;
// 然后对这些变量进行使用
}
全局变量
定义在函数外的变量就是全局变量。
1 2 3 4 5 6 7 // 全局变量
var x = 1 ;
function f (){
console . log ( x );
}
f ();
console . log ( x );
全局变量 window
1 2 3 4 5 var xx = "xxx" ;
alert ( xx );
alert ( window . xx );
console . log ( xx );
console . log ( window . xx );
alert()这个函数本身也是window的一个变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var xx = "xxx" ;
window . alert ( xx );
var old_alert = window . alert ;
old_alert ( xx ); // 可以弹出消息框,显示xx
window . alert = function (){
}
// 发现alert失效了
window . alert ( 123 );
// 恢复
window . alert = old_alert ;
window . alert ( 456 );
JS实际中只有一个全局作用域window,假设某一变量(函数也可以视为变量)没有在函数作用域内找到,就会向外查找,直到查找到全局作用域window。如果window中也没有找到,就会报错RefrenceError。
规范
我们所有的全局变量都是绑定在全局作用域window上的,如果不同的js文件使用了相同的全局变量就会产生冲突,那么我们应该怎么避免(减少)冲突呢?👇
1 2 3 4 5 6 7 8 9 // 全局唯一变量
// 相当于我自己定义一个对象,所有的变量都绑定在这个对象上
var myField = {};
// 定义全局变量
myField . name = "mofan" ;
myField . add = function ( a , b ){
return a + b ;
}
相当于自己的代码全部放到自己定义的唯一命名空间名字中,用于降低全局命名冲突👌。
局部作用域 let
1 2 3 4 5 6 7 8 function bbb (){
for ( var i = 0 ; i < 100 ; i ++ ) {
console . log ( i );
}
console . log ( i + 1 ); // i 出了这个作用域还可以使用
// 输出到101
}
bbb ();
在ES6中,提出 let 关键字,解决局部作用域冲突问题。
1 2 3 4 5 6 7 function bbb (){
for ( let i = 0 ; i < 100 ; i ++ ) {
console . log ( i );
}
console . log ( i + 1 ); // Uncaught ReferenceError: i is not defined
}
bbb ();
❗建议 要求 大家都使用 let 去定义局部作用域的变量。
常量 const
在ES6之前,我们这么定义“常量”:
只要用全部大写字母命名的变量,就是“常量”,建议不要修改这样的值。但是这只是一种约定,这个值依然是可以修改的。
1 2 3 4 var PI = '3.14' ;
console . log ( PI ); // 打印出:3.14
PI = '123' ; // 只是一种约定,依然可以改变
console . log ( PI ); // 打印出:123
因此在ES6中,引入关键字 const 用来定义常量。
1 2 3 const PI = '3.14' ; // 只读变量 常量
PI = '123' ; // Uncaught TypeError: Assignment to constant variable.
console . log ( PI );
4.3 方法
定义方法
方法就是把函数放在对象里面,对象内只有两个东西:属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 var mofan = {
name : '默烦' ,
birth : 2000 ,
//方法
age : function (){
var now = new Date (). getFullYear ();
return now - this . birth ;
}
}
/***********浏览器内调用***********/
mofan . name // 属性
mofan . age () // 年龄
❓那么上述代码中的this是什么意思呢,或者说this指向的是谁呢?
⭐ 先给出结论:谁调用this,this就指向谁。
我们可以对上述代码进行改造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function getAge (){
var now = new Date (). getFullYear ();
return now - this . birth ;
}
var mofan = {
name : '默烦' ,
birth : 2000 ,
age : getAge
}
/* ********浏览器内调用******* */
mofan . age () // 20
getAge () // NaN
为什么输出结果会像上述那样呢?
对于mofan.age(),age()表示的就是getAge(),getAge()中的this就表示mofan对象;而对于单个getAge(),其中的this指向的是window,但是在window这个全局变量中是没有birth属性的,因此返回的结果就是NaN。
apply
在Java中,this的指向无法指定的,谁调用它,它就指向谁。
但是!在JS中可以控制this的指向。😳
比如:
1 2 3 // 在上述代码中添加下列语句
console . log ( getAge . apply ( mofan ,[])); // 表示this指向了默烦,getAge参数为空
// 浏览器内输出:20
5. 内部对象
标准对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 typeof 123
"number"
typeof '123'
"string"
typeof []
"object"
typeof {}
"object"
typeof true
"boolean"
typeof NaN
"number"
typeof Math . abs
"function"
typeof undefined
"undefined"
5.1 Date
基本使用
1 2 3 4 5 6 7 8 9 10 11 12 var now = new Date ();
console . log ( now ); // 详细时间
console . log ( now . getFullYear ()); // 年
console . log ( now . getMonth ()); // 月 0~11
console . log ( now . getDate ()); // 日
console . log ( now . getDay ()); // 星期
console . log ( now . getHours ()); // 小时
console . log ( now . getMinutes ()); // 分钟
console . log ( now . getSeconds ()); // 秒
console . log ( now . getTime ()); // 时间戳
// 时间戳转时间
console . log ( new Date ( 1591002279219 ));
转换
1 2 3 4 5 6 7 8 9 10 now = new Date ( 1591002279219 )
// Mon Jun 01 2020 17:04:39 GMT+0800 (中国标准时间)
now . toDateString ()
// "Mon Jun 01 2020"
now . toLocaleString ()
// "2020/6/1 下午5:04:39"
now . toGMTString ()
// "Mon, 01 Jun 2020 09:04:39 GMT"
now . toLocaleDateString ()
// "2020/6/1"
5.2 JSON
什么是JSON
早期,所有的数据传输习惯使用XML文件!JSON:
(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
它基于 ECMAScript (欧洲计算机协会制定的 JS 规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
——源自百度百科
在JS中,一切皆为对象,任何JS支持的类型都可以用JSON表示。
格式:
对象使用{ }
数组使用[ ]
所有的键值对,都使用 key: value
JSON 的数据类型有:
字符串
数字
对象(JSON 对象)
数组
布尔
null
介绍一下对象类型(其他几种都很好理解),被大括号包裹起来的数据就是一个对象(这个 JSON 对象可能没有字段名,也可能有)。
如:{"name":"mofan","age":20,"gender":"男"}
1 2 3 4 5 6 7 8 9 10 11 12 var person = {
name : 'mofan' ,
age : 20 ,
gender : '男'
}
console . log ( person );
// 对象转换为JSON字符串
var jsonPerson = JSON . stringify ( person );
console . log ( jsonPerson );
// JSON字符串转换为对象
var objPerson = JSON . parse ( '{"name":"mofan","age":20,"gender":"男"}' );
console . log ( objPerson );
JSON 与 对象比较:
1 2 var obj = { name : mofan , age : 20 };
var json = '{"name":"mofan", "age":"20"}' ;
6. 面向对象编程
6.1 什么是面向对象
JS、Java、C# … 都有面向对象。但JS中与其他的有些区别!
类:对象的抽象,模板;对象:具体的实例。
原型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var Student = {
name : 'mofan' ,
age : 20 ,
run : function (){
console . log ( this . name + " run..." );
}
}
var xiaoming = {
name : "xiaoming"
}
// xiaoming 的原型设置为Student
xiaoming . __proto__ = Student ;
xiaoming . run ();
var Bird = {
fly : function (){
console . log ( this . name + " fly..." );
}
}
xiaoming . __proto__ = Bird ;
xiaoming . fly ();
1 2 3 4 5 6 7 8 function Student ( name ){
this . name = name ;
}
//给Student新增加一个方法
Student . prototype . hello = function (){
alert ( "Hello!" );
}
Class继承
class关键词是在ES6引入的。
1、定义一个类:属性,方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // ES6之后
// 定义一个学生的类
class Student {
constructor ( name ) {
this . name = name ;
}
hello (){
alert ( "Hello!" );
}
}
var xiaoming = new Student ( "xiaoming" );
console . log ( xiaoming . name );
var xiaowang = new Student ( "xiaowang" );
console . log ( xiaowang . name );
2、继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // ES6之后
// 定义一个学生的类
class Student {
constructor ( name ) {
this . name = name ;
}
hello (){
alert ( "Hello!" );
}
}
class ElementaryStudents extends Student {
constructor ( name , grade ) {
super ( name );
this . grade = grade ;
}
myGrade (){
alert ( "我考了100分" );
}
}
var xiaoming = new Student ( "xiaoming" );
console . log ( xiaoming . name );
var xiaowang = new ElementaryStudents ( "xiaowang" , 8 );
xiaowang . myGrade ();
console . log ( xiaowang . name );
console . log ( xiaowang . grade );
原型链
__proto__:
参考链接:javascript——原型与原型链
7. 操作BOM对象(重点)
BOM:浏览器对象模型
JS的诞生就是为了能够让它在浏览器中运行!
window (重要)
window代表 浏览器窗口、全局作用域。
1 2 3 4 5 6 7 8 9 // 在浏览器开发者模式中输入...
window . innerHeight
// 150
window . innerWidth
// 768
window . outerHeight
// 840
window . outerWidth
// 784
navigator
Navigator:封装了浏览器的信息(一个类)。
1 2 3 4 navigator . appName // 浏览器名称
navigator . appVersion // 浏览器的平台和版本信息
navigator . userAgent // 返回由客户机发送服务器的user-agent 头部的值
navigator . platform // 返回运行浏览器的操作系统平台
大多数时候,我们不会使用navigator对象,因为这些内容可以被人为修改。
❗不建议使用这些属性来判断和编写代码。
screen
screen:代表屏幕的尺寸
1 2 3 4 screen . width
// 1536
screen . height
// 864
location (重要)
location:代表当前页面的URL信息。
1 2 3 4 5 6 host : "www.baidu.com"
href : "https://www.baidu.com/?tn=02003390_42_hao_pg"
protocol : "https:"
reload : ƒ reload () // 刷新网页
// 设置新的地址
location . assign ( "https://www.bilibili.com/" );
document
document代表当前的页面,HTML、DOM文档树。
1 2 3 4 document . title
// "百度一下,你就知道"
document . title = ‘ mofan ’
// "mofan"
获取具体的文档树节点:
1 2 3 4 5 6 7 8 9 10 < body >
< dl id = "app" >
< dt >Java</ dt >
< dd >JavaSE</ dd >
< dd >JavaEE</ dd >
</ dl >
</ body >
< script type = "text/javascript" >
var dl = document . getElementById ( 'app' );
</ script >
获取cookie:
正是因为可以获取到cookie,因此有些不法分子可能会劫持你的cookie而上传到他的服务器上,让你的隐私曝光!我们在编写代码时,尽量不要让cookie曝光,服务端可以设置cookie:httpOnly,来保证用户信息隐私。
history
history代表浏览器的历史记录。(不建议使用)
1 2 history . back () // 后退
history . forward () // 前进
8. 操作DOM对象(重点)
核心
一个网页就是一个DOM树形结构。DOM节点可有的操作:
更新:更新DOM节点
遍历:得到DOM节点
删除:删除一个DOM节点
添加:添加一个DOM节点
要操作一个DOM节点,就必须先获得这个DOM节点。
8.1 获得DOM节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 < body id = "father" >
< h1 >标题1</ h1 >
< p id = "p1" >p1</ p >
< p class = "p2" >p2</ p >
< script type = "text/javascript" >
// 对应CSS选择器
var h1 = document . getElementsByTagName ( 'h1' );
var p1 = document . getElementById ( 'p1' );
var p2 = document . getElementsByClassName ( 'p2' );
var father = document . getElementById ( 'father' );
var children = father . children ; // 获取父节点下的所有子节点
// father.firstChild
// father.lastChild
</ script >
</ body >
8.2 更新节点
1 2 3 4 5 6 7 8 9 10 < body >
< div id = "id1" >
</ div >
< script type = "text/javascript" >
var id1 = document . getElementById ( 'id1' );
id1 . innerText = "hello!" ;
id1 . innerHTML = '<strong>world</strong>' ;
</ script >
</ body >
id1.innerText = "hello!"; 修改文本的值
id1.innerHTML = '<strong>world</strong>'; 解析HTML文本标签
紧接上述代码,我们使用JS操作CSS:
1 2 3 id1 . style . color = 'red' ;
id1 . style . fontSize = '30px' ;
id1 . style . padding = '2em' ;
这样,我们页面上的“world”字样呈现红色,字号为30px,内边距为2em。
8.3 删除节点
步骤:
获取父节点
再通过父节点删除自己
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 < body id = "father" >
< h1 >标题1</ h1 >
< p id = "p1" >p1</ p >
< p class = "p2" >p2</ p >
< script type = "text/javascript" >
var p1 = document . getElementById ( 'p1' );
var father = p1 . parentElement
father . removeChild ( p1 ); // 删除p1节点
/* 错误操作:删除是一个动态的过程
father.removeChild(father.children[0]);
father.removeChild(father.children[1]);
father.removeChild(father.children[2]);
*/
</ script >
</ body >
注意: 删除多个节点的时候,children是在时刻变化的,因此在删除时需要时刻注意!
8.4 插入节点
我们获得了某个界面,假设这个DOM节点时空的,我们可以通过innerHTML给这个节点增加元素,但是如果这个节点内有其他元素,使用innerHTML增加元素会覆盖原来的元素。这并不是我们想要的!😟
因此我们其他方式来添加(追加 )节点!
移动已存在的节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 < body >
< p id = "js" >JS</ p >
< div id = "list" >
< p id = "se" >JavaSE</ p >
< p id = "ee" >JavaEE</ p >
< p id = "ME" >JavaME</ p >
</ div >
< script type = "text/javascript" >
var js = document . getElementById ( 'js' ); // 已存在的节点
var list = document . getElementById ( 'list' );
list . appendChild ( js );
</ script >
</ body >
效果:
创建一个新的节点,实现插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 < body >
< p id = "js" >JS</ p >
< div id = "list" >
< p id = "se" >JavaSE</ p >
< p id = "ee" >JavaEE</ p >
< p id = "ME" >JavaME</ p >
</ div >
< script type = "text/javascript" >
var js = document . getElementById ( 'js' );
var list = document . getElementById ( 'list' );
// list.appendChild(js);
// 通过js创建一个新的节点
var newP = document . createElement ( 'p' );
newP . id = 'newP' ;
newP . innerText = 'mofan' ;
list . appendChild ( newP );
// 创建一个标签节点
var myScript = document . createElement ( 'script' );
myScript . setAttribute ( 'type' , 'text/javascript' );
</ script >
</ body >
结果:
insertBefore
insertBefore()方法可在已有的子节点前插入一个新的子节点。
提示: 如果你想创建一个新的文本列表项,在 LI 元素后你应该添加元素的文本节点,然后在列表中添加 LI元素。
你也可以使用 insertBefore() 方法来 插入/移除 已存在的元素。
语法:
node.insertBefore(newnode,existingnode)
newnode:要插入的节点对象;existingnode:要添加新的节点前的子节点
1 2 3 4 5 var ee = document . getElementById ( 'ee' );
var js = document . getElementById ( 'js' );
var list = document . getElementById ( 'list' );
// 要包含的节点.insertBefore(newNode,existingnode)
list . insertBefore ( js , ee );
结果:
9. 操作表单(表单验证)
表单内可以包含:
文本框 text
下拉框 <select>
单选框 radio
多选框 checkbox
隐藏域 hidden
密码框 password
…
获得填写的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 < body >
< form action = "#" method = "post" >
< p >< span >用户名:</ span >< input type = "text" id = "username" ></ p >
<!-- 多选框的值就是定义好的value值 -->
< p >
< span >性别:</ span >
< input type = "radio" name = "gender" value = "boy" id = "boy" />男
< input type = "radio" name = "gender" value = "girl" id = "girl" checked />女
</ p >
</ form >
< script type = "text/javascript" >
// 得到输入框的值
var input_text = document . getElementById ( 'username' );
var boy_radio = document . getElementById ( 'boy' );
var girl_radio = document . getElementById ( 'girl' );
console . log ( input_text . value );
// 修改输入框的值
input_text . value = '123' ;
console . log ( input_text . value );
// 对于单选框、多选框等固定的值,value只能取到标签内的value属性值
// 查看是否被选中,选中返回1,未选中返回0
console . log ( boy_radio . checked );
boy_radio . checked = true ; // 设置被选中
console . log ( boy_radio . checked );
</ script >
</ body >
提交表单
表单优化并使用MD5加密密码!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <! DOCTYPE html >
< html >
< head >
< meta charset = "utf-8" >
< title >提交表单并加密</ title >
< script src = "https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.10.0/js/md5.min.js" ></ script >
</ head >
< body >
<!--
表单绑定提交事件
onsubmit = 绑定一个提交检测的函数,返回true或false
将这个结果返回给表单,使用onsubmit接收!
onsubmit="return check();"
-->
< form action = "https://www.baidu.com/" method = "post" onsubmit = " return check ();" >
< p >< span >用户名:</ span >< input type = "text" id = "username" name = "username" ></ p >
<!-- 多选框的值就是定义好的value值 -->
< p >< span >密码:</ span >< input type = "password" id = "input-password" ></ p >
< input type = "hidden" name = "password" id = "md5-password" />
<!-- <button type="button" onclick="check()">提交</button> -->
< button type = "submit" >提交</ button >
</ form >
< script type = "text/javascript" >
function check (){
var username = document . getElementById ( 'username' );
var pwd = document . getElementById ( 'input-password' );
var md5Pwd = document . getElementById ( 'md5-password' );
console . log ( username . value );
md5Pwd . value = md5 ( pwd . value );
console . log ( md5Pwd . value );
// 校验表单内容,true就是校验成功并提交,false阻止提交
return true ;
}
</ script >
</ body >
</ html >
10. jQuery
jQuery就是一个封装了大量的JS函数的库。
先上个中文文档:jQuery API 中文文档 😏
引入jQuery:
1 < script src = "http://libs.baidu.com/jquery/2.0.0/jquery.min.js" ></ script >
使用公式:$(selector).action()
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <! DOCTYPE html >
< html >
< head >
< meta charset = "utf-8" >
< title ></ title >
< script src = "http://libs.baidu.com/jquery/2.0.0/jquery.min.js" ></ script >
</ head >
< body >
< a href = "" id = "test-jQuery" >点我弹窗</ a >
< script type = "text/javascript" >
$ ( '#test-jQuery' ). click ( function (){
alert ( 'hello,jQuery!' );
});
</ script >
</ body >
</ html >
10.1 jQuery选择器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 < script type = "text/javascript" >
/* 原生JS选择器,选择器少,而且臃肿 */
// 标签
document . getElementsByTagName ();
// id
document . getElementById ();
// 类
document . getElementsByClassName ();
/* jQuery选择器,选择器多且简洁,CSS中的选择器都可在jQuery中使用 */
// 标签
$ ( 'p' ). click ();
// id
$ ( '#id1' ). click ();
// 类
$ ( '.class1' ). click ();
</ script >
再放一遍中文参考文档网址:jQuery API 中文文档 😉
10.2 jQuery 事件
事件一般分为:鼠标事件、键盘事件、其他事件
事件的响应函数可以去文档中查看(对!又是它!): jQuery API 中文文档 😝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <! DOCTYPE html >
< html >
< head >
< meta charset = "utf-8" >
< title ></ title >
< script src = "http://libs.baidu.com/jquery/2.0.0/jquery.min.js" ></ script >
< style type = "text/css" >
#divMove {
width: 500 px ;
height: 500 px ;
border: 1 px solid red ;
}
</ style >
</ head >
< body >
<!-- 获取鼠标当前坐标 -->
mouse:< span id = "mouseMove" ></ span >
< div id = "divMove" >
在这移动试试
</ div >
< script type = "text/javascript" >
/* 当网页元素加载完毕之后,响应事件 */
$ ( function (){
$ ( '#divMove' ). mousemove ( function ( e ){
$ ( '#mouseMove' ). text ( 'x:' + e . pageX + 'y:' + e . pageY );
})
})
</ script >
</ body >
</ html >
10.3 jQuery 操作DOM
节点文本操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 < body >
< ul id = "test-ui" >
< li class = "js" >JS</ li >
< li name = "java" >Java</ li >
</ ul >
< script type = "text/javascript" >
// document.getElementById('')
// 获得值
$ ( '#test-ui li[name=java]' ). text ();
// 重载值
$ ( '#test-ui li[name=java]' ). text ( '123456' );
// 获得值
$ ( '#test-ui' ). html ();
// 重载值
$ ( '#test-ui' ). html ( '<u>987654</u>' );
</ script >
</ body >
css的操作:
1 $ ( '#test-ui li[name=java]' ). css ( "color" , "red" );
元素的显示和隐藏: 本质依然是 display: none
1 2 $ ( '#test-ui li[name=java]' ). show ();
$ ( '#test-ui li[name=java]' ). hide ();
其他测试:
1 2 3 $ ( window ). width ()
$ ( window ). height ()
...
还有ajax,参考Spring MVC
其余内容参考文档,最后一次再放出链接:jQuery API 中文文档 😆