組成部分: ECMA、DOM、BOMjavascript
什麼是ECMA?全稱 ECMAScript 簡寫 ECMA 或 EShtml
ECMA是一個標準,JS是實現java
例如: HTML5 是標準,chrome,FF,IE10是實現node
未來也可能有 xxxscript 實現ECMAgit
目前的版本:es6
版本進化過程github
1996 ES1.0 js穩定 Netscape將js提交給ECMA組織
1998 ES2.0 正式發佈
1999 ES3.0 瀏覽器普遍支持
2007 ES4.0 ES4過於激進,被廢除
2008 ES3.1 4.0變爲縮水版的3.1 代號:Harmony
2009 ES5.0 ES5 正式發佈,同時公佈了javascript.next-6.0前身
2011 ES5.1 成爲ISO國際標準
2013.3 ES6.0 ES6.0制定草案
2013.12 ES6.0 發佈草案
2015.6 ES6.0 ES6.0預計發佈,同時發佈 es7.0正在制定草案
兼容性:ajax
目前爲止ES5 ES6支持狀況還湊合
nodejs用的就是chrome內核,在node中已經可使用es6的不少特性了
ES5和ES6已經逐漸淪爲後臺語言
1. 在瀏覽器中如何使用?須要編譯工具,把ES6語法編譯成ES5
babel
traceur ---google出的編譯器
bootstrap 引導程序
<script src="traceur.js"></script>
<script src="bootstrap.js"></script>
<script type="module">
let a = 12;
</script>
<script src="https://traceur-compiler.googlecode.com/git/bin/traceur.js"
type="text/javascript"></script>
<script src="https://traceur-compiler.googlecode.com/git/src/bootstrap.js"
type="text/javascript"></script>
<script>
traceur.options.experimental = true;
</script>
<script type="module" src="js/calc.js"></script>
2. 在線編譯:主要用於測試
a. babeljs.io/repl
b. google.github.io/traceur-compiler/demo/repl.html
3. 在node中能夠直接使用
"use strict"
let a = 12;
console.log(a);
a. 直接用,須要添加 use strict
b. node --harmony_destructuring xx.js
let定義的變量不能在相同做用域下,重複聲明同一個變量chrome
function () {
let a = 10;
var a = 1;
}
function () {
let a = 10;
let a = 1;
}
如下現象用來理解塊級做用域bootstrap
現象1:
{
let a = 10;
var b = 1;
}
console.log(a);
console.log(b);
結論:let聲明的變量盡在 {}內有效
現象2: let聲明的變量僅在當前做用域中有效
for(let i=0;i<10;i++){}
console.log(i);
現象3:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
//========
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
i是let聲明的,因此當前的 i僅在本輪循環有效,直接會被解析成數字。
現象4:循環語句是父做用域,循環體是一個獨立的做用域,互不影響。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
現象5: 不存在變量提高
// var 的狀況
console.log(foo);
var foo = 2;
// let 的狀況
console.log(bar);
let bar = 2;
現象6: 暫時性死區
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
報錯:由於當使用let時,當前快做用域被封閉,let定義的變量僅可以在以後使用
內層變量可能會覆蓋外層變量。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f();
用來計數的循環變量泄露爲全局變量。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
1.
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
自執行函數封閉做用域,能夠用塊做用域替代
// IIFE 寫法
(function () {
var tmp = ...;
...
}());
// 塊級做用域寫法
{
let tmp = ...;
...
}
3.
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重複聲明一次函數f
function f() { console.log('I am inside!'); }
}
f();
}());
const聲明的變量不得改變值,這意味着,const一旦聲明變量,就必須當即初始化,不能留到之後賦值。
const的做用域與let命令相同:只在聲明所在的塊級做用域內有效。
if (true) {
const MAX = 5;
}
MAX
什麼是解構賦值? 左邊一種結構,右邊一種結構,左右一一對應進行賦值
分類
數組解構賦值 **
對象解構賦值 **
字符串解構賦值
布爾值解構賦值
函數參數解構賦值
數值解構賦值
let [x,y] = [1,2];
console.log(x,y);//1,2
{
let a,b,rest;
[a,b,...rest] = [1,2,3,4,5,6];
console.log(a,b,rest);//rest [3,4,5,6]
}
//對象的解構賦值
{
let a,b;
({a,b} = {a:1,b:2});
console.log(a,b);
}
// 解構賦值的默認值
{
let a,b,c,rest;
[a,b,c=3,d] = [1,2];
console.log(a,b,c,d);
}
//利用解構賦值交換變量中的值
{
let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b);
}
function f(){
return [1,2];
}
let [a,b] = f();
console.log(a,b);
{
function f(){
return [5,6,7,8,9];
}
let [a,,,,b] = f();
console.log(a,b);
}
{
function f(){
return [5,6,7,8,9];
}
let [a,...b] = f();
console.log(a,b);
}
{
let o = {name:'yuonly',age:20};
let {age,name} = o;
console.log(name,age);
}
// ... 能夠替代arguments
{
function test3(...arg){
for(let v of arg){
console.log('rest',v);
}
}
test3(1,2,3,4,'a');
}
//簡潔表達
{
let a = 1;
let b = 2;
//ES5
let es5 = {
a:a,
b:b
}
console.log(es5);
//ES6
let es6 = {
a,
b
}
console.log(es6);
}
{
//若是有方法的處理方式
// ES5
let es5 = {
hello:function(){
console.log('hellow');
}
}
//ES6
let es6 = {
hello(){
console.log('hello');
}
}
}
let a = 'b';
let es5_obj = {//es5中對象的 key必須是固定的
a:'c'
}
//es6
let es6_obj = {//屬性值能夠是變量
[a] : 'c'
}
console.log(es6_obj,'es6_obj');
{
//babel不支持,沒法編譯
let {a,b,...c} = {a:'test',b:'kill',c:'ddd',d:'ccc'}
c = {
c:'ddd',
d:'ccc'
}
}
{
// is :判斷兩個值是否相等
console.log('字符串',Object.is('abc','abc'));
console.log('數組',Object.is([],[]));//兩個不一樣的地址
//assign : 潛拷貝
console.log('拷貝',Object.assign({a:'a'},{b:'b'}));
// entries
let test = [k:123,o:456];
for(let [key,value] of Object.entries(test)){
console.log([key,value]);
}
}
{
//基本定義和生成實例
class Person{
constructor(name='laozhou'){
this.name = name;
}
}
let p1 = new Person('小王');
console.log('構造函數和實例',p1);
}
{
//繼承
class Father{
constructor(name='laozhou'){
this.name = name;
}
}
class Child extends Father{
}
console.log('子類的實例',new Child());
console.log('子類本身傳',new Child('小劉'))
}
{
//子類如何覆蓋父類的值
class Father{
constructor(name='laozhou'){
this.name = name;
}
}
class Child extends Father{
constructor(name='child'){
//this.type = 'boy';//super必須在第一行,不然報錯
super(name);//調用父親類的構造函數
this.type = 'boy';
}
}
console.log('子類覆蓋父類屬性的實例',new Child());
}
//靜態屬性
{
class Person{
constructor(name='laozhou'){
this.name = name;
}
}
//靜態屬性的定義,是直接給類下的屬性賦值,該屬性就是靜態屬性
Person.type = 'text';//type就是靜態屬性
}
//靜態方法
{
class Person{
constructor(name='laozhou'){
this.name = name;
}
static tell(){//至關於原型下的方法,是屬於類自己的,用類來調用
console.log('tell');
}
}
Person.tell();
}
{
//getter setter
class Father{
constructor(name='laozhou'){
this.name = name;
}
//此處longName不是函數而是屬性,至關於新增了一個屬性 longName
get longName(){
return 'yu_'+this.name;
}
set longName(value){
this.name = value;
}
}
let f1 = new Father();
console.log('getter',f1.longName);
f1.longName = 'hello';
console.log('setter',f1.longName);
}
promise是異步變成的解決方案(解決回調地獄)
{
//es5 中的異步操做
let ajax = function(callback){
console.log('執行');
setTimeout(function(){
callback && callback.call();
},1000);
}
ajax(function(){
console.log('timeout1');
})
}
{
//ES6
let ajax = function(){
console.log('執行2');
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();//resolve後會有then方法,執行後續操做
},1000);
})
}
ajax().then(function(){
console.log('promise','timeout');
})
}
//promise.all :把多個promise實例當作一個promise實例,當全部的狀態都完成以後,纔會觸發新的promise對象的then方法
//應用,好比廣告中有三張圖,須要三張圖都加載再去更新dom
{
//全部圖片加載完成在加載頁面
function loadImg(src){
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = src;
img.onload = function(){
resolve(img);
}
img.onerror = function(){
reject(err);
}
})
}
function showImg(imgs){
imgs.forEach(function(img){
document.body.appendChild(img);
})
}
Promise.all([
loadImg('https://img10.360buyimg.com/n4/s260x260_jfs/t3079/363/6070979658/42126/5b5c2f39/589af086N4a3bed39.jpg'),
loadImg('https://img14.360buyimg.com/n4/s260x260_jfs/t4345/284/2534342556/119746/550dee37/58d34a9dNf0bd717f.jpg'),
loadImg('https://img13.360buyimg.com/n4/s260x260_jfs/t3259/170/5587914266/144572/64259fc5/5873347aN14e34822.jpg'),
]).then(showImg);
}
{
//promise.race 誰先回來處理誰,先到先得
function loadImg(src){
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = src;
img.onload = function(){
resolve(img);
}
img.onerror = function(){
reject(err);
}
})
}
function showImgs(img){
let p = document.createElement('p');
p.appendChild(img);
document.body.appendChild(p);
}
Promise.race([
loadImg('https://img10.360buyimg.com/imgzone/jfs/t5149/215/1247256617/226900/c371168/590dcc2bN2234f761.jpg'),
loadImg('https://img14.360buyimg.com/n4/s260x260_jfs/t4345/284/2534342556/119746/550dee37/58d34a9dNf0bd717f.jpg'),
loadImg('https://img13.360buyimg.com/n4/s260x260_jfs/t3259/170/5587914266/144572/64259fc5/5873347aN14e34822.jpg'),
]).then(showImgs);
}
//使用promise後,更清晰
{
let oBox = document.getElementById('box');
function toWidth(w){
return new Promise(function(resolve,reject){
let timer = setInterval(function(){
var oldWidth = oBox.clientWidth;
if(oldWidth>w){
clearInterval(timer);
resolve();
}
oBox.style.width = oldWidth + 10 + 'px';
},100);
})
}
function toHeight(h){
return new Promise(function(resolve,reject){
let timer = setInterval(function(){
var oldHeight = oBox.clientHeight;
if(oldHeight>h){
clearInterval(timer);
resolve();
}
oBox.style.height = oldHeight + 10 + 'px';
},100);
})
}
function toSmall(size){
return new Promise(function(resolve,reject){
let timer = setInterval(function(){
var oldWidth = oBox.clientWidth;
var oldHeight = oBox.clientHeight;
if(oldWidth<size || oldHeight<size){
clearInterval(timer);
resolve();
}
console.log(123);
oBox.style.width = oldWidth - 10 + 'px';
oBox.style.height = oldHeight - 10 + 'px';
},100);
})
}
//使用promise後,更清晰,能夠隨意更改流程。
toHeight(400)
.then(function(){
return toWidth(600);
})
.then(function(){
return toHeight(300);
})
.then(function(){
return toSmall(100);
})
.then(function(){
return toHeight(400);
})
}
//ES5
{
function toWidth(w,callback){
let timer = setInterval(function(){
var oldWidth = oBox.clientWidth;
if(oldWidth>w){
clearInterval(timer);
callback && callback();
}
oBox.style.width = oldWidth + 10 + 'px';
},100);
}
function toHeight(h,callback){
let timer = setInterval(function(){
var oldHeight = oBox.clientHeight;
if(oldHeight>h){
clearInterval(timer);
callback && callback();
}
oBox.style.height = oldHeight + 10 + 'px';
},100);
}
function toSmall(size,callback){
let timer = setInterval(function(){
var oldHeight = oBox.clientHeight;
var oldWidth = oBox.clientWidth;
if(oldHeight<size){
clearInterval(timer);
callback && callback();
}
oBox.style.width = oldWidth - 10 + 'px';
oBox.style.height = oldHeight - 10 + 'px';
},100);
}
//代碼可讀性差,並且很難控制執行順序
toWidth(500,function(){
toHeight(300,function(){
toSmall(100,function(){
toWidth(400,function(){
toHeight(100,function(){
})
})
});
})
});
}
//模塊的導出 module1.js
export let a = 123;
export function test(){
console.log('test');
}
export class Hello{
test(){
console.log('class');
}
}
//模塊的導入 entry.js
a as A 起別名 A,外部使用A來操做a
import {a as A,test,Hello} from './lesson/6.module/module1.js';
console.log(A,test,Hello);
//導入全部模塊放入 obj對象下
import * as obj from './lesson/6.module/module1.js';
console.log(obj.a);
//導出 module2.js
let num = 123;
let test = function(){
console.log('test');
}
class Person{
test(){
console.log('Person');
}
}
//1,批量導出,一目瞭然導出了那些東西給外部 2, 沒有起名字,將命名權給倒入方。
export default {
num,
test,
Person
}
//導入 entry.js
import M from './lesson/6.module/module2.js';
console.log(M,M.num);
M.test()
{
function test(x,y=10){
console.log('默認值',x,y);
}
test(1);
test(99,88);
}
// 有默認值的參數後面,不能有 沒有默認值的參數
{
function test(x,y=10,c){//會報錯,在默認值後面不能有 沒有默認值的參數
console.log('默認值',x,y);
}
}
//函數的做用域
{
let x = 'test';
function test2(x,x=y){
console.log('做用域——',x,y);
}
test2('new');
}
//沒有的時候用上面的
{
let x = 'test';
function test2(c,y=x){
console.log('做用域2',x,y);
}
test2('new');
}
{
//此時的arg至關因而 arguments
function test3(...arg){
for(let v of arg){
console.log('rest:',v);
}
}
test3(1,2,3,4,5);
}
{
console.log(...[1,2,3]);
}
{
let arrow = v=>v*10;
console.log(arrow(3));
<!-- let arrow2 = (v)=>{return v*50};
console.log(arrow2(2)); -->
}
至關因而
{
let arrow = function(v){
return v*10;
}
console.log(arrow(3));
}
{
function tail(x){
console.log('tail',x);
}
function go(x){
return tail(x);
}
go(123);
}