前端学习 03 —— JavaScript 01

系列文章

前端学习 01 —— HTML5
前端学习 02 —— CSS01
前端学习 02 —— CSS 02
前端学习 02 —— CSS 03
前端学习 03 —— JavaScript 01
前端学习 03 —— JavaScript 02



一、什么是JavaScript

1.1、概述

JavaScript是一门世界上最流行的脚本语言,然而其作者只用了10天开发出来,一个合格的后端人员必须精通JavaScript。

JavaScript的相关历史,可以去这个博客看看~

https://blog.csdn.net/kese7952/article/details/79357868
 

二、快速入门

2.1、引入JavaScript

和CSS、HTML一样,用IDEA直接创建Java项目后删除src即可。这里的alter方法是弹窗。
在这里插入图片描述

HTML中:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>第一个js</title>
    <script>
        // 可以在这里直接写js
        alert("hello,world1!");
    </script>
    <!-- 导入必须写一对script标签,不能自闭合   -->
    <script src="js/first.js"></script>
</head>
<body>

    <script>
        // 有的也会写在body最下面
        alert("hello,world2!");
    </script>
</body>
</html>

js中:

alert("hello,world3!");

2.2、基本语法入门

首先要知道如何调试js,在IDEA中是没法直接调试的,我们可以通过浏览器调试。

运行网页后,按F12进入开发者模式,里面有console和sources,console就是控制台,我们可以直接在里面输入代码或是查看变量,而sources可以看到源码,点击左边的行号可以设置断点,然后刷新进入页面就能调试。

后面一般我们简短代码直接在Console里面写,这样更加快捷,console.log()是调试语句,可以输出变量,类似于System.out.println()。

浏览器控制台 调试断点

在js中的语法和Java基本类似,例如下面这样。

注意:JavaScript中的变量类型都用var,不过在一次更新后推荐局部变量使用let。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>第一个js</title>
    <script>
        let num = 80;
        if(num > 80)
            alert("优秀");
        else if(num > 70 && num < 80)
            alert("良");
        else
            alert("不及格");
    </script>
</head>
<body>
</body>
</html>

2.3、数据类型(概括)

1、数值型(number),js中不区分小数和整数。

123//整数
123.1//浮点数
1.123e3//科学计数法
-99//负数
NaN//not a number 表明不是一个数,但它本身也是数值型
Infinity//表示无穷大,js无法容纳

2、字符串:“abc”或者‘abc’

3、布尔值:true 或者 false

4、逻辑运算:&&、||、!

5、比较运算符:

= //赋值运算
== //等于 (类型不同但值一样,也为true,例如 1 == "1")
=== //绝对等于(类型和值都要相同,就是Java中的 == )

​ 注意:1. NaN === NaN,是false,NaN与所有数值都不相同,包括自己。用isNaN()判断。

​ 2.JS也存在浮点数问题,依然用绝对值解决,Math.abs((1/3)-(1-2/3))

5、null和undefined:null表示空,undefined表示未定义。比如数组越界会显示undefined。

6、数组:JS中的数组由于都是var类型,因此数组中不要求类型相同。

var arr = [1, 1.1, "hello", null, undefined]

7、对象:与Java不同,

/*
	class Person{
		String name = "z";
		int age = 3;
		int[] arr = [1,2,3];
	}
*/
var person = {
    
    
    name:"z",
    age:3,
    arr:["js", 1, 2]
};
alert(person.name);

2.4、严格检查模式

由于JavaScript的随意性经常导致一些BUG,所以有了严格检查模式,只需要在JavaScript第一行加入"use strict";就行。

下面对比一下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
   	/*这里的i会作为全局变量,真正的开发中会引起很大错误,一般是要求报错的,
   	但JavaScript由于其随意性不会报错。如果我们在第一行加入 "use sctrict"; 
   	则会对这种情况报错,一般都会使用严格检查模式*/
        i = 1;
    </script>
</head>
<body>
</body>
</html>

使用严格检查模式后:

严格检查模式

注意:使用严格检查模式要求JavaScript是ES6,要在IDEA进行设置。

ES6

三、数据类型(详细)

3.1、字符串

