前言
不同語言有不同的范式绅你、思想
了解不同的范式伺帘,有助于思路、思維的啟發(fā)忌锯。所謂觸類旁通
computer語言始終是工具伪嫁、武器,而不是拿來爭論的談資偶垮,可以為我所用张咳,而不必為之所限
口號: 學(xué)習(xí)js 為自己賦能
簡介
一門非常靈活的 動態(tài) 帝洪、弱類型 語言
反直覺:
1 性能 2 難度
語言熱榜(只是排行和好壞無關(guān))
跑個分:
參考(僅參考不必較真):
https://benchmarksgame-team.pages.debian.net/benchmarksgame/index.html
https://goodmanwen.github.io/Programming-Language-Benchmarks-Visualization/
歷史
90年代, Brendan Eich 給 Netscape 開發(fā)的瀏覽器輔助語言 Mocha(后更名為 JavaScript)脚猾,耗時10天出原型(包含了eval 函數(shù))葱峡,集成到 Netscape 2預(yù)覽版里,Mocha 基于對象而非 Java 那樣基于類龙助。
Mocha 的動態(tài)的對象模型砰奕,使用原型鏈的機制。
Netscape 2 正式版將 Mocha 更名為 JavaScript提鸟,后簡稱 js军援。
1.0 版本 js 語法大量借鑒 C 語言。行末可不加分號称勋,一開始 js 就是支持的胸哥。
1.1版 js 支持隱式類型轉(zhuǎn)換,可以把任意對象轉(zhuǎn)成數(shù)字和字符串赡鲜。1.0版 js 對象不能繼承烘嘱,1.1 加入對象的 prototype 屬性,prototype 的屬性和實例的對象共享蝗蛙。
為了加到 ISO 標準中,Netscape 找到了 Ecma醉鳖,因為 ISO 對 Ecma 這個組織是認可的捡硅。接著 Ecma 組建了 TC39 技術(shù)委員會負責創(chuàng)建和維護 js 的規(guī)范。
期間盗棵,微軟為了能夠兼容 js壮韭,組建了團隊開發(fā) JScript,微軟自己摸索然后開發(fā)纹因,并寫了份規(guī)范 The JScript Language Specification, version 0.1 提交給 TC39喷屋,微軟還將 VBScript 引入 IE。96年 Netscape 為 JavaScript 1.1 寫了規(guī)范 Javascript 1.1 Specification in Winword format 作為 TC39 標準化 js 的基礎(chǔ)瞭恰。
97年 TC39 發(fā)布了 ECMA-262 第一版規(guī)范屯曹。
Netscape 3 發(fā)布后,Brendan Eich 重構(gòu)了 js 引擎核心惊畏,加了嵌套函數(shù)恶耽、lambda、正則表達式颜启、偽屬性(動態(tài)訪問修改對象)偷俭、對象和數(shù)組的字面量、基于標記和清除的 GC缰盏。lambda 的函數(shù)名為可選涌萤,運行時會創(chuàng)建閉包淹遵,閉包可遞歸引用自己作為參數(shù)。新 js 引擎叫 SpiderMonkey负溪。增加break / continue 標簽語句以及 switch透揣。語言升級為 JavaScript 1.2,和 SpiderMonkey 一起集成到 Netscape 4.0笙以。
ES3 結(jié)合了 js 1.2 和 JScript 3.0淌实,標準堅持了10年。
2006年 Google 的 Lars Bak 開始了 V8 引擎的開發(fā)猖腕,2008 基于 V8 的 Chrome 瀏覽器發(fā)布拆祈,性能比 SpiderMonkey 快了10倍。
Ryan Dahl 2009 開發(fā)了 Node.js 倘感,提供標準庫讓 js 能夠建立 HTTP 服務(wù)端應(yīng)用放坏。此后js就不再局限于前端領(lǐng)域了
ES4 初期目標是希望能夠支持類、模塊老玛、庫淤年、package、Decimal蜡豹、線程安全等麸粮。
這一版本ES4太激進, 很多特性無法通過镜廉,而沒法通過標準弄诲,因此同步設(shè)計了10年多的 ES 3.1 最終改名為 ES5
2015年,(ECMAScript 2015)[]發(fā)布娇唯。這是改動最多的一個版本齐遵,加入了大量的語法特性,此后每年發(fā)布一版標準
ES6特性
箭頭函數(shù)塔插、Promise梗摇、迭代器....
應(yīng)用場景
前端、服務(wù)端想许、腳本工具
基礎(chǔ)語法
變量聲明
const
let
var
類型
number伶授、string、symbol伸刃、undefined谎砾、null、object捧颅、array景图、function
常見編碼規(guī)范
switch、for碉哑、 if挚币、new
語法參考了C 家族的風格:
條件判斷亮蒋、for循環(huán)都需要放到()里
switch需要手動break
for (let i =0 ; i<3; i++){
// do something
}
switch ("some var") {
case "some var":
// logic
break
case "other":
// ...
}
class A{}
const a = new A(); // 符合直覺的創(chuàng)建對象
解構(gòu)
let obj = {hello:"world"};
let {hello} = obj;
console.log(hello);
let obj2 = {obj};
console.log(obj2);
遍歷
for
let arr = [1,2,3];
for (let i = 0; i < arr.length; i++){
console.log(arr[i])
}
for (let i in arr){
console.log(arr[i]);
}
for (let i of arr){ // es6 新增 實現(xiàn)迭代器接口即可 使用此種遍歷方式
console.log(i); // 注意此處直接取到value
}
arr.forEach(i=> console.log(i)); // 閉包形式 不支持break、continue
let arrMulti = arr.map(i=>i*i); // 返回值
let obj = {a:"a", b:3};
for (let i in obj){
console.log(i, "value", obj[i]);
}
for (let i of Object.keys(obj)){ // 對象未實現(xiàn) iterator接口
console.log(i, "value", obj[i]);
}
while妆毕、do...while
函數(shù)
1 復(fù)用代碼
2 構(gòu)造對象
function makeObj(){
this.name = "new obj";
}
let o = new makeObj();
console.log(o)
3 箭頭函數(shù)
const arrow = (params1, params2) =>{
console.log('abc');
};
// 簡寫
arrow = (params1, params2) =>console.log('abc');
// 單參數(shù)可忽略括號
arrow = params =>console.log('abc');
一般高階函數(shù)的參數(shù)(閉包)可用箭頭函數(shù)
const pro = new Pormise(function(resolve, reject){ resolve('async resolve')});
其次慎玖,也可以當做普通函數(shù)使用,且不可以當做構(gòu)造函數(shù)
const print = ()=> console.log('hello world');
const obj = new print(); // error
箭頭函數(shù)沒有自己的this
閉包
特征:
1 閉包是(一種特殊的)function
2 閉包一般作為高階函數(shù)的參數(shù)或嵌套定義的function
3 閉包[調(diào)用態(tài)]捕獲(感知)所在作用域笛粘、作用域外層上下文
js世界中的閉包應(yīng)用非常廣泛
1 js最初是瀏覽器環(huán)境運行的趁怔,運行時單線程,早先異步都是通過回調(diào)函數(shù)來實現(xiàn)薪前,回調(diào)函數(shù)即最常見的閉包運用場景
request("baidu.com", function(err, response){
if (err){
throw "bad request";
}
console.log(response.status)
})
2 給DOM元素注冊監(jiān)聽函數(shù)
// 這里是 ctx let someVar = ...
document.addEventListener("foo", event => { // 在 document 上綁定 foo 事件的監(jiān)聽函數(shù)
event.preventDefault()
// do something ...
}
}
應(yīng)用:
// 模擬私有變量
function makeIncrement(){
let __somePrivate = 1; // 此變量外界無法干預(yù)
return function(){
// 有內(nèi)存泄漏嫌疑
return __somePrivate++; // 注意前后綴++運算符區(qū)別
}
}
let incementer = makeIncrement();
let count = incrementer(); // 1
count = incrementer(); // 2
語法迷思
js有很多操作其實都是反直覺的
原型鏈
如果用傳統(tǒng)面向?qū)ο笳Z言類比润努,那么原型鏈是類與類之間的關(guān)系,此處需要區(qū)別類 和實例
領(lǐng)域關(guān)鍵字
arguments
this:
傳統(tǒng)面向?qū)ο笳Z言中的this
class MyObj{
constructor(name: string){ // 構(gòu)造器
this.name = name;
}
say(){
console.log(`my name is ${this.name}`);
}
}
let obj = new MyObj("xiao zhang");
obj.say();
bind示括、call铺浇、apply
slice、substr垛膝、substring
this解謎
1 this綁定
四種綁定方式
遵循以下優(yōu)先級
new綁定 > 顯式綁定 > 隱式綁定 > 默認綁定
new
function A(){
this.a = "a";
}
let a = new A();
顯式
function Greeting(){
this.name = 'zhansan';
this.greeting = function(){
console.log(`hello ${this.name}`)
}
}
const obj = {name : "wangwu"};
new Greeting().greeting.call(obj);
隱式
const obj = {
name: 'zhangsan',
greeting: function(){
console.log(`hello ${this.name}`)
}
}
obj.greeting();
const obj2 = {name:"aaa"};
obj2.hello = obj.greeting;
obj2.hello();
默認
其他方式都算做默認綁定
2 箭頭函數(shù)this
1 不準確的說法
箭頭函數(shù)指向外層
箭頭函數(shù)this始終不變
let obj = {
a: ()=> console.log(this),
};
obj.a();
obj = function(){
this.a = ()=> console.log(this);
}
new obj().a();
obj = {
a: {
b: ()=> console.log(this),
},
};
obj.a.b();
obj = {
a: function(){
return ()=> console.log(this);
},
};
obj.a()();
// 箭頭函數(shù)this始終指向外層【函數(shù)】所綁定的作用域
// 箭頭函數(shù)this始終不變 是錯誤的說法
let b = {b:"b"};
b.a = obj.a;
b.a()();
obj = {
a: function(){
this.hello = 'world';
this.b = ()=> console.log(this);
},
};
new obj.a().b();
3 規(guī)則
this的值在函數(shù)被調(diào)用的時候才會指定
應(yīng)用解答
前置知識
var關(guān)鍵字
1 掛載到window對象
2 變量不經(jīng)申明也掛載到window對象下
坑點: 全局變量污染
function b(){
c = 18;
}
b();
console.log(c);
3 沒有塊級別作用域
if (true){
var hello = 'world';
}
console.log(hello);
var和let區(qū)別
1 不掛載window
2 有塊級別作用域
var number = 5;
var obj = {
number: 3,
fn1: (function () {
var number; // undefined
this.number *= 2; // 10
number = number * 2; // NaN
number = 3; // bibao.number = 3
return function () {
// this == obj
var num = this.number; // num = 10 鳍侣、3
this.number *= 2; // this.number = 20 、6
console.log(num); // print 10 3
number *= 3; // bibao.number = 9 吼拥、27
console.log(number); //print 9 27
}
})()
}
var fn1 = obj.fn1;
fn1.call(null); // window.fn1()
obj.fn1();
console.log(window.number); // 20
Promise API
| 天不生ES6 JS萬古如長夜
Promise 是異步編程的一種解決方案倚聚,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大。
構(gòu)造函數(shù)
// 主意構(gòu)造方法 比較獨特
const myPromise = new Promise((resolve, reject)=>{
if (// 異步操作成功) resolve('success');
reject('error');
})
// then 方法接收兩個函數(shù) 分別是成功和失敗的處理
myPromise.then(()=> console.log('hello world'))
此時 myPromise
是一個thenable 對象, 且通過then方法返回的也是 promise對象
特點
對象的狀態(tài)不受外界影響凿可。Promise對象代表一個異步操作秉沼,有三種狀態(tài):pending
(進行中)、fulfilled
(已成功)和rejected
(已失斂蠼汀)。
一旦狀態(tài)改變矗积,就不會再變全肮,任何時候都可以得到這個結(jié)果。
實例方法
所有promise 對象的實例方法均會返回promise對象棘捣,從而可以形成調(diào)用鏈
const obj = new Promise(function(reslove, reject){
// do somthing
resolve();
})
obj.then(()=> consolt.log('hello world')).
catch(e=> console.log(e)).finally(()=>console.log('over'));
// then 方法接收兩個參數(shù)
obj.then((rst)=>console.log('success with result ', rst),
err => console.log(err)
)
// catch 是 then(null, rejection)的快捷方式 一般推薦catch方式處理失敗情況
obj.then((rst)=>console.log('success with result ', rst)).
catch(err => console.log(err));
// catch 可以處理 構(gòu)造函數(shù)里 reject 拋出的錯誤
// 也可以處理 resolve或 then 里通用代碼拋出的異常
obj.then(()=>{
throw new Error('err')
}).catch((e)=>console.log(`catch error ${e}`));
// 此時如果沒有catch 的話則會拋出運行時異常
靜態(tài)方法
Promsie.all
const p = Promise.all([p1, p2, p3]);
Promise.all()方法接受一個數(shù)組作為參數(shù)辜腺,p1、p2乍恐、p3都是 Promise 實例评疗,如果不是,就會先調(diào)用下面講到的Promise.resolve方法茵烈,將參數(shù)轉(zhuǎn)為 Promise 實例百匆,再進一步處理。另外呜投,Promise.all()方法的參數(shù)可以不是數(shù)組加匈,但必須具有 Iterator 接口存璃,且返回的每個成員都是 Promise 實例。
p的狀態(tài)由p1雕拼、p2纵东、p3決定,分成兩種情況啥寇。(1)只有p1偎球、p2、p3的狀態(tài)都變成fulfilled辑甜,p的狀態(tài)才會變成fulfilled衰絮,此時p1、p2栈戳、p3的返回值組成一個數(shù)組岂傲,傳遞給p的回調(diào)函數(shù)。(2)只要p1子檀、p2镊掖、p3之中有一個被rejected,p的狀態(tài)就變成rejected褂痰,此時第一個被reject的實例的返回值亩进,會傳遞給p的回調(diào)函數(shù)。
Promise.race
Promise.allSettled
Promise.resolve
Promise.resolve('foo')
// 等價于
new Promise(resolve => resolve('foo'))
// resolve方法相當于一個快捷方式
resolve的參數(shù):
1 promise對象則原封不動返回
2 thenable 對象則立即執(zhí)行then方法然后返回結(jié)果對象的promise包裝
3 其他則包裝參數(shù)中內(nèi)容為 resolve狀態(tài)的promise對象
何謂thenable
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};