提示:以下代码均是在node环境下运行
什么是Javascript
在前端三大剑客中,js是最重要的一门语言,是一门轻量级脚本语言,使用户能够与网页、浏览器进行交互。
js组成部分
- ECMAScript(js标准、制定了基础语法)
- DOM(文档对象模型,与网页进行交互)
- BOM(浏览器对象模型,与浏览器进行交互)
js运行环境
- 含有js解析器的浏览器中
- node.js环境中
js语言特点
- 解释型语言
- 弱类型语言
- js代码从上至下顺序执行
- 区分大小写
使用方式
- 写在head标签中,引用外部js文件
- 写在body所有html代码后面,使用
script
标签
区别:
①代码是从上至下顺序执行的,当执行到head标签中的js文件时,此时html结构并未执行完,js中的值会返回空值;
②在body后面执行js代码:这时已经执行完html结构,js中的值不会为空;
解决办法:
在js外部文件中:在所有js代码外边添加监听,表示当页面加载完之后再执行js代码
windows.onload = function(){
// 这里放执行的代码
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 原生项目的开发模式 -->
<!-- 引入css -->
<!-- 引入js -->
<script src="./01-main.js"></script>
<!-- head标签内 编写或引入js代码 -->
<script>
// 编写js代码
console.log(this);
</script>
</head>
<body>
<div></div>
<!-- body标签内 编写或引入js代码 -->
<script>
// 编写js代码
alert('Hello JS2')
</script>
</body>
</html>
js注释
//
/* */
标识符规范
- 以字母、数字、下划线和美元符号
$
组成 - 不能以数字开头
变量
声明变量
使用var
关键字声明变量,变量的类型在赋值结束时决定,可以进行多次声明赋值
//使用var声明变量并赋值
//声明变量的名称
var a;
//给变量赋值 变量的数据类型与赋值的类型决定
a = 3;
console.log(a);//3
var声明提前
console.log(a);//undefined
var a = 123
console.log(a);//123
代码实际如下:即为变量声明提前
var a; //声明提前
console.log(a);//undefined
a = 123
console.log(a);//123
数据类型
基本数据类型(简单数据类型)
String(字符串)
通过单引号或者双引号包裹的字符即为字符串
字符串的字符长度可以通过属性length获取
var str1 = '123'
var str2 = "hello"
Number(数字)
var num1 = 12
var num2 = 23.45
var num2 = 010;//8
var num3 = 0x10;//16
Boolean(布尔型)
只有两种值:true、false
var real = true
var fake = false
null
var a = null
undefined
声明但未赋值,值就是undefined
var a
symbol
var s = Symbol('我是独一无二的symbol')
引用数据类型(复杂数据类型)
Object(对象)
,用来保存多个数据的容器,由大括号包裹键值对组成
var obj = {
name:'spylent',
age:20
}
Array(数组)
数组是一个特殊的对象,包含了多个值,值与值之间使用逗号分隔开,所有的值通过中括号括起来。
值可以是任意类型
var arr =[1,2,'string',[12,2],true]
Function(函数)
函数中包含多条代码,通过()
执行函数实现功能
function fun(){
console.log("我是一个函数")
}
fun()
基本数据类型与引用数据类型在内存的存储
undefined和null的关系
- undefined派生于null
console.log(undefined == null)//true
// ==:等同的意思, 两边值类型不同的时候,要先进行类型转换为同一类型后,再比较值是否相等。
- undefined指声明但未赋值
- null指声明且赋值为null,表示空对象
类型判断
typeof
使用typeof判断数据类型:返回值是字符串
typeof能够准确判断 string、number、boolean、undefined、symbol、function
不能准确判断 null和Object、array和Object
typeof 123 //'number'
typeof 'str' //'string'
typeof true//'boolean'
typeof Symbol() //'symbol'
var a
typeof a//'undefined'
var fun = function(){}
typeof fun //'function'
typeof null //Object
typeof [] //Object
不能准确判断原因:
因为javascript历史遗留问题,js中判断类型是以二进制前三位数以此判断是什么类型,null、array的前三位二进制数与Object前三位二进制数都一致,所以不能准确判断;
isNaN
判断是否不是一个数字
var b = 10/'a'
console.log(isNaN(b))//true 不是一个数字
isFinite
判断是否是一个有效值
由于内存的限制,ECMAScript不能保存世界上所有的数值。果某次计算的结果超过了JavaScript数值范围,将会返回Infinity(正无穷)或者-Infinity(负无穷);
var a = 9/0; // Infinity
Number.MIN_VALUE 5e-324
Number.MAX_VALUE 1.7976931348623157e+308
操作符
算数运算符
进行数据运算时,除'+'外,其他运算符可以自动将字符串数字隐形转成数字
var num1 = 2
var num2 = 8
console.log(num1 + num2)//10
console.log(num1 - num2)//-6
console.log(num1 * num2)//16
console.log(num1 / num2)//0.25
console.log(num1 % num2)//2
var num3 = '6'
var num4 = '2'
console.log(num3 + num4)//62
console.log(num3 - num4)//4
console.log(num3 * num4)//12
console.log(num3 / num4)//3
console.log(num3 % num4)//0
一元运算符
//可以将数字字符串或布尔类型等隐式转换成number类型
console.log(+'89', typeof +'89')//89 number
//与字符串运算时,就是字符串连接符
console.log('a' + 2, typeof 'a' + 2)//a2 string2
//正、负号可以将字符串数字隐式转换成数字
console.log(-'100', typeof -'100')//-100 number
if (!a) {
var a = 10
//++放在后面,并进行赋值:先赋值,后累加
let num = a++
console.log("num = " + num + ", a = " + a)//num = 10, a = 11
//++放在前面,并进行赋值:先累加,后赋值
num = ++a
console.log("num = " + num + ", a = " + a)//num = 12, a = 12
//--放在后面,并进行赋值:先赋值,后累减
let sub = a--
console.log("num = " + sub + ", a = " + a)//num = 12, a = 11
//--放在前面,并进行赋值:先累减,后赋值
sub = --a
console.log("num = " + sub + ", a = " + a)//num = 10, a = 10
}
var obj = {
name: '张三',
age: 18
}
console.log(obj)//{ name: '张三', age: 18 }
//删除数组或对象中特定索引的值
delete obj.age
console.log(obj)//{ name: '张三' }
var arr = [1, 3, 4, 52, "a"]
console.log(arr)//[ 1, 3, 4, 52, 'a' ]
delete arr[3]
console.log(arr, arr.length, arr[3])//[ 1, 3, 4, <1 empty item>, 'a' ] 5 undefined
var b = 333
console.log(void b)//undefined
赋值运算符
var a = 5;
var num1 = 5;
var num2 = 6;
console.log(num1 += num2, num1, num2);//11 11 6
console.log(num1 -= num2, num1, num2);//5 5 6
console.log(num1 *= num2, num1, num2);//30 30 6
console.log(num1 /= num2, num1, num2);//5 5 6
console.log(num1 %= num2, num1, num2);//5 5 6
比较运算符
var b = '5'
//两边值类型不同的时候,要先进行类型转换为同一类型后,再比较值是否相等
console.log(a == b)//true
//不做类型转换,类型不同的结果一定不等
console.log(a === b)//false
console.log(a != b)//false
console.log(a !== b)//true
console.log(a > b)//false
var c = 'a3'
console.log('b' > c)//true
console.log('12345' > '11456');//unicode比较 true
console.log('12345' > +'11456');//数值比较 true
var obj = { a: 1 }
var obj1 = obj
console.log(obj1 == obj)//true
console.log(obj1 === obj)//true
console.log(obj == '[object Object]')//true
console.log(obj === '[object Object]')//false
相等和全等的注意点
- 对于基本数据类型:双等和全等是有区别的
- 对于引用数据类型:双等和全等是没有区别的,只进行“指针地址”比较
- 当引用数据类型和基本数据类型使用相等时,引用数据类型先转换为基本数据类型,再进行值的比较
逻辑运算符
//同真才真,有假则假
console.log(123 && 345)//345
console.log(undefined && 123)//undefined
console.log('' && 8)//''
console.log(123 && false)//false
//有真才真,同假则假
console.log(123 || 345)//123
console.log(undefined || 123)//123
console.log('' || 8)//8
console.log(123 || false)//123
console.log("" || 0)//0
var a
console.log(!a)//true
console.log(!0)//true
console.log(!'')//true
console.log(!1)//false
三目运算符
//基本语法为: expression ? sentence1 : sentence2
//当expression的值为真时执行sentence1,否则执行 sentence2
var a;
1 > 2 ? a = 3 : a = 5
console.log(a)//5
类型转换
其他基本数据类型转字符串
注:除了null,undefined,其他三种基本数据类型的变量均有一个toString()函数
var a = true;
var b = 123;
var c = Symbol('123')
console.log(a.toString(), b.toString(), c.toString());
//true 123 Symbol(123)
console.log(typeof a.toString(), typeof b.toString(), typeof c.toString());
//string string string
// var d;
// var e = null
// console.log(d.toString()) //Cannot read property 'toString' of undefined
// console.log(e.toString()) //Cannot read property 'toString' of null
console.log("**********进制")
var num = 10;
console.log(num.toString());//10
console.log(num.toString(2))//1010
console.log(num.toString(8))//12
console.log(num.toString(16))//a
其他基本数据类型转数字
Number()
console.log(Number(true))//1
console.log(Number(false))//0
console.log(Number(null))//0
console.log(Number(undefined))//NaN
console.log(Number(10))//10
console.log(Number("+12.1"))//12.1
console.log(Number("1+2.3"))//NaN
console.log(Number("0xa"))//10
console.log(Number("010"))//10
console.log(Number("123ac"))//NaN
parseInt()函数
如果转换的值是null,undefined,boolean,均转换为NaN
console.log(parseInt("+12.1"))//12
console.log(parseInt("1+2.3"))//1
console.log(parseInt("0xa"))//10
console.log(parseInt("010"))//10
console.log(parseInt(''))//NaN
console.log(parseInt("123ac"))//123
parseFloat()函数
如果转换的值是null,undefined,boolean,均转换为NaN
console.log(parseFloat("+12.1"))//12.1
console.log(parseFloat("1+2.3"))//1
console.log(parseFloat("0xa"))//0
console.log(parseFloat("010"))//10
console.log(parseFloat(''))//NaN
console.log(parseFloat("123.3ac"))//123.3
其他基本数据类型转布尔
转换任意其他数据类型都可以转换为布尔类型
Boolean()
console.log(Boolean('hello'))//true
console.log(Boolean(0))//false
console.log(Boolean(null))//false
console.log(Boolean(undefined))//false
console.log(Boolean({ name: 'cym' }))//true
console.log(Boolean(Symbol('123')))//true
console.log(Boolean([]))//true
var fun = function () { }
console.log(Boolean(fun))//true
!!
console.log(!!undefined)//false
console.log(!!null)//false
console.log(!!'')//false
console.log(!!123)//true
console.log(!!Symbol())//true
console.log(!!{})//true
console.log(!![1, 2, 3])//true
var fun1 = function () { console.log("aa") }
console.log(!!fun1)//true
基本数据类型隐式转换
1.字符串加数字,数字就会转成字符串。数字加数字或字符串加字符串不需要转换。
在加法的过程中,首先把等号左右两边进行了求原值ToPrimitive()操作,如果有两个或多个原始值,只要其中有一个是String类型,就把两个或多个原始值都进行转化字符串toString()操作,进行字符串拼接;否则把两个或多个原始值都进行转化数字toNumber()操作,进行数字相加。
2.数字减字符串,字符串转成数字。如果字符串不是纯数字就会转成NaN。字符串减数字也一样。两个字符串相减也先转成数字。
3.乘,除,大于,小于跟减的转换也是一样。
var a = 1 + 2 + '3'
var b = 2 + '100a'
var c = 3 + 'a'
console.log("a = " + a, typeof a)//a = 33 string
console.log("b = " + b, typeof b)//b = 2100a string
console.log("c = " + c, typeof c)//c = 3a string
var d = 10 - '100'
var e = 2 - 'a'
var f = 3 - '100a'
console.log("d = " + d, typeof d)//d = -90 number
console.log("e = " + e, typeof e)//e = NaN number
console.log("f = " + f, typeof f)//f = NaN number
var g = 10 / '100'
var h = 8 / 'a'
var i = 3 % '100a'
console.log("g = " + g, typeof g)//g = 0.1 number
console.log("h = " + h, typeof h)//h = NaN number
console.log("i = " + i, typeof i)//i = NaN number
console.log("1=='1':", 1 == '1')//1=='1': true
console.log("undefined==null:", undefined == null)//undefined==null: true
console.log("0==false:", 0 == false)//0==false: true
console.log("'0'==false:", '0' == false)//'0'==false: true
console.log("''==false:", '' == false)//''==false: true
引用数据类型隐式转换
-
通过ToPrimitive将值转换为原始值
原始值:字符串、数字
js引擎内部的抽象操作ToPrimitive有着这样的签名:
ToPrimitive(input, PreferredType?)
input是输入的值,即要转换的对象,必选;
preferedType是期望转换的基本类型,他可以是字符串,也可以是数字。选填,默认为number;
他只是一个转换标志,转化后的结果并不一定是这个参数值的类型,但是转换结果一定是一个原始值(或者报错)。
对于Date求原始值比较特殊,PreferredType是String,其他Object对象均为Number。
既然要隐式转换,就应该有一套转换规则,才能追踪最终转换成了什么
隐式转换中主要涉及到三种转换:
1、将值转为原始值,ToPrimitive()。
2、将值转为数字,ToNumber()。
3、将值转为字符串,ToString()。
PreferredType转换策略:每一个步骤都要依赖上一个步骤的结果
1、如果输入的值已经是一个原始值,则直接返回它
2、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,
如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
3、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
4、否则,抛出TypeError异常。
1、如果输入的值已经是一个原始值,则直接返回它
2、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
3、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,
如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
4、否则,抛出TypeError异常。
注意:
PreferredType的值会按照这样的规则来自动设置:
1、该对象为Date类型,则PreferredType被设置为String
2、否则,PreferredType被设置为Number
特殊情况1:
[] + [] // ""
进行ToPrimitive,两个都是Array对象,不是Date对象,所以以Number为转换标准,所以先调用valueOf(),结果还是[ ],不是原始值,所以继续调用toString(),结果是“”(空字符串)原始值,将“”返回。第二个[ ]过程是相同的,返回“”。加号两边结果都是String类型,所以进行字符串拼接,结果是“”。
特殊情况2:
[] + {} // "[object Object]"
进行ToPrimitive,依然是以Number为转换标准。
[ ]的结果是“”。
{ }先调用valueOf(),结果是{ },不是原始值,所以继续调用toString(),结果是“[object Object]”,是原始值,将“[object Object]”返回。
加号两边结果都是String类型,所以进行字符串拼接,结果是“[object Object]”。
特殊情况3:
{} + [] // 0
这道题按照上一题的步骤,讲道理的话,结果应该还是“[object Object]”,但结果却出人意料——显示的答案是0!
这是什么原因呢?js解释器会将开头的 {}
看作一个代码块,而不是一个js对象;原来{ } + [ ]被解析成了{ };+[ ],前面是一个空代码块被略过,剩下+[ ]就成了一元运算。[ ]的原值是””, 将””转化成Number结果是0
特殊情况4:
{} + {} // "[object Object][object Object]"
在金丝雀版本的chrome浏览器和node中,结果符合预期。
结果是”object Object”。
在普通版本的chrome浏览器中结果是NaN。
这是为什么呢?原因是在node中会将以“{”开始,“}”结束的语句外面包裹一层( ),就变成了({ } + { }),结果就符合预期。而普通版本的chrome依然会解析成{};+{},结果就变成了NaN
console.log({}.valueOf(), typeof {}.valueOf());//{} object
console.log({}.toString(), typeof {}.toString());//'[object Object]' string
console.log([].valueOf(), typeof [].valueOf());//[] object
console.log([].toString(), typeof [].toString());//'' string
var a = {} + {}
var b = [] + []
var c = [] + {}
console.log(a, typeof a)//[object Object][object Object] string
console.log(b, typeof b)// string
console.log(c, typeof c)//[object Object] string
流程控制
if-else
- if 语句 - 只有当指定条件为 true 时,使用该语句来执行代码
- if…else 语句 - 当条件为 true 时执行代码,当条件为 false 时执行其他代码
- if…else if…else 语句- 使用该语句来选择多个代码块之一来执行
function exchange (num) {
if (num && typeof num == 'number') {
//typeof num=='number' && 0<num and num<=10
if (num > 0 && num <= 10) {
if (num == 1) {
result = "壹";
} else if (num == 2) {
result = "贰";
} else if (num == 3) {
result = "叁";
} else if (num == 4) {
result = "肆";
} else if (num == 5) {
result = "伍";
} else if (num == 6) {
result = "陆";
} else if (num == 7) {
result = "柒";
} else if (num == 8) {
result = "捌";
} else if (num == 9) {
result = "玖";
} else {
result = "拾";
}
} else if (num > 10) {
result = "请输入不大于10的数字";
} else {
result = "请输入不小于0的数字";
}
} else if (num == 0) {
result = "零";
} else {
result = "请输入数字";
}
console.log(result);
}
exchange(0);//零
exchange(-120);//请输入不小于0的数字
exchange(100);//请输入不大于10的数字
exchange('as');//请输入数字
exchange();//请输入数字
switch
首先设置表达式 n(通常是一个变量)。随后表达式的值会与结构中的每个 case 的值做比较。如果存在匹配,则与该 case 关联的代码块会被执行。请使用 break 来阻止代码自动地向下一个 case 运行
var day = new Date().getDay();
switch (day) {
case 4:
console.log("今天是星期四");
case 5:
console.log("今天是星期五");
default:
console.log("期待周末")
}
default 关键词来规定匹配不存在时做的事情;
case代码块中break不能省略;
default可以放到代码任意位置,break不能省略;最后位置可以省略break;
循环语句
关键字:break
如果想在所有迭代前退出,即可使用break。当执行break后,会立即跳出循环体。
关键字:continue
continue不会跳出循环。而是立即结束当前循环,进入下一次循环。
For 循环
for (*语句 1*; *语句 2*; *语句 3*)
{
*被执行的代码块*
}
for (var i=0; i<5; i++)
{
console.log(i);
}
while 循环
while (*条件*)
{
*需要执行的代码*
}
while (i<5)
{
console.log(i);
i++;
}
do/while 循环
var result = 0;
var i = 1;
do{
result += i;
i++;
} while(i<=100);
console.log(result);