JavaScript中的字符串也不可变

1、正常字符串直接使用单引号或双引号包裹。

2、转义字符:

\' 输出单引号,\n 换行,\t tab键,\u#### unicode,\x## Ascll字符

3、多行字符串编写:这和Java有区别

var msg = `这里的符号是键盘ESC下面那个,不是单引号
			它可以直接输出多行,这就是第二行`

4、模板字符串 :这是ES6( ECMAScript 6 是JavaScript的标准)的新特性。

let name = "小明";
let age = 3;
let msg = `${
      
      name}已经${
      
      age}岁了`
console.log(msg);

结果在控制台中查看:

字符串结果1

5、字符串长度:正常调用字符串的方法

let str = "student"
console.log(str.lenth);

6、截取字符串:调用supstring(),若只给一个参数则从该参数到末尾

str.supstring(1, 4);//截取从第一个字符串到第4个(不包含第四个)

3.2、数组

Array可以包含任意的数据类型

var arr = [1,2,3,4,5];

1、长度

arr.length

注意:假如给arr.length赋值,数组大小会变化。如果使其变小,数据会丢失,如果使其变大,多余的会成为undefined类型。

2、indexOf():通过元素获得下表索引

arr.indexOf(2)
结果返回1,因为arr=[1,2,3,4,5],而数字2的下标为1

3、slice(),类似于supstring(),只用一个参数,则从该参数到末尾

>let arr2=[0,1,2,3,4];
>arr2.slice(2)//结果 [2, 3, 4]
>arr2.slice(0,2)//结果 [0, 1]

3、push,pop,unshift,shift

push():把数据压入到尾部
pop():把尾部数据弹出
unshift():压入到头部
shift():弹出头部的一个元素

4、数组排序 :sort()

5、元素逆序:reverse()

6、数组拼接:concat(新数组),返回一个拼接好的数组,并没有修改原数组

7、连接符:join()

let b = ['a','b','c'];
b.join('-');
返回结果:"a-b-c"

8、多维数组:和Java一样

var arr = [[1,2],[3,4]];
arr[1][1]
得到4

3.3、对象

这里只是说对象,还没涉及到面向对象。对象由若干个键值对构成,类似于json。

var 对象名 = {
    
    
    属性名:属性值,
    属性名:属性值,
    属性名:属性值
}
//定义了一个student对象,它由三个属性
let student = {
    
    
    name:"小明",
    age: 18,
    score:0
}

JS中对象用{ }表示,通过键值对来描述属性,每个属性用逗号隔开,最后一个不用。

我们可以在控制台查看,在IDEA中运行后,在浏览器F12,选择Console,然后直接输入student

对象

1、对象赋值

student.name = "小红";

2、可以使用一个不存在的属性,只会报undefined

sutdent.hahah
报undefined,但不会报错。

3、动态删除属性:通过delete

delete student.age//结果:true
student//结果:{name: "小明", score: 0}

4、动态的添加属性:直接给新的属性添加值

student.haha = 'haha'//返回 'haha'
student //返回 {name: "小明", score: 0, haha: "haha"}

5、判断属性值是否在这对象中:xxx in xxx

"age" in student //返回true
"toString" in student//返回true,toString是继承得到的

注意:JavaScript中属性值需要带引号

6、判断一个属性是否是中国对象自身拥有的:hasOwnProperty()

student.hasOwnProperty("toString");//返回false
student.hasOwnProperty("age");//返回true

3.4、流程控制

if判断、while循环、for循环和Java一样。

下面是两三个和Java不同的。( JavaScript里面没有 for(类型 a : 类型 b) )

// for in 是下标
let a = [1,2,3];
for(let num in a){
    
    
    console,log(a[num]);
}
//for of 是值
for(let num of a){
    
    
    console,log(a[num]);
}

 
其次就是forEach()循环

这是ES 5.1引入

let a = [1,2,3];
//这是通过函数的方式循环输出a数组,其中value会取到每个值
a.forEach(function(value){
    
    
    console.log(value);
})

3.5、Map和Set

Map和Set是ES6的新特性,虽然Java中已经有了

Map:

