1.什么是vue
Vue.js(讀音 /vjuː/, 類似於 view) 是一套構建用戶界面的 漸進式框架。與其他重量級框架不同的是,Vue 采用自底向上增量開發的設計。Vue 的核心庫只關注視圖層,並且非常容易學習
,非常容易與其它庫或已有項目整合。另一方面,Vue 完全有能力驅動采用單文件組件和 Vue 生態系統支持的庫開發的復雜單頁應用。其實說白了Vue.js就是一個用於搭建類似於網頁版知乎這種
表單項繁多,且內容需要根據用戶的操作進行修改的網頁版應用。
Vue.js 的目標是通過盡可能簡單的 API 實現響應的數據綁定和組合的視圖組件。
Vue.js 自身不是一個全能框架——它只聚焦於視圖層。因此它非常容易學習,非常容易與其它庫或已有項目整合。另一方面,在與相關工具和支持庫一起使用時,Vue.js 也能完美地驅動復雜的單
頁應用。
Vue是一個數據驅動頁面的一個框架,基於MVVM模式,M指的是數據,V值得是視圖,VM是視圖模型,將數據綁定視圖上(雙向綁定)
這個框架着重於VM部分
2.VUE誕生的背景
近幾年來,得益於手機設備的普及和性能的提升,移動端的web需求大量增加,產生了一種叫webapp的東西,也就是移動端的網頁應用。
它們功能越來越復雜,交互也越來越酷炫,功能與效果越來越接近於原生的APP。比如下面這些:
(效果直逼原生APP)
這種webapp它們不僅僅像h5營銷網頁一樣有酷炫的效果,它們還有復雜的點擊、輸入、下拉選擇,視圖切換等復雜的交互。在這樣的業務需求下,我們還是沿用PC端的開發方案,難免會不太合適。比如:視圖切換。
在PC端,視圖切換我們會用<a>標簽進行頁面的跳轉,但如果在移動端,那就歇菜了,你會遇到這樣的畫面:
(等到花兒都謝了)
這個時候用戶只能等.....3秒,5秒,8秒.......很難想象,在一個需要頻繁切換視圖的webapp里面,使用<a>標簽去實現,對用戶來說是很不友好的,換你你也不願意等那么久,反正我是不願意了....
此外,接收用戶輸入的同時,很可能要及時更新視圖,比如用戶輸入不同的內容,頁面就會相對應進行更新,點擊不同的選項,就會顯示不同的狀態等等交互效果。一旦這種交互多了,你要手動地進行操作,代碼就容易變得復雜和難以維護。
為了解決webapp這些的體驗和開發上的不足,我們決定學習並使用一個MVVM框架——Vue.js
2.什么是MVVM
MVVM可以拆分成:View --- ViewModel --- Model三部分 ,看下面的視圖:
那么,我們怎么理解MVVM呢?
上圖中,左側的View相當於我們的DOM內容,我們所看到的頁面視圖,右側的Model相當於我們的數據對象,比如一個對象的信息:
{ name:'張三', age:30 }
而中間的監控者就負責監控兩側的數據,並相對應地通知另一側進行修改。比如:你在Model層中修改了name的值為:“李四”,那么View視圖層顯示的“張三”也會自動變成了“李四”,而這個過程就是有ViewModel來操作的,不需要你手動地去寫代碼去實現(你不用再手動操作DOM了)。
如果你寫過復雜的DOM操作,你就可以感受到它帶來的便利。
這就是MVVM框架,屬於MVVM的JS框架除了Vue.js,還有React.js,Angular.js。
3.Vue.js的優點
(1) 簡潔 (2) 輕量 (3)快速 (4) 數據驅動 (5) 模塊友好 (6) 組件化Vue
vue技術雙向綁定原理使我們開發頁面更簡單,比如我們以前用源生js開發頁面時候,書寫復雜可讀性差,后來用jquery開發頁面業務邏輯重復,可復用差,Vue通過數據雙向綁定是這一一切變得更簡單
Eg:(改變值)
Js:
<div></div>
document.getElementsByTagName(‘div‘)[0].innerHTML = ‘韓國‘;
document.getElementsByTagName(‘div‘)[0].innerHTML = ‘中國‘
Jq
<div></div>
$(‘div‘).html(‘韓國‘)
$(‘div‘).html(‘中國‘)
Vue
Vue只提供一個Api就是Vue,它是類,我們要想獲取Vue實例化對象,只能通過new關鍵字創建
通過el定義一個Vue視圖的容器元素,可以傳遞css選擇器,id選擇,類選擇器,元素名稱選擇器等等
頁面中有多個符合條件選擇器,vue只會捕獲第一個符合條件的選擇器對應的元素選擇器
實現了將視圖到視圖模型的綁定
<div>{{msg}}</div>
var data = {
msg: ‘韓國‘
}
new Vue({
el: ‘div‘,
data: data
})
data.msg = ‘中國‘
通過data屬性可以為Vue實例化對象添加屬性,添加的屬性與外部的data中的數據是同步的
不論是修改外部data中的數據還是修改Vue實例化對象中的數據,他們的數據始終同步的
數據綁定實現了將模型到視圖模型的綁定
var data = {
msg: ‘國‘,
obj: {
color: ‘red‘
}
}
var app = new Vue({
el: ‘#app‘,
data: data
})
console.log(data.msg === app.msg) //true
console.log(app.obj === data.obj) //true
// data.msg = ‘下周‘
4.Vue.js的兩大核心
鋪墊了這么多,終於講到了Vue的核心。
那么,我們就來認識一下Vue.js,這里摘取一段官網對它的介紹:
通過盡可能簡單的API實現響應的數據綁定和組合的視圖組件
這句話有兩個關鍵詞:數據綁定和視圖組件。
Vue的數據驅動:數據改變驅動了視圖的自動更新,傳統的做法你得手動改變DOM來改變視圖,vuejs只需要改變數據,就會自動改變視圖,一個字:爽。再也不用你去操心DOM的更新了,這就是MVVM思想的實現。
視圖組件化:把整一個網頁的拆分成一個個區塊,每個區塊我們可以看作成一個組件。網頁由多個組件拼接或者嵌套組成。看下圖:
具體在開發過程中怎樣實現一個組件,到底哪些區塊可以划分成一個組件,后面的章節我們再一一介紹,這里你只需要知道,在Vue.js中,網頁是可以看成多個組件組成的即可。
5.Vue.js的適用場景
如果你還在用jquery頻繁操作你的DOM來更新頁面的話,那么,你可以用Vue.js來解放你的DOM操作了。
如果你的項目中有多個部分是相同的,並可以封裝成一個組件,那么,你可以試試用Vue.js。
此外,Vue.js的核心實現中使用了ES5的Object.defineProperty特性,IE8及以下版本瀏覽器是不兼容的,所以,你的項目需要兼容這些較低版本的瀏覽器的話,那么,Vue.js就不適用了。
畢竟,開發一個項目的目的不是為了使用某個框架。
6.VUE.js安裝
我們可以在 Vue.js 的官網上直接下載 vue.min.js 並用 <script> 標簽引入。
下載好以后,將文件保存到制定位置使用時直接引入即可
我們能發現,引入vue.js文件之后,Vue被注冊為一個全局的變量,它是一個構造函數。
7.相關學習准備
ES5和ES6
說到ES的時候順嘴說一下JavaScript
JavaScript一種動態類型、弱類型、基於原型的客戶端腳本語言,用來給HTML網頁增加動態功能。(好吧,概念什么最討厭了)
動態:
在運行時確定數據類型。變量使用之前不需要類型聲明,通常變量的類型是被賦值的那個值的類型。
弱類:
計算時可以不同類型之間對使用者透明地隱式轉換,即使類型不正確,也能通過隱式轉換來得到正確的類型。
原型:
新對象繼承對象(作為模版),將自身的屬性共享給新對象,模版對象稱為原型。這樣新對象實例化后不但可以享有自己創建時和運行時定義的屬性,而且可以享有原型對象的屬性。
PS:新對象指函數,模版對象是實例對象,實例對象是不能繼承原型的,函數才可以的。
JavaScript由三部分組成:
1. ECMAScript(核心)
作為核心,它規定了語言的組成部分:語法、類型、語句、關鍵字、保留字、操作符、對象
PS:*不完全兼容的實現
2. DOM(文檔對象模型)
DOM把整個頁面映射為一個多層節點結果,開發人員可借助DOM提供的API,輕松地刪除、添加、替換或修改任何節點。
PS:DOM也有級別,分為DOM1、DOM2、DOM3,拓展不少規范和新接口。
3. BOM (瀏覽器對象模型)
支持可以訪問和操作瀏覽器窗口的瀏覽器對象模型,開發人員可以控制瀏覽器顯示的頁面以外的部分。
PS:BOM未形成規范
什么是ES5
作為ECMAScript第五個版本(第四版因為過於復雜廢棄了),瀏覽器支持情況可看第一副圖,增加特性如下。
1. strict模式
嚴格模式,限制一些用法,'use strict';
2. Array增加方法
增加了every、some 、forEach、filter 、indexOf、lastIndexOf、isArray、map、reduce、reduceRight方法
PS: 還有其他方法 Function.prototype.bind、String.prototype.trim、Date.now
3. Object方法
什么是ES6
ECMAScript6在保證向下兼容的前提下,提供大量新特性,目前瀏覽器兼容情況如下:
ES6特性如下:
1.塊級作用域 關鍵字let, 常量const
2.對象字面量的屬性賦值簡寫(property value shorthand)
var obj = { // __proto__ __proto__: theProtoObj, // Shorthand for ‘handler: handler’ handler, // Method definitions toString() { // Super calls return "d " + super.toString(); }, // Computed (dynamic) property names [ 'prop_' + (() => 42)() ]: 42 };
3.賦值解構
let singer = { first: "Bob", last: "Dylan" }; let { first: f, last: l } = singer; // 相當於 f = "Bob", l = "Dylan" let [all, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec("2015-10-25"); let [x, y] = [1, 2, 3]; // x = 1, y = 2
4.函數參數 - 默認值、參數打包、 數組展開(Default 、Rest 、Spread)
//Default function findArtist(name='lu', age='26') { ... } //Rest function f(x, ...y) { // y is an Array return x * y.length; } f(3, "hello", true) == 6 //Spread function f(x, y, z) { return x + y + z; } // Pass each elem of array as argument f(...[1,2,3]) == 6
5.箭頭函數 Arrow functions
(1).簡化了代碼形式,默認return表達式結果。
(2).自動綁定語義this,即定義函數時的this。如上面例子中,forEach的匿名函數參數中用到的this。
6.字符串模板 Template strings
var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // return "Hello Bob, how are you today?"
7. Iterators(迭代器)+ for..of
迭代器有個next方法,調用會返回:
(1).返回迭代對象的一個元素:{ done: false, value: elem }
(2).如果已到迭代對象的末端:{ done: true, value: retVal }
for (var n of ['a','b','c']) { console.log(n); } // 打印a、b、c
8.生成器 (Generators)
9.Class
Class,有constructor、extends、super,但本質上是語法糖(對語言的功能並沒有影響,但是更方便程序員使用)。
class Artist { constructor(name) { this.name = name; } perform() { return this.name + " performs "; } } class Singer extends Artist { constructor(name, song) { super.constructor(name); this.song = song; } perform() { return super.perform() + "[" + this.song + "]"; } } let james = new Singer("Etta James", "At last"); james instanceof Artist; // true james instanceof Singer; // true james.perform(); // "Etta James performs [At last]"
10.Modules
ES6的內置模塊功能借鑒了CommonJS和AMD各自的優點:
(1).具有CommonJS的精簡語法、唯一導出出口(single exports)和循環依賴(cyclic dependencies)的特點。
(2).類似AMD,支持異步加載和可配置的模塊加載。
// lib/math.js export function sum(x, y) { return x + y; } export var pi = 3.141593; // app.js import * as math from "lib/math"; alert("2π = " + math.sum(math.pi, math.pi)); // otherApp.js import {sum, pi} from "lib/math"; alert("2π = " + sum(pi, pi)); Module Loaders: // Dynamic loading – ‘System’ is default loader System.import('lib/math').then(function(m) { alert("2π = " + m.sum(m.pi, m.pi)); }); // Directly manipulate module cache System.get('jquery'); System.set('jquery', Module({$: $})); // WARNING: not yet finalized
11.Map + Set + WeakMap + WeakSet
四種集合類型,WeakMap、WeakSet作為屬性鍵的對象如果沒有別的變量在引用它們,則會被回收釋放掉。
// Sets var s = new Set(); s.add("hello").add("goodbye").add("hello"); s.size === 2; s.has("hello") === true; // Maps var m = new Map(); m.set("hello", 42); m.set(s, 34); m.get(s) == 34; //WeakMap var wm = new WeakMap(); wm.set(s, { extra: 42 }); wm.size === undefined // Weak Sets var ws = new WeakSet(); ws.add({ data: 42 });//Because the added object has no other references, it will not be held in the set
12.Math + Number + String + Array + Object APIs
一些新的API
Number.EPSILON Number.isInteger(Infinity) // false Number.isNaN("NaN") // false Math.acosh(3) // 1.762747174039086 Math.hypot(3, 4) // 5 Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2 "abcde".includes("cd") // true "abc".repeat(3) // "abcabcabc" Array.from(document.querySelectorAll('*')) // Returns a real Array Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior [0, 0, 0].fill(7, 1) // [0,7,7] [1, 2, 3].find(x => x == 3) // 3 [1, 2, 3].findIndex(x => x == 2) // 1 [1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2] ["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"] ["a", "b", "c"].keys() // iterator 0, 1, 2 ["a", "b", "c"].values() // iterator "a", "b", "c" Object.assign(Point, { origin: new Point(0,0) })
13. Proxies
使用代理(Proxy)監聽對象的操作,然后可以做一些相應事情。
var target = {}; var handler = { get: function (receiver, name) { return `Hello, ${name}!`; } }; var p = new Proxy(target, handler); p.world === 'Hello, world!';
可監聽的操作: get、set、has、deleteProperty、apply、construct、getOwnPropertyDescriptor、defineProperty、getPrototypeOf、setPrototypeOf、enumerate、ownKeys、preventExtensions、isExtensible。
14.Symbols
Symbol是一種基本類型。Symbol 通過調用symbol函數產生,它接收一個可選的名字參數,該函數返回的symbol是唯一的。
var key = Symbol("key"); var key2 = Symbol("key"); key == key2 //false
15.Promises
Promises是處理異步操作的對象,使用了 Promise 對象之后可以用一種鏈式調用的方式來組織代碼,讓代碼更加直觀(類似jQuery的deferred 對象)。
function fakeAjax(url) { return new Promise(function (resolve, reject) { // setTimeouts are for effect, typically we would handle XHR if (!url) { return setTimeout(reject, 1000); } return setTimeout(resolve, 1000); }); } // no url, promise rejected fakeAjax().then(function () { console.log('success'); },function () { console.log('fail'); });
ES6簡單語法
****VUE相關編輯工具:Sublime text3****
let和const
es6新增了let命令,用來聲明變量。它的用法類似於var,但是所聲明的變量,只在let命令所在的代碼塊內有效。
上面代碼在代碼塊之中,分別用let
和var
聲明了兩個變量。然后在代碼塊之外調用這兩個變量,結果let
聲明的變量報錯,var
聲明的變量返回了正確的值。這表明,let
聲明的變量只在它所在的代碼塊有效
<script type='text/javascript' src='vue.min.js'></script>
<script type='text/javascript'> { //let聲明的變量是塊兒級作用域且使用let不能重復聲明變量 let a = 12; // 正確 } console.log(a); { let a = 10; // 錯誤,不可以重復聲明同一個變量 } console.log(a); // 報錯:Identifier 'a' has already been declared
</script>
下面我們來看一下var和let有什么區別
1 var a = []; 2 for (var i = 0; i < 10; i++) { 3 a[i] = function () { 4 console.log(i); 5 }; 6 } 7 a[6]();
上面代碼中,變量i
是var
命令聲明的,在全局范圍內都有效,所以全局只有一個變量i
。每一次循環,變量i
的值都會發生改變,而循環內被賦給數組a
的函數內部的console.log(i)
,里面的i
指向的就是全局的i
。也就是說,所有數組a
的成員里面的i
,指向的都是同一個i
,導致運行時輸出的是最后一輪的i
的值,也就是 10
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6]();
上面代碼中,變量i
是let
聲明的,當前的i
只在本輪循環有效,所以每一次循環的i
其實都是一個新的變量,所以最后輸出的是6
。你可能會問,如果每一輪循環的變量i
都是重新聲明的,那它怎么知道上一輪循環的值,從而計算出本輪循環的值?這是因為 JavaScript 引擎內部會記住上一輪循環的值,初始化本輪的變量i
時,就在上一輪循環的基礎上進行計算
不存在變量提升
var
命令會發生”變量提升“現象,即變量可以在聲明之前使用,值為undefined
。這種現象多多少少是有些奇怪的,按照一般的邏輯,變量應該在聲明語句之后才可以使用。
為了糾正這種現象,let
命令改變了語法行為,它所聲明的變量一定要在聲明后使用,否則報錯。
// var 的情況 console.log(foo); // 輸出undefined var foo = 2; // let 的情況 console.log(bar); // 報錯ReferenceError let bar = 2;
上面代碼中,變量foo
用var
命令聲明,會發生變量提升,即腳本開始運行時,變量foo
已經存在了,但是沒有值,所以會輸出undefined
。變量bar
用let
命令聲明,不會發生變量提升。這表示在聲明它之前,變量bar
是不存在的,這時如果用到它,就會拋出一個錯誤。
不允許重復聲明
let
不允許在相同作用域內,重復聲明同一個變量。
// 報錯 function func() { let a = 10; var a = 1; } // 報錯 function func() { let a = 10; let a = 1; }
因此,不能在函數內部重新聲明參數
function func(arg) { let arg; // 報錯 } function func(arg) { { let arg; // 不報錯 } }
為什么需要塊級作用域?
ES5 只有全局作用域和函數作用域,沒有塊級作用域,這帶來很多不合理的場景。
第一種場景,內層變量可能會覆蓋外層變量。
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
上面代碼的原意是,if
代碼塊的外部使用外層的tmp
變量,內部使用內層的tmp
變量。但是,函數f
執行后,輸出結果為undefined
,原因在於變量提升,導致內層的tmp
變量覆蓋了外層的tmp
變量。
第二種場景,用來計數的循環變量泄露為全局變量。
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
上面代碼中,變量i
只用來控制循環,但是循環結束后,它並沒有消失,泄露成了全局變量。
const命令
基本語法
const
聲明一個只讀的常量。一旦聲明,常量就會初始化且常量的值就不能改變。
const PI = 3.1415; PI // 3.1415 PI = 3; // TypeError: Assignment to constant variable.
上面代碼表明改變常量的值會報錯
const
聲明的變量不得改變值,這意味着,const
一旦聲明變量,就必須立即初始化,不能留到以后賦值
const foo; // SyntaxError: Missing initializer in const declaration
上面代碼表示,對於const
來說,只聲明不賦值,就會報錯
const
的作用域與let
命令相同:只在聲明所在的塊級作用域內有效。
if (true) { const MAX = 5; } MAX // Uncaught ReferenceError: MAX is not defined
模板字符串
<script type='text/javascript' src='vue.min.js'></script> <script type='text/javascript'> var a = 1; var b = 2; var str =`哈哈${a}嘿嘿${b}`; console.log(str); //如果想要在字符串中插入變量的話,只需插入變量名即可 </script>
箭頭函數
說到函數我們肯定不會感到陌生,之前就大量的接觸到了函數我們再來回顧一下
def 函數名(形參): ''' 形參1: 形參2: return 返回值 ''' 函數體 res = 函數名(實參) print(res)
那么什么是箭頭函數呢?箭頭函數又該怎么寫呢?
基本語法:
ES6允許使用“箭頭”(=>)定義函數
var f = a = > a //等同於 var f = function(a){ return a; }
如果箭頭函數不需要參數或需要多個參數,就使用一個圓括號代表參數部分。
//無形參 var f = () => 5; // 等同於 var f = function () { return 5 }; //多個形參 var sum = (num1, num2) => num1 + num2; // 等同於 var sum = function(num1, num2) { return num1 + num2; };
使用箭頭函數注意點:
箭頭函數有幾個使用注意點。
(1)函數體內的this
對象,就是定義時所在的對象,而不是使用時所在的對象。
1 var name = '張三'; 2 var person = { 3 name:'小馬哥',
age:18, 4 fav:function(){ 5 console.log(this) 6 console.log(this.name) 7 } 8 } 9 10 person.fav();
我們發現,打印的結果為
此時this指向的是使用它的對象,也就是person對象
var person2 = { name:'小馬哥', age:18, fav: ()=>{ // 當前this指向了定義時所在的對象(window) console.log(this); } } person2.fav();
打印的結果:
使用箭頭函數,它表示定義時所在的對象window。
再看一個例子吧!
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
上面代碼中,setTimeout
的參數是一個箭頭函數,這個箭頭函數的定義生效是在foo
函數生成時,而它的真正執行要等到 100 毫秒后。如果是普通函數,執行時this
應該指向全局對象window
,這時應該輸出21
。但是,箭頭函數導致this
總是指向函數定義生效時所在的對象(本例是{id: 42}
),所以輸出的是42
。
(2)不可以使用arguments
對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。
var person3 = { name:'小馬哥', age:18, fav: ()=>{ console.log(argument); } } person3.fav('把妹','把爺');
報出如下❎:
對象的單體模式
為什么要有對象單體模式?
為了解決箭頭函數this指向的問題 推出來一種寫法 對象的單體模式
1 var person = { 2 name:'小馬哥', 3 age:12, 4 fav(){ 5 console.log(this.name,this.age); 6 } 7 } 8 person.fav();
ES6的面向對象
JavaScript 語言中,生成實例對象的傳統方法是通過構造函數。
function Animal(name,age){ this.name = name; this.age = age; } Animal.prototype.showName = function(){ console.log(this.name); console.log(this.age); } var a = new Animal('小黃',5); a.showName();
上面這種寫法跟傳統的面向對象語言(比如 C++ 和 Java)差異很大,很容易讓新學習這門語言的程序員感到困惑。
ES6 提供了更接近傳統語言的寫法,引入了 Class(類)這個概念,作為對象的模板。通過class
關鍵字,可以定義類。
基本上,ES6 的class
可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,新的class
寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。上面的代碼用 ES6 的class
改寫,就是下面這樣
class Animal{ // 構造器 當你創建實例之后 constructor()方法會立刻調用 通常這個方法初始化對象的屬性 constructor(name,age){ this.name = name; this.age = age; } showName(){ console.log(this.name); } } var a2 = new Animal('點點',3);
上面代碼定義了一個“類”,可以看到里面有一個constructor
方法,這就是構造方法,而this
關鍵字則代表實例對象。也就是說,ES5 的構造函數Animal,對應 ES6 的Animal類的構造方法。
Animal類除了構造方法,還定義了一個showName方法。注意,定義“類”的方法的時候,前面不需要加上function
這個關鍵字,直接把函數定義放進去了就可以了。另外,方法之間不需要逗號分隔,加了會報錯。
ES6 的類,完全可以看作構造函數的另一種寫法。
console.log(Animal2===Animal2.prototype.constructor);//true
上面代碼表示,類本身就指向了類的構造函數。
使用的時候,也是直接對類使用new
命令,跟構造函數的用法完全一致。
constructor方法
constructor
方法是類的默認方法,通過new
命令生成對象實例時,自動調用該方法。一個類必須有constructor
方法,如果沒有顯式定義,一個空的constructor
方法會被默認添加。
class Animal { } // 等同於 class Animal { constructor() {} }
上面代碼中,定義了一個空的類Point
,JavaScript 引擎會自動為它添加一個空的constructor
方法。
NodeJs介紹
Nodejs英文網:https://nodejs.org/en/
在這里我們會發現這樣一句話:
翻譯成中文如下:
Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境。
Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,使其輕量又高效。
Node.js 的包管理器 npm,是全球最大的開源庫生態系統。
上面的這段譯文也就說明了什么是NodeJs,當然了這只是比較官方的解釋,那么NodeJs究竟是什么呢?
什么是node?
根據官方文檔可以知道,node就是一個給予谷歌v8引擎的一個javascript的運行時,可以理解為運行js的一個虛擬機。他使用的是一個 事件驅動,非阻塞I/O模型 ,他是將js的運行環境搬到了服務器端,和客戶端沒有一點關系。是一個純服務端的東西,node只是為js提供了一個平台。node里面其實還分了兩塊,一是封裝了v8引擎,目的是為了執行es(如定義變量,定義函數等),另外一個提供了大量的工具庫,是幫助node實現各種功能的,提供了一些以前js的環境辦不到的事情,比如文件操作,網絡操作,操作系統的操作。
既然node是一個平台(所謂的平台就是用來運行特定語言的),也就意味着node是用來運行語言的,那么java也是語言,node能運行java嗎?據nodejs創始人Ryan Dahl回憶,他最初是選擇了Ruby這門語言,但是Ruby這門語言的虛擬機效率不怎么樣最終放棄了,按照這種思路,貌似node將java的虛擬機集成進來應該可以運行java,但node作者最終選擇了javascript。這樣js就實現了在服務端運行的可能,js運行在node平台上(分為v8部分,用來執行es,和大量的工具庫組件(API)稱之為libuv,提供了以前js的環境辦不到的事,如文件操作,網絡操作等等)。
知道了什么是node,應該還要清楚node在web中有什么用途?
(1)node可以接受客戶端用戶的所有請求,並且能夠快速的給出響應,因此node可以用來做網站。
(2)node可以作為一個中間層來來分發調用數據接口,比如有一個網站數據是有java提供的,我們可以讓node作為一個中間曾,來接受用戶的請求,然后通過node來調用java數據接口,獲取到數據后直接在node層面做html的瓶裝,然后將渲染好的頁面直接給用戶。為什么要這樣做,直接請求java接口不行嗎,這是因為node被稱之為高性能的web服務器,在並發和抗壓方面都比傳統的平台要好很多,因此這樣一包裝可以極大的減輕服務器的開發。
通過上面的兩點,可以總結出,node在web中要么從前端頁面到后端服務全包了,一個是只做其中的一點。
一言以蔽之,node就是一個javascript的運行環境(平台),他不是一門語言,也不是javascript的框架。可以用來開發服務端應用程序,web系統。其特點是體積小,快速,高性能。
Node中的NPM
首先我們先來了解一下什么是NPM?
簡單的說,npm就是JavaScript的包管理工具。類似Java語法中的maven,gradle,python中的pip
安裝
傻瓜式的安裝。
第一步:打開https://nodejs.org/en/
第二步:
第三步:我們為了統一版本,雖然node.js更新到了8.11.1的版本,但對於我個人而言,還是比較喜歡6.10.*版本的。
第四步:
第五步:點點點。為了避免環境變量出現額外的問題,winodows用戶將nodejs統一安裝在c盤中,mac電腦直接安裝。
npm是和Nodejs一起並存的,只要安裝了Nodejs,npm也安裝好了,安裝好Nodejs之后。打開終端,執行如下命令,檢查是否安裝成功
但是由於npm自身的更新頻率比Node.js高很多,所以通過上面安裝的npm可能不是最新版本,可以通過下面的命令單獨更新npm。在這里不簡易大家更新了。
針對mac電腦的用戶,如果執行
會出現如下錯誤;
解決方案:只需要
ok,到目前為止,我們的軟件都安裝好了。
既然我們知道npm它能夠管理我們的包,也就是我們所謂的模塊。
那么,比如在之前我們使用到的jquery框架,bootstrap框架。都可以使用npm去下載了。
安裝包
我們在桌面上創建一個文件夾/01-studyNpm。
注意:千萬不要起名成:node、npm這樣的文件夾,以免與系統軟件產生不必要的沖突。
打開終端,切換到當前創建的文件夾目錄下,一定是當前目錄。
npm 初始化
在去下載包之前,首先先讓當前項目的包進行初始化操作,執行命令:
npm init
運行這個命令后,它會詢問一些關於包的基本信息,根據實際情況回答即可。如果不喜歡這種方式,可以使用npm init --yes
命令直接使用默認的配置來創建package.json
文件,最后根據需要修改創建好的package.json
文件即可。
{ "name": "01-studynpm", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
主要字段的含義如下:
-
name: 模塊名, 模塊的名稱有如下要求:
- 全部小寫
- 只能是一個詞語,沒有空格
- 允許使用破折號和下划線作為單詞分隔符
-
version: 模塊版本信息
-
description:關於模塊功能的簡單描述,如果這個字段為空的話,默認會從當前目錄的
READMD.md
或README
文件讀取第一行內容作為它的默認值。 -
main: 模塊被引入后,首先加載的文件,默認為
index.js
。 -
scripts: 定義一些常用命令入口
關於最后一個英文的意思,我們可以證明,當我執行npm init之后,會自動的生成package.json的文件。
安裝模塊
使用npm install
會讀取package.json
文件來安裝模塊。安裝的模塊分為兩類dependencies
和devDependencies
,分別對應生產環境需要的安裝包和開發環境需要的安裝包。
同樣在安裝模塊的時候,可以通過指定參數來修改package.json文件,以jquery和webpack做例子
npm install jquery --save npm install webpack --save-dev
來將新安裝的模塊信息記錄到package.json
文件.
我們正式操作一遍,下載jquery包
npm install jquery --save
執行以上命令,便可以安裝對應的包到執行命令的當前目錄,並創建一個node_modules
的文件夾,然后把需要安裝的安裝包下載到里面。
打開package.json文件會發現:
下載不同版本的模塊
npm install jquery@2.0.1 --save
卸載模塊
npm uninstall jquery --save
使用cnpm(淘寶鏡像)
使用npm下載依賴時,由於是從國外的網站上下載內容,所以可能經常會出現不穩定的情況,所以需要下載cnpm代替npm,cnpm是國內淘寶的做的,在國內使用穩定。
1.下載cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
2.使用cpm
cnpm install jquery --save
模塊化