文章目录
3 JavaScript
3.1 什么是JavaScript
JavaScript(行为):是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行,用于控制网页的行为,是一门世界上最流行的脚本语言
一个合格的后端人员,必须要精通JavaScript
ECMAScript可以理解为是JavaSctipt的一个标准,最新版本已经到es6版本,但是大部分浏览器还只停留在支持es5代码上!导致开发环境和线上环境版本不一致
3.2 快速入门
3.2.1 引入JavaScript
- 内部标签
<script>
//......
</script>
- 外部引入
abs.js
//...
test.html
<script src="abc.js"></script>
- 测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--script标签内,写javascript代码-->
<script>
alert('hello, world');
</script>
<!--外部引入:注意,script标签必须成对出现-->
<script src="js/qj.js"></script>
<!--不用显示定义type,也默认就是javascript-->
<script type="text/javascript"></script>
</head>
<body>
<!--这里也可以存放JavaScript代码-->
</body>
</html>
3.2.2 基本语法入门
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
// 1.定义变量 变量类型 变量名 = 变量值;
var score = 60;
var name = "qinjiang";
'helloworld'
alert(score);
// 2.条件控制
if (score > 60 && score < 70){
alert("60~70");
}else if (score > 70 && score < 80){
alert("70~80");
}else{
alert("other");
}
/*JavaScript严格区分大小写
console.log(score) 在浏览器的控制台打印变量!System.out.println();
*/
</script>
</head>
<body>
</body>
</html>
3.2.3 数据类型
数值,文本,图形,音频,视频…
- 变量
var $A_a = 1
- number:js不区分小数和整数,统一用number
123 // 整数
123.1 // 浮点数
1.23e3 //科学计数法
-99 //负数
NaN //not a number
Infinity //无限大
- 字符串
'abc'
"abc"
-
布尔值:true,false
-
逻辑运算
&& // 两个都为真,结果为真
|| // 一个为真,结果为真
! // 真即假,假即真
- 比较运算符(重要)
=
== // 等于(类型不一样,值一样,也会判断为true)
=== // 绝对等于(类型一样,值一样,结果为true)
这是一个js的缺陷,坚持不要使用==比较
须知:NaN == NaN,这个与所有的数值都不想等,包括自己,只能通过isNaN(NaN)来判断
- 浮点数问题:尽量避免使用浮点数进行运算,存在精度问题
console.log((1/3) === (1-2/3))
Math.abs(1/3-(1-2/3) < 0.00000000001)
-
null 和 undefined
null空
undefined未定义
-
数组
Java的数组必须是相同类型的对象,js中不需要这样
var arr = [1, 2, 3, 4, 5, 'hello', null, true]; // 常用
new Array(1, 12, 3, 4, 5, 'hello');
数组下标如果越界了,就会报错
underfined
- 对象
对象是大括号,数组是中括号
对象的每个属性之间使用逗号隔开,最后一个不需要添加符号
// Person person = new Person(1, 2, 3, 4, 5);
var person = {
name: 'qinjiang',
age: 3,
tags: ['js', 'java', 'web', '...']
}
取对象的值
person.name
> "qinjiang"
person.age
> 3
3.2.4 严格检查格式
<!--前提:IDEA需要支持ES6语法
'use strict'; 严格检查模式,预防js的随意性导致产生的一些问题
必须写在js的第一行-->
<script>
'use strict';
var j = 1;
// ES6 let 局部变量都建议使用let定义
let i = 1;
</script>
3.3 数据类型
3.3.1 字符串
- 正常字符串我们使用 ’ ’ 或者 " " 包裹
- 注意注意字符 \
\'
\n //换行
\t //table
\u4e2d //中 \u#### Unicode字符
\x41 // Ascll字符
- 多行字符串编写
//tab上esc下的paio键~
let msg = `hello
world
你好啊!
`;
- 模拟字符串
let name = "qinjiang";
let msg1 = `你好呀,${name}`
console.log(msg1)
- 字符串长度
console.log(str.length);
- 字符串的不可变性
- 大小写转换
//注意,这里是方法,不是属性
student.toUpperCase()
student.toLowerCase()
- 获取指定下标
student.indexOf('u')
- substring
student.substring(1) // tudent, 从第一个截取到最后一个字符
student.substring(1, 3) // tu, [1, 3)
3.3.2 数组
Array可以包含任意的数据类型
- 长度
arr.length
注意:加入给arr.length赋值,数组长度就会发生变化,如果赋值过小,元素就会丢失
arr.length = 10
arr
> (10) […]
arr[7]
> undefined
arr.length = 2
arr
> (2) […]
- indexof,通过元素获得下标索引
arr.indexOf(2)
1
字符串的 “1” 和数字 1 是不同的
-
slice() 可以截取Array的一部分,返回一个新数组,类似于String中的substring
-
push()、pop() 尾部
push //压入到数组尾部
pop //弹出数组尾部的一个元素
- unshift()、shift() 头部
unshift //压入到数组头部
shift //弹出数组头部的一个元素
- 排序
a
> Array(3) [ "b", "c", "a" ]
a.sort()
> Array(3) [ "a", "b", "c" ]
- 元素反转
a.reverse()
> Array(3) [ "c", "b", "a" ]
- concat()
a.concat([1, 2, 3])
> Array(6) [ "c", "b", "a", 1, 2, 3 ]
a
> Array(3) [ "c", "b", "a" ]
注意:concat() 并没有修改数组,只是会返回一个新的数组
- 连接符join:打印拼接数组,使用特定的字符串连接
a.join('-')
> "c-b-a"
- 多维数组
arr = [[1, 2], [3, 4], ['5', '6']]
arr[1][1]
> 4
数组:存储数据(知道如何存、如何取,方法都可以自己实现)
3.3.3 对象
若干个键值对
var 对象名 = {
属性名: 属性值,
属性名: 属性值,
属性名: 属性值
}
Js中是用 {…} 表示一个对象,键值对描述属性xxx: xxx,多个属性之间使用逗号隔开,最后一个属性不加逗号!
- 对象赋值
person.name = 'qinjiang'
> "qinjiang"
person.name
> "qinjiang"
- 使用一个不存在的对象属性,不会报错
person.haha
> undefined
- 动态的删减属性:delete
delete person.name
> true
person
> Object { age: 3, email: "24736743@qq.com", score: 0 }
- 动态的添加属性:直接添加
person.haha = "haha"
> "haha"
person
> Object { age: 3, email: "24736743@qq.com", score: 0, haha: "haha" }
- 判断属性值是否在这个对象中
JavaScript中的所有键都是字符串,值是任意对象
"age" in person
> true
//继承
"toString" in person
> true
- 判断一个属性是否是这个对象自身拥有的
person.hasOwnProperty("toString")
> false
person.hasOwnProperty("age")
> true
3.3.4 流程控制
- if判断
let age = 3;
if (age > 3){
alert("haha");
}else if(age < 3){
alert("kuwa~");
}else {
alert("kuwa~~");
}
- while循环,避免程序死循环
while (age < 100){
age = age + 1;
console.log(age);
}
do{
age = age + 1;
console.log(age);
}while (age < 100)
- for循环
for (let i = 0; i < 100; i++){
console.log(i);
}
- 数组循环
let age = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
//输出对象的值
age.forEach(
function (value){
console.log(value);
}
)
//输出对象的key(下标)
for(let num in age){
console.log(num);
console.log(age[num]);
}
//遍历数组
for(let num of age){
console.log(num);
}
3.3.5 Map和Set
ES6的新特性
- Map
//ES6
//学生的成绩,学生的名字
//let names = ["tom", "jack", "haha"];
//let scores = [100, 90, 80];
let map = new Map([["tom", 100], ["jack", 90], ["haha", [80]]]);
let name = map.get("tom"); // 通过key获得value
console.log(name);
map.set("admin", 123456); // 新增或修改
> Map(4) { tom → 100, jack → 90, haha → (1) […], admin → 123456 }
map.delete("tom"); // 删除
- Set:无序不重复的集合
let set = new Set([3, 1, 1, 1, 1]); // set可以去重
set.add(2);
set.delete(1);
console.log(set.has(3)); // 是否包含那个元素
3.3.6 iterator
遍历数组、map、set
let arr = [3, 4, 5];
for (let x of arr){
console.log(x);
}
let map = new Map([["tom", 100], ["jack", 90], ["haha", 80]]);
for (let x of map){
console.log(x);
}
let set = new Set([5, 6, 7]);
for (let x of set){
console.log(x);
}
3.4 函数及面向对象
3.4.1 函数定义
- 定义方式一
绝对值函数
function abs(x){
if(x >= 0){
return x;
}else{
return -x;
}
}
一旦执行到return代表函数结束,返回结果!
如果没有执行return,函数执行完也会返回结果,结果就是 undefined 或 NaN
- 定义方式二
var abs = function(x){
if(x >= 0){
return x;
}else{
return -x;
}
} // 类似java的匿名内部类
function(x){…} 这是一个匿名函数,但是可以把结果赋值给abs,通过abs就可以调用函数
- 调用函数
abs(10) // 10
abs(-10) // -10
参数问题:javaScript可以传任意个参数,也可以不传参数
假设不存在参数,如何规避
//手动抛出异常来判断
if (typeof x !== 'number'){
throw 'Not a Number';
}
- arguments
arguments
是一个JS免费赠送的关键字,代表传递进来的所有的参数,是一个列表
var abs = function(x){
console.log("x => " + x);
for (let i = 0; i < arguments.length; i++){
console.log(arguments[i]);
}
}
abs(1, 2, 3, 4)
x => 1
1
2
3
4
问题:arguments会包含所有的参数,我们有时候想使用多余的参数来进行附加操作,需要排除已有的参数
- rest
获取除了已定义参数外的其他参数,rest参数只能卸载最后面,必须用…标识
function a(a, b, ...rest){
console.log("a => " + a);
console.log("b => " + b);
console.log("rest => " + rest);
}
a(1, 2, 3, 4, 5, 6, 7, 8)
a => 1
b => 2
rest => 3,4,5,6,7,8
3.4.2 变量的作用域
- 在Javascript,var定义变量实际是有作用域的,假设在函数体中声明,则在函数体外不可以使用(可以通过
闭包
实现)
'use strict'
function qj(){
var x = 1;
x = x + 1;
}
x = x + 2; // Uncaught ReferenceError: x is not defined
- 如果两个函数使用了相同的变量,只要在函数内部,就不冲突
'use strict'
function qj(){
var x = 1;
x = x + 1;
}
function qj2(){
var x = 'A';
x = x + 1;
}
- 内部函数可以访问外部函数的成员,反之则不行
'use strict'
function qj(){
var x = 1;
function qj2(){
var y = x + 1;
}
var z = y + 1; // Uncaught ReferenceError: y is not defined
}
- 假设内部函数变量和外部函数函数变量重名,采用就近原则
'use strict'
function qj(){
var x = 1;
//内部函数可以访问外部函数的成员,反之则不行
function qj2(){
var x = "A";
console.log('inner: ' + x); // inner: A
}
console.log('outer: ' + x); // outer: 1
qj2()
}
- 提升变量的作用域
'use strict'
function qj(){
var x = 'x' + y;
console.log(x);
var y = 1;
}
//上面的函数等价于下面的函数
function qj(){
// var x, y, z...
var y;
var x = 'x' + y;
console.log(x);
y = 1;
}
> x undefined
JS执行引擎,自动提升了y的声明,但是不会提升变量y的赋值;这是在JavaScript建立之初就存在的特性,要养成规范:所有的变量定义都放在函数头部
function qj2(){
var x = 1,
y = x + 1,
z, i, a; // underfined
// 之后随意用
}
- 全局函数
'use strict'
//全局变量
var x = 1;
function f(){
console.log(x);
}
f()
console.log(x);
全局对象window
'use strict'
var x = 'xxx';
window.alert(x); // alert()这个函数本身也是一个window变量
alert(window.x); // 默认所有的全局变量,都会自动绑定在window对象上
JavaScript实际上只有一个全局作用域,任何变量(函数也可以视为变量)假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域中都没有找到,就会报错 RefrenceError
var old = window.alert;
window.alert = function (){
};
//发现alert()失效了
window.alert(123);
//恢复
window.alert = old;
window.alert(456);
- 规范
由于我们所有的全局变量都会绑定到我们的window上,如果不同的js文件使用了相同的全局变量,就会冲突 ~ 解决方法:
// 唯一的全局变量
var KuangApp = {};
// 定义全局变量
KuangApp.name = 'kuangshen';
KuangApp.add = function (a, b){
return a + b;
}
把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名冲突的问题 jQuery
- 局部作用域let
解决局部作用域冲突问题,建议都用 let
去定义局部作用域的变量
function a() {
for (let i = 0; i < 100; i++){
console.log(i);
}
console.log("i: " + (i + 1)); // Uncaught ReferenceError: i is not defined
}
- 常量
在ES6之前,只有用全部大写字母命名的变量就是常量;建议不要修改这样的值
var PI = '3.14'
PI = '213'; //可以改变这个值
在ES6引入了常量关键字 const
const PI = '3.14' // 只读变量
PI = '213'; // Uncaught TypeError: invalid assignment to const 'PI'
3.4.3 方法
- 定义方法
var kuangshen = {
name: 'qinjiang',
birth: 2020,
//方法:就是把函数放在对象的里面,对象只有两个东西(属性和方法)
age: function (){
let now = new Date().getFullYear();
return now - this.birth;
}
}
//属性
kuangshen.name
//方法,一定要带()
kuangshen.age()
拆开上面的代码
function getAge(){
let now = new Date().getFullYear();
return now - this.birth;
}
var kuangshen = {
name: 'qinjiang',
birth: 2020,
age: getAge //方法作为一个变量
}
//kuangshen.age() // ok
//getAge() //NaN, 现在属于window
this是无法指向,是默认指向调用它的那个对象
- apply
在js中可以控制this指向
getAge().apply(kuangshen, []); // this指向了kuangshen这个对象,参数为空
> 20
kuangshen.age()
> 20
getAge()
> NaN
213’; //可以改变这个值
在ES6引入了常量关键字 `const`
```javascript
const PI = '3.14' // 只读变量
PI = '213'; // Uncaught TypeError: invalid assignment to const 'PI'
3.4.3 方法
- 定义方法
var kuangshen = {
name: 'qinjiang',
birth: 2020,
//方法:就是把函数放在对象的里面,对象只有两个东西(属性和方法)
age: function (){
let now = new Date().getFullYear();
return now - this.birth;
}
}
//属性
kuangshen.name
//方法,一定要带()
kuangshen.age()
拆开上面的代码
function getAge(){
let now = new Date().getFullYear();
return now - this.birth;
}
var kuangshen = {
name: 'qinjiang',
birth: 2020,
age: getAge //方法作为一个变量
}
//kuangshen.age() // ok
//getAge() //NaN, 现在属于window
this是无法指向,是默认指向调用它的那个对象
- apply
在js中可以控制this指向
getAge().apply(kuangshen, []); // this指向了kuangshen这个对象,参数为空
> 20
kuangshen.age()
> 20
getAge()
> NaN