//学生成绩,学生姓名,用两个数组实现
let score = [100, 70, 40];
let names = ['Jack', 'Tom', 'Bob'];
//用Map实现
let map = new Map([['Jack',100],['Tom',70],['Bob',40]]);
map.set('Simpson',90);//用set方法修改或增加
map.delete('Jack');//用delete删除
map.get('Tom');//用get获取

 
Set:无序不重复的集合

let set = new Set([1,2,3,1,2]);//它会自动去掉重复的元素
set.delete(1);//删除1
set.has(1);//判断是否有1

3.6、迭代 Iteratble

这是ES 6 引入的

我们遍历数组、Map、Set都通过for of。

let map = new Map([['Jack',100],['Tom',70],['Bob',40]]);
for(let x of map){
    
    
    console.log(x);
}
let set = new Set([1,2,3]);
for(let x of set){
    
    
    console.log(x);
}

四、函数

4.1、定义函数

方式一:

// 定义函数一:function是关键字,abs是函数名,x是参数。
function abs(x) {
    
    
    if(x > 0)
        return x;
    else
        return -x;
}

 
方式二:

//这种有点类似与Java中的匿名内部类,function依然是参数,但没有函数名,函数值返回给abs。但我们调用是一样的。
let abs = function(x){
    
    
    if(x > 0)
        return x;
    else
        return -x;
};

 
方式一和方式二效果是一样的,一般后端都喜欢用方式一,和Java定义方法方式是相同的。

调用函数时直接正常调用

abs(10);//返回10
abs(-10);//返回-10

 
需要注意的是,在JavaScript中即便我们函数定义了参数,但我们依然可以不传入参数,或者定义了一个参数而传入多个参数,并且这两种方式都能运行下去而不报错。

abs(aa);//返回NaN,这不是一个数
abs();//返回NaN

 
这种显然是不应该发生的,我们可以在函数中进行处理:

//通过typeof关键字可以得到x的类型,若x不是数字则手动改抛出异常。
//JavaScript中关键字或者属性都需要引号
function abs(x) {
    
    
    if(typeof x !== "number"){
    
    
        throw "not a number";
    }
    if(x > 0)
        return x;
    else
        return -x;
}

可以发现,通过判断类型能解决少传或者错传参数问题,但多传入参数依然没事。这是因为JavaScript中会将参数都放入关键字arguments中。

函数问题

arguments是一个数组,会包含所有关键字。

function test(x) {
    
    
    if(typeof x !== "number"){
    
    
        throw "not a number";
    }
    for (let i = 0; i < arguments.length; i++) {
    
    
        console.log(arguments[i]);
    }
}

 
结果:

arguments

可以发现,arguments甚至包含了我们正常传入的参数1,我们希望有一个参数只包含我们多传入的参数,于是就有了ES6新特性出的 …rest。

//...rest只能放在最后,rest不是关键字,只需...标识即可,rest也是个数组,包含多余的参数。
function test(a, b, ...rest) {
    
    
    console.log("a->"+a);
    console.log("b->"+b);
    console.log(rest);
}

结果:

rest

4.2、变量作用域

在JavaScript中var、let、const定义的变量都是有作用域的。

1、如果在函数体内声明变量,在函数体外则不能调用该变量!(后面也可以通过闭包实现)

function f() {
    
    
    let a = 1;
}
console.log(a);//报错:Uncaught ReferenceError: a is not defined

 
2、若两个函数使用相同变量名,不会冲突,因为变量相互独立。

function f1() {
    
    
    let a = 1;
}
function f2() {
    
    
    let a = 1;
}

 
3、内部函数可以访问外部函数的成员,反之不行。

function f() {
    
    
    let a = 1;
    function f1() {
    
    
        let b = 2;
        console.log(a);
    }
    f1();
    console.log(b);//这里会报错
}

 
4、若内部函数和外部函数变量重名,内部函数会调用自己的变量,外部也会调用自己变量。

function f() {
    
    
    let a = 1;
    function f1() {
    
    
        let a = 2;
        console.log(a);
    }
    f1();
    console.log(a);
}
f();

结果:

