JS - imooc
DOM:提供与网页内容交互的方法和接口
DOM通过创建 表示文档的树,让开发者可以控制网页的内容和结构。使用DOM API可以轻松地删除、添加、替换、修改节点
DOM 可以让 JavaScript 和 页面中的 HTML 交互
document 表示浏览器中的整个页面,它包含完整的 DOM
如何告诉浏览器只在页面加载之后才执行代码?
要告诉浏览器执行代码之前需要等待,我们要用到两部分JavaScript,一个是 window 对象,另外还有一个函数
DOM 还能做什么?
从DOM得到元素,向DOM创建或增加元素
删除数组元素的两种方式:
- 将该索引的数组元素值设置为 null(数组的长度不变)
- 删除这个元素:使用函数splice(数组的长度 -1)
undefined 和 null 是两个不同的值:
- undefined表示一个变量未赋值
- null 表示这个变量有一个空值
BOM:提供与浏览器交互的方法和接口
可以使用async
属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照它们在页面中出现的次序执行
.appendChild()
window.onload = init; //页面完全加载时才会调用并执行init函数
var li = document.createElement("li");
li.innerHTML = songName;
var ul = document.getElementById("playlist");
ul.appendChild(li);
// 让<ul>元素增加<li>元素作为它的一个子元素,一旦完成,DOM中<li>就会成为<ul>的一个子节点,浏览器会相应更新显示,反映这个新<li>
总结 事件与处理程序
1.处理一个按钮点击事件时,要注册一个函数来处理这个事件,要做到这一点,需要编写一个函数,并把按钮的 onclick 属性设置为这个函数名
2.要得到用户在一个表单输入文本域中输入的文本,需要使用这个输入域的 value 属性
JavaScript 函数和对象
H5 JavaScript API 是由对象、方法(也称为函数)和属性构成
定义函数时指定形参,调用函数时提供实参
如果一个函数没有 return 语句,它会返回 undefined
如果把一个局部变量命名成与一个已有的全局变量同名,会“遮蔽”这个全局变量(但是他们是独立的变量)
对象:一个属性集合
var Fido = {
name:"Fido",
weight:"40",
breed:"Mixed",
loves:["walks", "fetching", "balls"]
};
将元素压入数组末尾:fido.loves.push("chewing bones");
//枚举对象的所有属性
for (prop in fido) { //枚举属性,我们使用了一个 for-in 循环
alert("Fido has a " + prop + " property "); //每次循环迭代时,变量prop会得到下一个属性名的相应串值
if (prop == "name") {
alert("This is " + fido[prop]); //我们使用[]记法来访问这个属性的值
}
}
谈谈向函数传入对象
我们已经聊了很多实参是怎样传递给函数的——实参通过 传值 给函数
所以如果我们传递一个整数,相应函数的 形参 会得到这个 整数 value 的copy,并在函数中使用
同样的规则适用于对象,然而我们需要看清楚 当一个对象被指定给一个变量的时候,变量中包含了什么。
当一个对象被指定给一个变量的时候,这个变量包含的是这个对象的引用,而不是对象本身,可以认为 对象引用 是 指向对象的指针
所以当你调用函数并传入对象的时候,实际上只传递了对象引用,这个 对象引用 的副本 会传递给 形参 ,它指向原来的对象
让我们看看 当我们传递 fido 到loseWeight 函数时,发生了什么
fido 是一个对象的引用,loseWeight 函数的 dog 形参得到 fido 引用的一个副本;所以,形参属性的改变都会影响我们所传入的对象
function loseWeight(dog) {
dog.weight = dog.weight - 10;
// dog引用是fido引用的一个副本
// 当我们传 fido 到loseWeight函数中时,传递给 dog形参的是 引用的副本,不是对象的副本,所以fido 和 dog 指向同一对象
}
alert(fido.name + "now weighs " + fido.weight);
案例:下一次放映时间
<!DOCTYPE html>
<html lang="zh">
<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></title>
</head>
<body>
<script type="text/javascript">
function getNextShowing(movie) {
var now = new Date().getTime();
// 现在使用 movie 的数组 showtimes,迭代处理各个放映时间
for (var i = 0; i < movie.showtimes.length; i++) {
// 对于每个放映时间,得到相应的时间值(单位为毫秒),然后比较
var showtime = getTimeFromString(movie.showtimes[i]);
if ((showtime - now) > 0) {
return "Next showing of" + movie.title + "is " + movie.showtimes[i];
}
}
return null; //如果没有放映场次了,就返回null
}
function getTimeFromString(timeString) {
var theTime = new Date();
var time = timeString.match(/(\d+)(?::(\d\d))?\s*(p?)/);
theTime.setHours( parseInt(time[1]) + (time[3] ? 12 : 0));
theTime.setMinutes( parseInt(time[2]) || 0 );
return theTime.getTime();
}
var banzaiMovie = {
title:"Buckaroo Banzai",
genre:"Cult classic",
rating:5,
showtimes:["1:00pm","5:00pm","7:00pm"]
}
var nextShowing = getNextShowing(banzaiMovie);
alert(nextShowing);
</script>
</body>
</html>
// 对象也可以有行为var fido = { //对象中有函数时,我们说这个对象有一个 方法 bark: function() { alert("Woof woof!"); }; // 我们使用了匿名函数,并把他赋给对象的 bark 属性}fido.bark(); //调用方法
增加 "this" 关键字
var movie1 = { titie: "Plan 9 from Outer Space", genre: "Cult Classic", rating: 5, showtimes: ["3:00pm", "7:00pm", "11:00pm"], getNextShowing: function() { var now = new Date().getTime(); //这里在每个属性前面增加一个 this 关键字,指示我们想得到movie1对象的引用 for (var i = 0; i < this.showtimes.length; i++) { var showtime = getTimeshowtimeString(this.showtimes[i]); if ((showtime - now) > 0) { return "Next showing of " + this.title + " is " + this.showtimes[i]; } } return null; } };
构造函数
可以把它想象成一个小工厂,根据你希望的属性值设置对象,然后给你奉上一个漂亮的新对象,其中包含所有正确的属性和方法
//dog 是一个构造函数,它取一组实参,这正是我们希望的属性初始值:名字、品种、重量,一旦有了这些值,再使用this关键字为属性赋值 //它还定义了bark方法,所有这些工作的结果是什么?Dog构造函数会返回一个对象 //构造函数首字母大写,形参取我们希望的对象属性值 function Dog(name, breed, weight) { //这里我们把 对象属性 初始化为 传入构造函数的值,属性名和形参不要求相同,不过它们通常是一样的,这也是一个约定 this.name = name; this.breed = breed; this.weight = weight; //可以在构造的对象中包含bark方法,将bark属性初始化为一个函数值,这类似于之前的做法 this.bark = function() { if (this.weight > 25) { //方法需要使用 "this.weight" 和 "this.name" 来指示对象中的属性,这与前面一样 alert(this.name + "says Woof!"); } else { alert(this.name + "says Yip!"); } }; }
调用构造函数
// 要用一种特殊的方式调用构造函数,在调用前面加上关键字new
// 要创建一只狗,要结合构造函数使用new关键字,然后像任何其他函数一样调用
// 我们创建了3个不同的Dog对象,分别传入不同的实参来定制各个狗var fido = new Dog("Fido", "Mixed", 38);var tiny = new Dog("Tiny", "Chawalla", 8);var clifford = new Dog("Clifford", "Bloodhound", 65);
// 一旦得到对象,就可以调用它们的bark方法让每个Dog吠叫fido.bark();tiny.bark();clifford.bark();
//总结:我们创建了3个不同的Dog对象,每个对象都有自己的属性,这里结合前面创建的Dog构造函数还使用了new关键字。构造函数返回一个Dog对象,并用我们传入的实参定制//对每个对象调用bark方法,注意所有的狗都共享同一个bark方法,每个狗吠叫时,this指向做出调用的那个dog对象,所以如果对fido调用bark方法,那么在bark方法中,this就设置为fido对象
只要在一个方法代码中放入this,就会把它解释为 调用这个方法的对象 的一个引用:所以如果调用fido.bark,则this会引用fido
构造函数
this总是指向调用方法的当前对象
Q:函数和方法真正的区别是什么?
如果对象有一个函数,我们就称它是一个方法,它们都以同样的方式工作,只不过调用对象的方法时要使用点操作符,而且方法可以使用this来访问调用这个方法的对象,可以认为函数是一段能调用的独立代码,而方法是与一个特定对象关联的行为
Q:如果用构造函数创建对象,而且这些对象有一个方法,那么所有这些对象都共享这个方法的相同代码是吗?
是的,这正是面向对象编程的优点之一:你可以在一个地方为一类对象(比如所有dog对象)创建代码,所有dog对象都会共享这个代码。要让各个狗有所不同,现在的做法是利用属性,并使用this访问这些属性
Q:我能把this设置为我选择的一个值吗?如果可,会不会弄乱了?
不行,不能把this设置为任何值,this是一个关键字而不是一个变量,看起来它像是一个变量,表现也有些类似,不过它确实不是变量
Q:this 在对象方法之外有值吗?
没有,如果没有调用一个对象方法,this就是undefined
Q:所以应该这么考虑this:在一个对象上调用一个方法时,执行这个方法的整个过程中 this 的值都设置为这个对象,这样理解对吗?
在对象的体中确实是这样,this就是对象本身。不过有些特殊的情况下并非如此,例如,如果对象中还包括对象,情况就会更为复杂,如果开始在对象中嵌套对象,就需要仔细查看语义,不过以上理解是一个很好的一般原则
Q:我听说面向对象编程中可以有对象类,它们相互继承。比方说,可以有一个哺乳动物类,狗和猫都可以继承这个哺乳动物类,在JS中能这么做吗?
当然能,JS使用了一种称为原型继承的机制,与严格的基于类的模型相比,这是一种更为强大的模型,深入介绍原型继承超出了本书的范畴
Q:我们说new Date()时就是在使用一个构造函数?
是的,Date是JS中的一个内置构造函数,如果调用new Date(),你就会得到一个Date对象,这个对象包含很多有用的方法,可以用来处理日期
Q:我们自己编写的对象与用构造函数创建的对象之间有什么区别吗?
主要区别在于你如何创建对象,用大括号和逗号分隔的属性所写的对象称为“对象字面量”。你是照字面把这些对象输入到代码中。
如果你想要一个类似的对象,就必须自行输入,确保它有同样的属性,由构造函数创建的对象则是通过使用new和一个构造函数创建的,它会返回对象。你可以使用构造函数创建多个有相同属性的对象,不过如果愿意,这些属性就可以有不同的属性值
Window 对象
表示你的JS程序的全局环境,同时还表示应用的主窗口
你定义的所有全局变量都会放在window命名空间中,
window对象重要的属性和方法:
属性:
- location:包含页面的URL,如果改变这个属性,浏览器就会访问新的URL
status:包含将在浏览器状态区显示的一个串
onload:包含了页面完全加载时要调用的函数
document:包含DOM
方法:
- alert:显示一个提醒
prompt:类似于alert,只不过会从用户得到信息
open:打开一个心的浏览器窗口
close:关闭窗口
setTimeout:指定的时间间隔后,调用一个处理程序
setInterval:以一个指定的时间间隔反复调用一个处理程序
window.onload()
//通过向window.onload属性指定一个函数,可以确保在页面加载和DOM完全建立不会运行代码window.onload = function() { // code here}
document 对象
属性:
- domain:提供 文档的服务器 的域
title:得到文档的标题
URL:文档的URL
方法:
- getElementById:根据元素id获取这个元素
getElementByTagName:使用标记来获取元素
getElementsByClassName:使用类来获取元素
createElement:创建适合包含在DOM中的元素
document.getElementById
document 是文档对象,这是一个内置的JavaScript对象,允许你访问DOM
getElementById 是一个方法
P
所有元素都支持这些属性和方法:
属性:
- innerHTML
childElementCount:这个元素有多少子元素
firstChild:第一个子元素
方法:
- appendChild:向DOM中插入新元素
insertBefore:向DOM中插入新元素
setAttribute:设置元素中的属性
getAttribute:获取元素中的属性
如果函数名后面使用了小括号,比如init(),就是说你希望调用函数init
如果只是使用名,就会把这个函数值赋给onload属性
总结
JavaScript 使用传值方式传递参数
传递一个对象作为一个函数的实参时,比如 dog,形参会得到这个 对象引用 的一个副本
如果声明一个局部变量时与一个全局变量同名,这个局部变量会遮蔽全局变量
从页面链接到多个JS文件时,所有全局变量都定义在同一个全局空间中
方法可以使用一个特殊的关键字 this 来引用调用这个方法的对象
构造函数是 创建对象 的函数
构造函数的任务是创建一个新对象,并初始化这个对象的属性
document.getElementById 方法会返回一个元素对象
与 Web 交流
如何从JS做出请求
//首先从一个URL开始,我们要告诉浏览器到哪里找我们想要的数据var url = "http://someserver.com/data.json"//接下来创建一个请求对象:使用XMLHttpRequest构造函数创建一个新的请求对象var request = new XMLHttpRequest();//下面需要告诉这个请求对象我们希望它获取哪个URL,以及要使用哪种请求。为此我们使用了请求对象的 open 方法//open只是用一个URL建立一个请求,并告诉这个请求对象要使用哪种请求,一遍XMLHttpRequest验证连接,可以调用如下open方法:request.open("GET", url);//这会使用HTTP GET建立一个请求对象,HTTP GET是获取HTTP数据的标准方法//接下来到重点了:要求XMLHttpRequest对象获取数据时,它会自己去获取数据,所以我们并不是一直傻等数据,而是会提供一个处理程序,数据到达时就会调用这个处理程序,如下建立处理程序request.onload = function() { if (request.status == 200) { alert("Data received!"); }}//最后一步:需要告诉请求对象去获取数据,为此要使用send方法request.send(null);
总结:我们要创建一个XMLHttpRequest对象,基于一个URL和HTTP请求类型加载这个对象,同时提供一个处理程序,然后发出请求,等待数据到达,数据到达时就会调用这个处理程序
HTTP GET获取的数据可以在request对象的responseText属性中找到
request.onload = function() { if (request.status == 20) { alert(request.responseText); }}
给 XMLHttpRequest 一个URL,它就会为你获取数据,然后需要告诉XMLHttpRequest拿到数据之后要怎么处理(比如给一个处理函数)
JSON
要想使用 JSON ,你只需要了解JS对象和两个方法调用
1.我们有一个想 交换或存储的JavaScript对象 ,所以调用JSON.stringify方法,把这个对象作为实参传入
2.结果是表示这个对象的一个字符串,要把这个字符串转换回一个对象,需要把它传给JSON.parse方法,结果是原始对象的一个副本
案例:将一个对象转换为它的 JSON 串格式
并不是所有一切都能转换为一个 JSON 串,例如方法就不能转换为一个 JSON 串
// 创建一个对象,然后把它转换为一个串var plan9Movie = new Movie("Plan 9 from Outer Space","Cult Classic", 2,["3:00pm", "7:00pm", "11:00pm"]);
一旦得到对象,可以用 JSON.stringify 方法把它转换为 JSON 串格式
var jsonString = JSON.stringify(plan9Movie);alert(jsonString);
从另一个服务器接收一个 JSON 串,可以把 JSON串 转换回一个对象来进行处理:JSON.parse
var jsonMovieObject = JSON.parse(jsonString);alert("JSON Movie is " + jsonMovieObject.title);
JSONP
一种使用<script>
标记获取 JSON对象 的方法,“JSON with Callback”(有回调的 JSON)
P:Padding,在请求中返回 JSON 之前先用一个函数来包装
建立定时器
setInterval(handleRefresh, 3000);// 每隔3000ms,JS就会调用你的处理程序,在这里就是要调用handleRefresh函数function handleRefresh() { alert("I'm alive");}
DOM的过人之处就在于,我们可以在任何时间向DOM插入新元素,甚至是<script>
函数
所以只要向做出一个 JSONP 调用,就能插入一个新的<script>
元素
replaceChild方法 可以替换一个元素的子元素
head.replaceChild(newScriptElement, oldScriptElement);
创建一个新的 script 元素
function handleRefresh() { var url = "http://gumball.wickedlysmart.com?callback=updateSales"; // 我们建立了 JSONP URL,并把它赋给变量url var newScriptElement = document.createElement("script"); newScriptElement.setAttribute("src", url); // 将这个元素的src属性设置为我们的JSONP URL newScriptElement.setAttribute("id", "jsonp");}
setAttribute方法允许你设置一个HTML元素的属性,如src和id属性,或者是另外一些属性
要访问Web服务托管的数据,除了XMLHttpRequest外,另一种候选方法是JSONP
如果需要访问由远程服务器上一个Web服务托管的数据(假设这个Web服务支持JSONP),则要使用 JSONP。
Web服务就是一个通过HTTP访问的Web API
JSONP是一种使用<script>
元素获取数据的方法
JSONP就是JSON数据包装在JS中,通常会包装在一个函数调用中
将JSON数据包装在JSONP中 的函数 调用称为 “回调”
将回调函数指定为 JSONP 请求中的一个 URL查询参数
如果做出多次请求,可以在JSONP请求URL的末尾使用一个随机数,使浏览器不会缓存这个响应
要指定<script>
元素做出JSONP请求,可以把它直接增加到HTML,或者使用JavaScript将<script>
元素写至DOM
Canvas
//绘制 150*100 像素的矩形:
画布是Web页面中显示的图形区,上下文是与画布关联的一个对象,它定义了一组属性和方法,可以用来在画布上进行回执,甚至可以保存上下文的状态,以后再恢复
画布设计用来支持多个接口,通过使用上下文,就能在同一个画布元素中处理不同的接口
不能直接在画布上绘制,因为你需要选择一个上下文来指定使用哪个接口
// fillStyle是上下文的一个属性,保存了在画布上完成绘制时所用的颜色context.fillStyle = "lightblue";
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.strokeRect(20,20,150,100);
类似于fillRect,fillStyle也要通过上下文来控制
不过与fillRect不同的是,fillStyle是一个属性,而不是方法,所以需要设置而不是调用
上下文是一个对象,可以控制对画布的访问,使用fillStyle和fillRect时,首先是设置一个属性,告诉画布”不管你接下来画什么,都要用这个颜色“,所以设置fillStyle之后,用颜色填充的任何东西(比如用fillRect)都会使用这种颜色,直到你再将fillStyle设置为另一种不同的颜色来改变颜色
圆
使用beginPath方法告诉画布我们要开始一个新路径
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>三角形</title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id=myCanvas width=500px height=500px></canvas>
</body>
<script type="text/javascript">
var c = document.getElementById("myCanvas");
var context = c.getContext("2d");
context.arc(200,200)
</script>
</html>
上下文对象中还有一个名为 arc 的方法:
context.arc(150, 150, 50, 0, 2 * Math.PI, true);
// context.arc(x, y, radius, startAngle, endAngle, direction)
// x,y参数确定圆心在画布上的位置
// direction 逆时针false,顺时针true
*从度得到弧度,需要 π/180
要在画布上绘制,首先需要创建一个上下文,因为上下文提供了一个特定的接口。目前2D上下文是唯一的选择,不过将来可能还会有其他上下文类型
要在画布中绘制一个矩形,可以使用context.fillRect方法,这个方法会创建一个矩形,并填充指定的颜色
要创建一个矩形轮廓,可以使用 strokeRect 而不是 fillRect
可以用poster属性提供你自己的海报图像
Web存储
利用 cookie 在浏览器上存储信息
cookie 如何工作:浏览器获取一个Web页面,服务器可以随响应发送一个cookie,cookie中包含一个或多个键值对
浏览器在本地存储cookie,下一次发出请求时会把它发回给服务器
服务器可以使用cookie实现个性化体验
cookie与一个域关联,而且只能发送给这个域。页面所能存储和获取的数据项 必须是由同一个域提供的页面创建的
每个域有一个单独的存储空间,所以存储在一个源的数据项对另一个源中的Web页面是不可见的
localStorage.setItem(key);
localStorage.getItem(key);
localStorage.setItem("sticky_0", "Pick up dry cleaning");
localStorage.setItem("sticky_1", "Cancel cable tv, who needs it now?");
var sticky = localStorage.getItem("sticky_1");
alert(sticky);
利用localStorage,只能使用字符串作为键和值
但是并没有那么严格,假设你需要存储整数5,可以存储字符串"5",然后从本地存储获取时再将它转换回一个整数
localStorage.setItem("numitems", 1);
// JS会将 数字1 强制转换为 字符串"1",
var numItems = parseInt(localStorage.getItem("numitems"));
numItems += 1;
localStorage.setItem("numitems",numberItems);
localStorage.setItem("price", 9.99);
var price = parseFloat(localStorage.getItem("price"));
localStorage提供了获取方法和设置方法(getItem 和 setItem)
localStorage.length:告诉我们localStorage中有多少个数据项
localStorage.key:key方法会给出localStorage中各个数据项的键(如"sticky_0"),然后使用这个键抽取相应的值
var sticky = localStorage["sticky_0"];
Web 工作线程
JS一次只能做一件事,如果有一些代码的执行需要花费太长时间,就可以创建一个 Web工作线程,由它处理这个任务,而让主JS控制线程确保与浏览器和用户的交互一切正常
工作线程由一个单独的JavaScript文件定义
onmessage
onmessage处理程序从 工作线程 接收到的消息,包装在一个Event对象中,它有2个属性,data和target
// event是工作线程提交一个消息时 从工作线程发送到页面代码的对象
worker.onmessage = function (event) {
// data属性包含工作线程发送的消息
var message = event.data;
// target是发出这个消息的工作线程的一个引用,如果需要知道这个消息来自哪个工作线程,就很方便
var worker = event.target;
}
Web工作线程在一个单独的线程处理任务,所以主JavaScript代码可以继续运行,用户界面可以保持响应
Web工作线程的代码 放在与页面代码不同的一个单独的文件中
Web工作线程 不能访问页面代码中的函数或DOM
页面中的代码与Web工作线程通过消息通信
要向一个工作线程发送信息,可以使用postMessage
可以通过postMessage向工作线程发送字符串和对象,但不能向工作线程发送函数
可以将工作线程的onmessage属性设置为一个处理函数,来接收由工作线程返回的消息
一个工作线程准备发回一个结果时,会调用postMessage,并传入结果作为参数
工作线程结果封装在一个事件对象中,并置于data属性中
可以使用event.target属性查找哪个工作线程发出了信息
消息在主页面代码和工作线程之间会复制,而不是共享
可以使用多个工作线程完成能分解为多个任务的大规模计算,如计算一个分形可视化图形或对光线跟踪图像
可以从页面代码调用worker.terminate()来终止一个线程,这会终止工作线程脚本,工作线程还可以调用close()让自己停止工作
工作线程还有一个onerror属性,可以把这个属性设置为一个错误处理函数,如果你的工作线程存在一个脚本错误就会调用这个处理函数
要在工作线程文件中包含和使用JavaScript库,可以使用importScript
第2节 JS基本数据类型
typeof( )
是运算符(不是函数):可以检测值或者变量的类型
aeb: a*10的b次方
NaN:不是一个数,是一个数字类型的值
substring()
//提取子串,substring(a,b)方法得到从a开始到b结束(不包括b处)的子串,a可以大于b,b可以省略,表示到字符串结尾,可以自动交换两个参数的位置
substr()
//提取子串,substr(a,b)中,将得到从a开始的 长度为b的子串,a可以是负数,表示倒数位置,b可以省略,表示到字符串结尾
slice()
//提取子串,slice(a,b)方法得到从a开始到b结束(不包括b处)的子串,a可以是负数,a必须小于b
indexOf()
//返回某个指定的字符串值在字符串中首次出现的位置,如果要检索的字符串值没有出现,则该返回-1
null:表示 “空对象”
第3节 表达式与操作符
3* '2天' //NaN
隐式类型转换:如果参与数学运算的某操作数不是数字型,那么JS会自动将此操作数转换为数字型
在进行小数运算时,要调用数字的toFixed()方法保留指定的小数位数
(0.1 + 0.2).toFixed(2) //'0.30'
Number((0.1+0.2).toFixed(2)) //0.3
Math.ceil() 向上取整
Math.floor() 向下取整
undefined == null // true
NaN不自等
如何判断某变量值为NaN:isNaN()函数可以用来判断变量值是否为NaN
isNaN(undefined) //true
isNaN('3天') //true
isNaN(null) //false
短路计算
赋值表达式
a++ 和 ++a 的区别
a++ 先用a再加1,++a 先加1再用a
var a = 3;
var b = a++;
console.log(b); // 3
console.log(a); // 4
var a = 3;
var b = ++a;
console.log(b); // 4
console.log(a); // 4
闰年判断(满足以下一个条件即可)
1.能被4整除且不能被100整除
2.能被100整除也能被400整除