文章目录
JS入门
1. JS的导入方式
与CSS类似JS也有自己的导入方式。(两种)
- 内部式
<!--在head或body中直接放入script标签在其中直接写JS文件-->
<head>
<script>
function getName(){
}
</script>
</head>
- 外部文件导入式
<!--在head或body中用script标签引入JS文件-->
<head>
<script type="text/javascript" src=".js"></script>
</head>
不写script标签不写类型时,默认就是text/javascript。不管哪种导入方式,script标签在head和body中都可以使用,不像css的导入只能在head中。
2. JS调试
JS在浏览器中调试,在浏览器中按F12可以进入调试界面。
如图下图所示:
- Element:是元素调试界面,所代表的是HTML文件的调试窗口。
- Console:是控制台,可以调试、显示JS文件的执行结果。
-
- 具体调试方法:1、使用alert弹窗进行文字的显示。2、console.log()进行打印。使用这两个方法时可以直接在Console控制台中那个蓝箭头直接输入调试,不必重新修改JS代码。
- Sources:是资源控制台,在其中整个文件夹目录,可以在其中进行JS的逐步调试。它的调试方式与使用大多数编译器的调试一样,断点设置也是点击代码行数处。
3. JS语法
大家学习一门语言可以从它的使用角度来学习。比如我要写代码,我的代码中应该有哪些东西?如:变量、数据的类型、流程控制、运算符、函数(方法)等等一些在代码中可以看见的一些东西,这样就形成一个框架了。
严格检查模式
上文也说了,JS是一种非常不严格的语言,不管咋出错都不会报错。所以为了解决这一缺陷,在ES6中新增严格检查模式,不符合规则就报红。具体写法是:在代码最开头写上’use strict‘
'use strict';
var x = 12;
//这会报红因为没有声明这是一个局部变量
y = 10;
变量
变量的声明与作用域
变量有两种声明方式:
- var:与let都是声明的局部变量,但是没有let严格。具体表现在for循环中使用var定义局部变量的话在退出for循环时仍会存留for循环中的局部变量。
- let:let是ES6新特性。加强了变量的严格性。
- 在局部中直接写变量不声明:不声明变量直接写变量名,会导致变量成为局部变量。
例如:
//变量的作用域是一个相对的概念,放在全局就是全局变量,放在局部就是局部变量
//全局变量,全局变量不能用let声明
var x = 1;
function getName(){
var name = "lex";
let name1 = "alex";
//name2就是全局变量,因为没有声明var、let
name2 = "hua";
}
变量空间的申请
变量有两种申请方式:
- 使用var、let直接申请
var num = 1;
let name = "李四";
- 使用new申请变量
var name = new String("李四");
两种申请方式的区别:
- 使用前者申请的空间在栈内存中,后者申请的空间在堆内存中。
- 与Java中的内存存储类似,但是不尽相同。
关于变量的一些规范
变量的名称:
- 尽量与Java类似,使用驼峰式。(好像是)
全局变量的存放:
- 为了使在引用多个JS文件时不会使全局变量之间冲突,将你自己写的全局变量存在你自己定义的全局变量对象中。这样调用全局变量时使用不同的全局变量对象进行调用使用。
- 当你创建一个JS文件后,所有的全局变量都存在一个内置的全局变量对象window中。这也就意味着你可以从window中调用全局变量。
例如:
//注意只能用var声明全局变量,对象也算变量
var myValue = {};
myValue.name = "hhh";
myValue.age = 20;
//注意这里的age不与myValue中的age冲突,因为作用域不同。age在window对象中,myValue.age在myValue中,而myValue才在window中。
var age = 22;
这是一种规范,jQuery也是这么干的。比如:jQuery. 简化成了$( )(是等价的)。
JS的注释
JS有两种注释,与Java相同
- //
- /**/
JS数据类型
数字类型
number类型,共分为五类:整数、小数、使用科学计数法的数、NaN、Infinity。
- 整数
var x = 1;
注意:在JS中 整数 / 整数 = 浮点数,只要商的话就将结果强制类型转换一下。
- 小数
var x = 1.1;
注意JS中使用小数与Java中相同,要注意精度问题,根据问题的种类选择使用浮点数还是大数。
- 使用科学计数法的数
var x = 1e5;
- NaN空值
var x = NaN;
注意:对于控制不可以使用比较运算符进行判断。要使用isNaN()这个函数。
//错误示范
var x = NaN;
if(x === NaN){
}
//正确示范
var x = NaN;
if(isNaN(x)){
}
- Infinity无穷大
var x = Infinity;
字符串类型
字符串的声明
字符串使用单引号(‘ ’)或双引号(“ ”)来声明单行字符串,使用反引号声明多行字符串(``)
var name = 'lisi';
var sex = "man";
var p = `I am a
super man!`
注意:以上的字符串存在常量池中,是不可以改变的,要改变就new一个字符串。要声明到堆内存中则要使用new String。
反义字符
**反义字符与Java中相同。用反斜杠在前面。常用反义字符有:\n、\ ‘、\ "、\u####(使用Unicode字符集的####为四位二进制)、\x###(ASCII码的字符)**等等。
var x = "123\"xxx\n";
字符串的拼接
-
模板字符串
模板字符串用于字符变量与字符串的拼接,使用的是EL表达式。
模板字符串使用反引号 ,使用${x}拼接,如:
var age = 21; var msg = `i am ${age}`; console.log(msg);
-
使用+拼接字符串
var name = "lihua";
console.log(name+"is 11 years old");
字符串的一些方法(大部分与Java中相同)
- length(长度)
var name = "lihua";
console.log(name.length);
- substring(截取字符串)
var num = "123456789";
console.log(num.substring(0,4));
//输出1234
- charAt(获取其中index的字符)
var x = "123";
console.log(x.chatAt(1));
//2
- indexOf(获取第一次碰到字符或字符串的下标)
var x = "12345";
conlole.log(x.indexOf(2))
//1
- toUpperCase(全变大写)
var x = "aaaa";
console.log(x.toUperCase());
- toLowerCase(全变小写)
布尔类型
- true
- false
空指针类型
- null:空,是为赋值的。
- undefined:是为定义的。
数组类型
数组既是一种数据类型,也是一种容器。所以会有增删改查这些容器都具备的基本方法。
JS的数组与Java不同,因为不必声明数据类型所以可以存储不同类型的元素,并且数组的长度可变。
数组的创建
使用中括号创建数组;
//不初始化
var array = [];
//初始化的声明
var array = [1, 2, 3, 'saq', "213"];
数组的访问
直接使用下标访问,若数组越界不会终止程序,会返回一个undefined:
var x = [1,2,3,4,5];
console.log(x[2]);
数组变长
JS中的数组不像Java中的数组那么严格,长度是可以变的。
var x = [1,2,3];
x.length = 10;
//x会增加7个元素。
数组的一些重要方法
- 增删
var arr = [];
//增
//增到尾
arr.push(1);
//增到头
arr.unshift(2);
//删
//删除尾
arr.pop();
//删除头
arr.shift();
- indexOf(获取元素的下标)
var x = [1,2,3,4];
console.log(1);
//0
- slice(截取部分元素,并形成新数组返回)
var x = [1,2,3,4];
var y = x.slice(0,2);
console.log(y)
//1 2
- sort(将数组中的元素进行排序)
var x = [2,1,4,7,5];
x.sort();
//1,2,4,5,7
//排序默认升序排列,若要降序则可以自己定义一个比较器(一个函数)如:
var compare = function(obj1, obj2){
if(obj1 > obj2)
return 1;
else
return -1;
}
x.sort(compare);
- reverse(倒转数组)
var x = [1,2,3,4];
consele.log(x);
//4 3 2 1
- concat(拼接)
var x = [1,1,1];
var y = [2,2,2];
//返回一个新数组,不会修改原数组
var z = x.concat(y);
//1 1 1 2 2 2
- join(使用连接符将数组拼接成字符串)
var x = [1,2,3,4];
var y = x.join("-");
console.log(y);
//1-2-3-4
对象类型
对象的创建
对象使用大括号({})声明,内部属性名与值之间用冒号表示(:),属性之间用逗号隔开、最后一个不写逗号。如:
var obj = {
name:"lihua",
age:12,
tags:[2,3,4],
get:function(){}
}
有些像python中的字典。
也可以直接引用函数作为方法:
function get(){
return 1;
}
var obj = {
name:"lihua",
age:12,
tags:[2,3,4],
get:get
}
对象属性的访问
有两种访问方式:
- 使用dot访问与添加(当对象中没有该元素时就添加,有就是修改)
var obj = {}
//因为没有该元素,所以就是添加
obj.name = "lihua"
//因为有该元素,所以是修改
obj['name'] = "lisi";
//访问属性
console.log(obj.name);
console.log(obj['name']);
对象可以动态的删除添加键值对。
ES6新容器
这些容器都是人写的新类,不是JS内置的数据类型。可以实现增删改查功能。
Map(增删改查)
//不初始化
Map map = new Map();
//初始化,使用二维数组初始化,内部数组为键值与值
Map map = new Map([['name', "lihua"], ['age', 14]]);
//增改,若找得到则修改,找不到就进行添加。
map.set('admain', 12345);
//删
map.delete('name');
//查
map.get('age');
Set(增删查)
//不初始化
Set set = new Set();
//初始化,使用一维数组进行初始化。这里初始化时有两个1,因为是集合所以只会有一个1多余的不会初始化进去。
Set set = new Set([1,2,3,1,5])
//因为集合不是数组,它是无序的所以不需要改,直接查看删除增加即可。
//增,增加元素。
set.add(6);
//删
set.delete(1);
//查,有则返回true。
set.has(3);
iterator迭代器
这些容器内置迭代器,所以可以用for of遍历它们。
Map map = new Map([['name', "lihua"], ['age', 14], ['tags', [1,2,34]]]);
for(let x of map){
console.log(x);
//x为每个键值对的值。
}
重要关键字(非很频繁)
indexof关键字
获取数据的数据类型使用:indexof xxx(indexof是关键字)
in关键字
使用in关键字可以判断某元素是否在数组或对象中。返回布尔类型
var x = [1,2,3,4];
var y = {
name:"jjj",
age:12
}
console.log(1 in x);
//in 在对象中只能判断是否有该键值,并且键值要写成字符串
console.log('name' in y);
运算符
算数运算符
-
-
-
- /
- %
- ++
- –
逻辑运算符
- &&
- ||
- !
比较运算符
- >
- <
- ==
对于两个等号的相等,只要值相等即可,不需类型相同。
- !=
对于两个字符的相等,只要值不等即可,不需类型相同。
- >=
- <=
- ===
强相等判断,必须值和类型都相等才能判断为真。
- !==
强相等判断,必须值和类型都不等才能判断为真。
- ?
三元运算符,与各种语言中的都一样。(没学过的话看我前面Java中的)
赋值运算符
- =
- +=
- -=
- %=
- *=
- /=
位运算符
- &
- |
- ~
- ^(按位异或)
- >>
- <<
- >>>(零填充右移)
类型运算符
- typeof(返回变量的类型)
- instanceof(判断对象是否是某类或其子类的实例,与Java中相同)
流程控制
分支结构
if(x==1){
}else if(x==2){
}else{
}
switch(i){
case 1:...;break;
case 2:...;break;
case 3:...;break;
}
循环结构
while(){
}
do{
}while()
重要的for
普通for
for(int i = 0;i < 11;i++){
}
for in
for(let x in array){
//对象也可以。x为后面的下标
}
for of
for(let x of array){
//对象也可以。x为后面的值。这使用的是迭代器。
}
forEach
array.forEach(function(value){
//value是正在进行迭代的元素的值。
});
总结for:1.普通for,i为额外变量值。2.for in,变量为元素下标。3.for of,本质用的是迭代器,变量为元素的值。4.forEach,是一个函数,用在对象或数组上,参数是一个函数,函数中的参数是当前迭代的元素的值。
模块化
因为代码大多数都是共用的,为了减少代码冗余进行模块化。
函数(函数也是一种类型,可以typeof)
函数使用function声明,函数由function关键字、函数名、参数列表、函数体构成。与python相同,函数可以看成变量,是可以赋值的。
函数的声明
- 有名函数
function getName(){
retutn 1;
}
- 匿名函数
var getName = function(){
retutn 1;
}
getName();
函数的参数
- 因为JS中没有显示声明的数据类型,所以函数中参数是不用声明数据类型的,也就把var给省略了。
function getName(name, age){
return name;
}
- 实参列表对象:arguments
arguments是一个实参列表对象(实际上就是一个数组,存着实参们),每一个函数都有一个arguments。在函数体中可以使用。
为什么会有实参列表对象呢?直接用形参列表不可以吗?因为JS的不严谨性,使得实参多于或少于形参都不会报错,所以出现实参列表对象。当形参多余实参时,多余的参数是undefined
function getName(x1, x2, x3){
if(x1 != undefined && x2 != undefined && x3 != undefined){
console.log(arguments.length);
}
}
getName(1,1,1,1);
//输出4
- 可变长参数:…rest
在Java中可有可变长参数,但是Java中你可以自定义参数名,JS的可变长参数的参数名只能是rest。
实参列表对象用于确定总共有多少参数,且参数的值是啥。而可变长参数用来判断多余的、尾部的参数们是啥。
function getLength(x1, x2, x3, ...rest){
console.log("多余的参数有"+rest.length+"个");
}
类与对象
对象
对象的两种定义方式:
- 直接创建对象
var obj = {
name:"小红",
get:function(){
return this.name;
}
}
这种方式创建的对象是一次性的,不像使用类还可以多次创建同种类型的对象。
- 使用类new对象
var string = new String();
当然,这种方式也有限制。只有ES6以后的才能只用。因为类在ES6中提出的。
this指针的注意事项:
学习过多种面向对象语言就会非常熟悉this指针。在对象内this指针指向对象本身。但是在JS中全局函数中有this指针也是可以的。因为全局变量存在window对象中(函数也是一个变量)。所以全局函数中的this指针指向window对象。
例如:
var x = 3;
var getX = function(){
return this.x;
}
var value = {
x:1,
get:getX
}
value.get();//输出1
getX();//输出3,相当于window.getX(),全局变量中也有一个x变量3
类
封装:
类是ES6的新特性,使用方法与Java类似,只不过构造函数写法不同。
例如:
class Test{
let x1;
let x2;
//构造函数
constructor(x1, x2){
this.x1 = x1;
this.x2 = x2;
}
}
var test = new Test(1, 2);
继承:
JS的继承与Java相同,使用extends关键字进行继承。在子类的构造函数中构造父类使用super( )。
例如:
class Test{
let x1;
let x2;
//构造函数
constructor(x1, x2){
this.x1 = x1;
this.x2 = x2;
}
}
class TwoTest extends Test{
constructor(x1, x2){
super(x1, x2);
console.log("I'am TwoTest");
}
}
对于继承而言,与Java不同的是:Java的继承形成的是继承树,但是JS的继承形成的是一个链。在浏览器的元素审查列表可以看见JS的父类是点不完的,而且有套娃的现象。
在ES6之前,对于继承这个操作,JS使用的是一种叫原型的东西。也就是定义了一个对象,另一个对象与它相似,那么就以前者为原型进行重构。__proto__可以查看原型。
多态:
在JS中因为没有明确声明数据类型的变量,所以对于像Java中父类引用指向子类对象这一多态操作是行不通的。在JS中使用了apply函数进行多态,每个函数都有这个函数。(也就是可以调用apply函数。有人可能会问为什么函数还能调用函数?不要忘记之间说过的在JS中函数也是变量,如果学过python肯定对这个概念有深刻体会。)
使用方法:function_x.apply(obj, [ ])。
- function_x是要进行多态的函数,也就是对于多个对象使用这个函数会有不同的行为。
- obj是指向对象,本质上是改变this指针的指向。
- [ ],这个数组是参数列表。如果function_x无参直接用一个空数组[]即可,有参数组中添加参数即可,例如:[x1, x2]
class One{
function print(){
console.log("I'am One");
}
}
class Two{
function print(){
console.log("I'am Two");
}
}
var one = new One();
var two = new Two();
var list = [one, two];
for(let x of list){
print.apply(x, []);
}
/*
输出:
I'am One
I'am Two
*/
class TwoTest extends Test{
constructor(x1, x2){
super(x1, x2);
console.log(“I’am TwoTest”);
}
}
**对于继承而言,与Java不同的是:Java的继承形成的是继承树,但是JS的继承形成的是一个链。在浏览器的元素审查列表可以看见JS的父类是点不完的,而且有套娃的现象。**
**在ES6之前,对于继承这个操作,JS使用的是一种叫原型的东西。也就是定义了一个对象,另一个对象与它相似,那么就以前者为原型进行重构。__proto__可以查看原型。**
**多态:**
在JS中因为没有明确声明数据类型的变量,所以对于像Java中父类引用指向子类对象这一多态操作是行不通的。在JS中使用了apply函数进行多态,每个函数都有这个函数。(也就是可以调用apply函数。有人可能会问为什么函数还能调用函数?**不要忘记之间说过的在JS中函数也是变量,如果学过python肯定对这个概念有深刻体会。**)
**使用方法:function_x.apply(obj, [ ])。**
* function_x是要进行多态的函数,也就是对于多个对象使用这个函数会有不同的行为。
* obj是指向对象,本质上是改变this指针的指向。
* [ ],这个数组是参数列表。如果function_x无参直接用一个空数组[]即可,有参数组中添加参数即可,例如:[x1, x2]
```javascript
class One{
function print(){
console.log("I'am One");
}
}
class Two{
function print(){
console.log("I'am Two");
}
}
var one = new One();
var two = new Two();
var list = [one, two];
for(let x of list){
print.apply(x, []);
}
/*
输出:
I'am One
I'am Two
*/