2
1

 
这是因为在JavaScript中,函数查找变量是从自身函数开始,由内向外查找。这里f1的a也是独立的,不会给f的a赋值。

5、JavaScript执行引擎会自动进行声明。

function fun() {
    
    
    var x = 'x '+y;
    console.log(x);
    var y = 'y';//如果用let声明,报错 Cannot access 'y' before initialization
}
fun();//执行结果:x undefined

这说明其实JS有自动声明y变量,只是没有初始化。上面其实等价于下面代码:

function fun() {
    
    
    var y;
    var x = 'x '+y;
    console.log(x);
    y = 'y';
}

因此我们一般有个规范来避免JS自动声明:所有变量声明都放在函数头部,即便没有还给它们初始化。

6、全局变量:

只要定义在function外的变量都属于全局变量,在JavaScript中有一个默认的全局对象——window,它就代表着浏览器,我们声明的全局变量、函数都会绑定在它上面。

//alert这个方法也是属于window的
window.alert("hello");

考虑之前我们定义函数的第二种方式,其实函数也可以视为变量。那么看下面代码:

var old_alert = window.alert;//把函数alert赋值
old_alert("old_alert");
window.alert = function(){
    
    
    //这里是一个空函数赋值给window.alert,使alert原本内容被覆盖
}
//此时调用alert()失效
window.alert = old_alert;//此时alert()恢复
alert("恢复了");

由于window是唯一一个真正的全局变量,如果开发者自己定义全局变量都会默认绑定到window上,那么当多个开发者的全局变量名相同时就会造成混论。因此,我们有一个规范来减少冲突。

//定义一个唯一全局变量对象
var myApp = {
    
    };//这里是对象,用的花括号
//定义自己全局变量时绑定到这个唯一全局对象上
myApp.name = "小明";//定义属性
//定义方法
myApp.add = function(a, b){
    
    
    return a+b;
}

通过上面这种,把自己的代码全都放入到自己定义的唯一空间名字中,可以有效降低全局命名冲突问题!

7、局部作用域 let

前面说过,var现在基本被let给替换,因为存在作用域问题。

function a(){
    
    
    for(var i = 0; i < 10; i++){
    
    
        console.log(i);
    }
    //这里按理来讲是应该报错的,因为i是属于for的局部变量
	//但实际上这里没有报错,因此需要替换为let
    console.log(i);
}

8、常量const

在ES6之前没有const关键字,那时候常量由人们约定全大写就是常量。例如 var PI = “3.14”,

ES6之后用const表明是常量。

4.3、方法

1、定义:方法和函数的区别就是,方法定义是在对象里面。对象只包含两个东西:属性和方法。

let student = {
    
    
    name:"小明",
    birth:1999,
    //getFullYear()返回当前年份
    age:function () {
    
    
        let now = new Date().getFullYear();
        return now - this.birth;
    }
}
//调用
student.name;//属性
student.age();//方法

对象里属性和方法的定义都是键值对的方式,这里的对象student定义了age方法,在对象中要访问属性需要加上 this. 。

2、把上面的代码分开试试:

function getAge() {
    
    
    let now = new Date().getFullYear();
    return now - this.birth;
}
let student = {
    
    
    name:"小明",
    birth:1999,
    //getFullYear()返回当前年份
    age:getAge
}

之所以能这样,是因为能把函数视为变量(参考之前定义函数的方式二),现在相当于把函数getAge赋值给age,因此age也变为方法。现在可以通过student.age()得到年龄,但直接使用getAge()会得到NaN。

方法拆开

这是因为getAge()中的this指代问题,通过student.age()时,this指向student,所以this.birth值为1999。但我们直接使用getAge()时,因为getAge()绑定到window,而window没有属性birth,所以得到NaN。

3、我们可以通过apply关键字来改变this的指向:

function getAge() {
    
    
    let now = new Date().getFullYear();
    return now - this.birth;
}
let student = {
    
    
    name:"小明",
    birth:1999,
    //getFullYear()返回当前年份
    age:getAge
}
console.log(getAge.apply(student,[]));//this指向student,参数为空

猜你喜欢

转载自blog.csdn.net/qq_39763246/article/details/113407573
今日推荐