目录
一、JS 的简介
1. JS 概念
JavaScript 是一种具有面向对象能力的、解释型的程序设计语言。
2. 组成
(1)ECMAScript( 基础 语法)
JavaScript 的核心语法 ECMAScript 描述了该语言的语法和基本对象。
(2)DOM( 文档对象模型)
文档对象模型(DOM)—— 描述了处理网页内容的方法和接口。
(3)BOM( 浏览器对象模型)
浏览器对象模型(BOM)—— 描述了与浏览器进行交互的方法和接口。
3. JS的使用方式
3.1 行内样式
直接在body中的元素中使用js代码。
<body>
<button onclick="alert('你怎么那么好看')">按钮</button>
</body>
3.2 嵌入式
在页面中其他任意位置通过 script 标签来定义。
<body>
</body>
<script>
alert("哈哈");
</script>
3.3 引入式
在 head 标签或其他位置通过外部引入JS文件,这种方式在日常开发中常用,使结构、样式、行为相分离。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="test.js"></script>
</head>
二、JS基本语法
1. 变量
(1)变量的声明和赋值
JavaScript 是一种弱类型语言,在声明变量时不需要指明数据类型,直接用 var 修饰符进行声明。
// 先声明再赋值
var a ;
a = 5;
// 声明同时赋值
var b = 15;
(2)变量的规范
1)若变量只声明而没有赋值,则该变量的值为 undefined。
var a ;
2)变量要有定义才能使用,若变量未声明就使用,JavaScript 会报错。
b = 10;
3)在同一条 var 命令中声明多个变量,只有最后一个才有赋值。
//这里只有c=10, 其他为undifined
var a, b, c = 10;
4)若使用 var 重新声明一个已经存在的变量但并未赋值,是无效的;若使用 var 重新声明一个已经存在的变量并且赋值,则会覆盖掉前面的值。
var a = 10
var a //这里声明的 a 无效
var a = 20 //这里的 a 会覆盖上面第一行的 a
(3)变量提升
JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升。
console.log(a);
var a = “so easy”;
//变量提升,相当于下面的代码
var a;
console.log(a);
a = “so easy”;
//说明:最后的结果是显示 undefined,表示变量 a 已声明,但还未赋值。
注意:变量提升只对 var 命令声明的变量有效,如果一个变量不是用 var 命令声明的,就不会发生变量提升。
2. 数据类型
JavaScript 中有 6 种数据类型,其中有五种简单的数据类型:Undefined、Null、 布尔、数值和 字符串。一种复杂数据类型 Object
- 数 值(Number ): 整数和小数(比如 1 和 3.14)
- 字符串(String ): 字符组成的文本(比如"Hello World")
- 布尔值(Boolean ):true(真)和 false(假)两个特定值
- Undefined: 表示“未定义”或不存在,即此处目前没有任何值
- Null: 表示空缺,即此处应该有一个值,但目前为空
- 对象(object )( 引用) : 各种值组成的集合
- 1)、对象(object){name:”zhangsan”,age:”18”}
- 2)、数组(array)[1,2,3]
- 3)、函数(function)function test() {}
3. 数据类型
typeof 操作符是用来检测 数据类型。对于值或变量使用 typeof 操作符会返回如下字符串。
说明:
- typeof null 返回的是 object 字符串。
- 函数不是数据类型,但是也可以使用 typeof 操作符返回字符串。
- typeof 操作符可以操作变量也可以操作字面量。
注意:函数在 JavaScript 中是对象,不是数据类型,所以使用 typeof 区分 function 和object 是有必要的。
4. 数据类型转换
JS 数据类型转方法主要有两种:显示类型转换和隐式类型转换。
(1)显示类型转换
A. 转数字
1)Number转换
var a = “123”;
a = Number(a);
注意:
a) 如果转换的内容本身就是一个数值类型的字符串,那么将来在转换的时候会返回自己。
b) 如果转换的内容本身不是一个数值类型的字符串,那么在转换的时候结果是NaN.
c) 如果要转换的内容是空的字符串,那以转换的结果是0.
d) 如果是其它的字符,那么将来在转换的时候结果是NaN.
2)parseInt():
var a = “123”; a = parseInt(a);
a) 忽略字符串前面的空格,直至找到第一个非空字符,还会将数字后面的非数字的字符串去掉。
b) 如果第一个字符不是数字符号或者负号,返回NaN
c) 会将小数取整。(向下取整)
3)parseFloat();//浮点数(小数)
与parseInt一样,唯一区别是parseFloat可以保留小数。
B. 转字符串
可以将其它的数据类型转成字符串。
1)String()
var a = 123;
a = String(a);
2)toString()的方法来进行转换(包装类)。
var a = 123; a = a.toString();
undefined,null不能用toString。
C. 转boolean类型
可以将其它类型转为boolean值:
Boolean()
var a =”true”; a = Boolean(a);
注意:
在进行boolean转换的时候所有的内容在转换以后结果都是true,除了:false、""(空字符串)、0、NaN、undefined
(2)隐式类型转换(强制类型转换)
- Boolean(value) - 把给定的值转换成 Boolean 型;
- Number(value) - 把给定的值转换成数字(可以是整数或浮点数);
- String(value) - 把给定的值转换成字符串;
A. 转 number
加减乘除以及最余都可以让字符串隐式转换成number
var a = “123”;
a = +a;
B. 转string
var a = 123;
a = a + "" ;
C. 转boolean
var a = 123;
a = !!a ;
4. 运算符
javaScript 的运算符同 Java 基本相同,这里不做详细阐述。
5. 控制语句
javaScript 的空控制语句同 Java 基本相同。
(1)选择语句
主要分为单选(if条件语句)、双选(if else 条件语句)、多选(if else ... if else ... else),还有一个switch 机构。
(2)循环
for 循环、while循环、do ... while循环
注意:
break 与 continue
break:停止本层循环。
continue:暂停本次循环,继续下一次。
6. 数组
JavaScript 中的数组与 Java 的数据用法雷同,不同的是 JS 中的数组长度不定长,数组中的元素也不再仅限于同种数据类型,在 JS 中一个数组中的元素可以是任意类型。
(1)JS 数组的定义方式
var arr=[值 1,值 2,值 3]; //隐式创建
var arr=new Array(值 1,值 2,值 3); //直接实例化
var array=new Array(size); //创建数组并指定长度
(2)JS 数组的遍历方式(三种)
1)普通 for 循环:正常元素(无论是否有值)
for(var i=0; i<=数组.length-1; i++){
}
var arr = [1,2,3];
arr[10] = '10';
arr['a'] = 'a';
arr[-1] = '-1';
// 普通for循环 :正常元素(无论是否有值)
for(var i=0; i<arr.length; i++){
console.log(arr[i]);
}
2)for…in:所有有值的元素(正常和非正常)
for(var 下标(名称任意) in 数组名){
数组名[下标]是获取元素
} //下标(名称任意)
// for...in : 所有有值的元素(正常和非正常)
for(var idx in arr){
console.log(arr[idx]);
}
3)forEach()方法:元素正常且有值
数组名.forEach(function(element,index){
}) // element(名称任意):元素,index(名称任意):下标
// forEach:正常且有值
arr.forEach(function(e,i){
console.log(e + "==" + i);
});
注意:
如果没有索引的元素,推荐使用forEach方法。
(3)JS 中数组的常用方法
push 添加元素到最后
unshift 添加元素到最前
pop 删除最后一项
shift 删除第一项
reverse 数组翻转
join 数组转成字符串
indexOf 数组元素索引
slice 截取(切片)数组,原数组不发生变化
splice 剪接数组,原数组变化,可以实现前后删除效果
concat 数组合并
三、JS 函数
1. 函数的定义
在 JS 中函数定义的方式有三种:函数声明语句、函数定义表达式、Function 构造函数。
(1)函数声明语句
function test ( 形参列表 ) { 函数体 }
function test(){
console.log(1);
}
test();
// 变量声明提升
console.log( a );
var a = 2;
(2)函数定义表达式
以表达式方式定义的函数,函数的名称是可以不需要的。
1)命名函数表达式
var 变量名 = function 函数名 ( 参数列表 ) { 函数体 }
var test = function abc(){
console.log('a');
}
console.log(test.name); // 函数名为abc
console.log(test); //输出的是名为abc的函数体
console.log(abc); //这里会报错,表达式会忽略abc这个名字,变成匿名函数表达式
2)匿名函数表达式
由于在命名函数表达式中函数的名字会被忽略,所以一般我们使用匿名函数表达式。
var 变量名 = function ( 参数列表 ) { 函数体 }
var test = function(){
console.log('a');
}
(3)new Function 构造函数
Function 构造函数接收任意数量的参数,但最后一个参数始终都被看成是函数体,而前面的参数则列举出了新函数的参数。
var add = new Function('x','y','return (x + y)');
// 等同于
function add(x, y) {return (x + y);}
add()
注意:
- js 中的函数没有重载,同名的函数,会被后面的函数覆盖。
- js 中允许有不定数目的参数,后面介绍 arguments 对象。
2. 函数声明的提升
JavaScript 引擎将函数名视同变量名,所以采用 function 命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。
();//先调用
function f() {}//后声明
注意:函数声明的提升只限于函数声明语句,表达式不行。
f(); //这里会报错
var f = function (){};// TypeError: undefined is not a function
3. 函数的参数、调用和 return
(1)参数
函数运行的时候,有的时候需要提供外部数据,这种外部数据就叫参数,定义时的参数称为形参,调用时的参数称为实参。
- 实参可以省略,那么对应形参为 undefined
- 若函数形参同名(一般不会这么干):在使用时以最后一个值为准。
- 可以给参数默认值:当参数为特殊值时,可以赋予默认值。
- 参数为值传递,传递副本 ;引用传递时传递地址,操作的是同一个对象。
//调用函数时,实参可以省略,则对应形参为 undefined
function test(a , b) {
console.log(a + "+" + b + "=" + (a + b));
}
test(3,4,5) //3 + 4 = 7
test(1); //1 + undefined = NaN
test(); //undefined + undefined = NaN
//若函数形参同名:在使用时以最后一个值为准
function test2(a , a) {
console.log(a); //值为2
}
test2(1,2);
//给参数默认值
function defaultValue(a){
a = a || "a";
return a;
}
console.log(defaultValue());
function f(a){
//若参数 a 不为 undefined 或 null,则取本身的值,否则给一个默认值
(a !== undefined && a !== null) ? a = a : a = 1;
return a;
}
console.log(f());
//值传递
var num = 12;
function change(n) {
n = 30;
}
change(num);
console.log(num);//值为12
//引用传递
var obj = {name: "tom"};
function paramter(o) {
o.name = 2;
}
paramter(obj);
console.log(obj.name); //值为2
//给形参 o 赋予了新的数组
var obj2 = [1, 2, 3];
function paramter2(o){
o = [2, 3, 4];
o[1] = 3;
}
paramter2 (obj2);
console.log(obj2) //结果为[1,2,3]
(2)函数的调用
常用调用方式: 函数名([ 实参]);存在返回值可以变量接收,若接收无返回值函数则为 undefined。
JS 其他调用方式:函数调用模式、方法调用模式、间接调用模式
1)函数调用模式
function add(a,b){
return a+b;
}
var sum = add(1,2)
console.log(sum)
2)方法调用模式
var o = {
m: function(){
console.log(1);
}
};
o.m();
3)间接调用模式
- JS 中函数也是对象,函数对象也可以包含方法。
- call()和 apply()方法可以用来间接地调用函数。
- 任何函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。
- call()方法使用它自有的实参列表作为函数的实参,apply()方法则要求以数组的形式传入参数。
var obj = {};
function sum(a,b){
return a+b;
}
console.log(sum.call(obj,3,2))
console.log(sum.apply(obj,[3,2])
4)匿名函数的调用
匿名函数:指没有函数名的函数,function ( 参数 ){ }
匿名函数的调用:也叫立即执行函数,写法有两种:
(function(){ ... })()
(function(){ ... }()) //建议采用这一种,外面的括号相当于一个运算符,会起到函数定以后立即执行的效果。
注意:要在函数体后面加括号就能立即调用,则这个函数必须是函数表达式,不能是函数声明。
关于立即执行函数的详细讲解请见友情链接:https://blog.csdn.net/csdn_yudong/article/details/77431106
(3)teturn 语句
函数的执行可能会有返回值,需要使用 return 语句将结果返回。return 语句不是必需的,如果没有的话,该函数就不返回任何值,或者说返回 undefined。
作用:
- 在没有返回值的方法中,用来结束方法。
- 有返回值的方法中,一个是用来结束方法,一个是将值带给调用者。
4. arguments 对象和函数的方法及属性
arguments 对象中存放了调用该函数时传递的实际参数,函数中可以使用 arguments 对象来获取实参。
function test(a, b, c){
var len = arguments.length;
console.log(len)
for(var i=0; i<len; i++){
console.log(arguments[i]);
}
}
test(1,20); //结果为1和20,利用实参列表arguments来遍历实参
函数本身也是对象,也有一些属性和方法。
- 函数名.name 函数名称
- 函数名.length 形参的个数
- 函数名.toString() 返回函数的源码
5. 函数的作用域
函数作用域:全局(global variable)和局部(local variable)。
(1)全局变量与局部变量同名问题
var box =1; //全局变量
function display(box){
var box=3; //此处 box 与全局变量 box 没有关系,这里的 box 为传递的参数,相当于新声明的局部变量
var b = 2; //局部变量
console.log("box-->"+box); //值为3
}
display();
//b 不能访问
console.log("b-->"+b);
(2)在函数中定义变量时,若没有加 var 关键字,使用之后自动变为全局变量
function fun(){
a = 100; //由于没有加 var 关键字,a = 100在调用后自动变成全局变量
}
fun();
alert(a); //所以这里可以访问到a = 100
(3)变量作用域提升
function foo(x) {
if (x > 100) {
var tmp = x - 100;
}
}
//等同于
function foo(x) {
var tmp;
if (x > 100) {
tmp = x - 100;
};
}
6. 闭包
(1)闭包的概念
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露。
这里的内存泄漏就是内存占用,内存被占用的越多,内存就变得越来越少了,就像内存被泄露了一样。
注意:闭包必须要有关键字 return ,只有把结果返回出去,外部才能调用。
(2)闭包的作用
1)实现公有变量(使局部变量在外部也能被访问)
function(){
var count = 0;
function demo(){
count ++;
console.log(count);
}
return demo;
}
var counter = add();
counter(); //值为1
counter(); //值为2
counter(); //值为3
2)可以做缓存(储存结构,使变量的值始终保持在内存中)
function test(){
var num = 100;
function a(){
num ++;
console.log(num); //101
}
function b(){
num --;
console.log(num); 100
}
return [a,b];
}
var myArr = test();
myArr[0](); //值为101
myArr[1](); //值为100
3)可以实现封装,属性私有化
4)模块化开发,防止污染全局变量
这里比较大的一个好处就是在日常开发工作中,特别是大型项目,利用闭包可以有效的防止同名变量的相互影响。