本科時被一個笑話笑的肚子疼逃魄,問哪一句話會立即在互聯(lián)網(wǎng)論壇里掀起腥風(fēng)血雨挽铁。
答:PHP 是全世界最好用的語言
怎么會是 PHP 呢薪介,一定是 Javascript祠饺,即可前端,也可服務(wù)器汁政。
玩笑歸玩笑道偷。我個人最喜歡的語言是 Javascript,不是我真覺得它有多好记劈,而是我最熟悉的就是它了勺鸦,愛一行才能干一行嘛。因為最近用 Framer 做前端動效目木,發(fā)現(xiàn)制作難的效果需要更深層的理解面向?qū)ο缶幊袒煌尽6?Framer 的代碼是 Coffeescript, Coffeescript 又是由 Javascript 改編而來的。所以決定啃下 JS 面向?qū)ο缶幊踢@塊硬骨頭刽射,向自己從前的面向過程編程說 Bye Bye.
正題军拟,我是看 Udacity 的視頻教程學(xué)習(xí)的,文末有視頻鏈接誓禁,部分內(nèi)容包涵個人理解懈息,理解有誤之處還請指正。
Scope
JS 的作用域有兩種摹恰,第一種是全局作用域 Global辫继,第二種是函數(shù)作用域 Function. 全局作用域在代碼執(zhí)行過程中一直存在阁最,函數(shù)作用域在函數(shù)執(zhí)行完之后消亡。
二者在層級關(guān)系上有著嵌套的關(guān)系骇两,Global 嵌套著 Function速种,當(dāng)代碼執(zhí)行時,從最底層 Scope 逐層往上搜尋變量低千。
Closures
閉包配阵,我的理解是,在 Function 執(zhí)行后示血,依然能夠調(diào)用 Function 中的變量棋傍。即局部作用域的內(nèi)容再執(zhí)行后,沒有被銷毀难审,依然可以被調(diào)用瘫拣。
有 2 種方式可以實現(xiàn)閉包:
1.return
function Car(){
var price = 3000;
return function(){
return price;
};
}
var obj = Car();
# Car 函數(shù)中的 price 仍然被調(diào)用了,沒有被銷毀
console.log(obj());
2.將其賦值給全局變量
var obj =[];
function Car(){
var price = 3000;
obj.push(price);
}
Car();
# Car 函數(shù)中的 price 仍然被調(diào)用了告喊,沒有被銷毀
console.log(obj[0]);
This
JS 的 this 變量以前一直讓我很困惑麸拄,不是很清楚怎么使用。今天終于弄清楚了黔姜,個人總結(jié)的一句話是
this 指向的是代碼執(zhí)行時的執(zhí)行環(huán)境
比如:
var method = 2;
var obj = {
method: 1,
outputMethod: function(){
console.log(this.method);
}
}
# 輸出的結(jié)果是 1
obj.outputMethod();
簡單的說拢切,this 指向的是.
左邊的對象,如果.
左邊為空秆吵,則指向 Global. 有一個例外淮椰,就是 new
, new
會創(chuàng)建一個完全新的對象,this 指向該全新的對象纳寂,并返回該對象主穗。如下:
var Car = function(p1){
# this = Object.create();
this.p1 = p1;
# return this;
}
# this 指向 Car 類的實例 ford
var ford = new Car('1');
Prototype chains
原型鏈?zhǔn)?JS 一個很有特色的機(jī)制,一個對象可以引用其上層對象的屬性和方法毙芜。這樣可以讓把重復(fù)的內(nèi)容寫在同一個 prototype 里面忽媒,節(jié)省存儲空間。
var man = {gender: 'male'}
# boy 可以引用 man 的屬性
var boy = Object.create(man);
# man 的上層對象是 Object, 因此還可以調(diào)用其 toString() 方法
boy.toString();
Object decorator pattern
寫代碼注意其可復(fù)用性爷肝,盡量寫完代碼后猾浦,審查一下是否可以有優(yōu)化的空間,將相同的代碼提取并合并灯抛,方便以后修改金赦。
var man1 = {age:0};
man1.age++;
var man2 = {age:0}
man2.age++;
# man 作為一個有 age 的對象,可以提取出來对嚼。其次夹抗,age++ 這個操作可以提出出來單獨成為一個函數(shù)。上述代碼可以轉(zhuǎn)成如下纵竖。
var man = function(obj, age){
var obj = obj;
obj.age = age;
obj.agePlus = function(){
obj.age++;
}
return obj;
}
var man1 = man({}, 0);
man1.agePlus();
var man2 = man({}, 0);
man2.agePlus();
代碼量小的時候漠烧,可能看不出來優(yōu)勢杏愤。但是當(dāng)代碼量大的,提升的效率是幾何級的了已脓。設(shè)計師可以把這種提取看作是 Symbol 控件的整合珊楼。當(dāng)你需要把頁面中的 100 個相同按鈕改變樣式的時候,沒有定義 Symbol 的你可能眼角會流下淚水吧度液。
Functional classes
JS 中厕宗,在我理解,所有內(nèi)容本質(zhì)上對象堕担,這樣一來已慢,函數(shù)本身也是對象。因此可以把具有特性的函數(shù)進(jìn)一步優(yōu)化霹购,成為具有一個特定功能的類佑惠,Class.
# 類首字母一般大寫
var Man = function(age){
var obj = {age: age};
obj.agePlus = function(){
obj.age++;
}
return obj;
}
var man1 = man(0);
man1.agePlus();
var man2 = man(0);
man2.agePlus();
此時 Man 函數(shù)就成了一個類,具有 age 屬性齐疙。當(dāng)然你可以擴(kuò)展它膜楷,讓其擁有更多的屬性和方法。
Prototypal classes
由于很多人使用函數(shù)來定義類剂碴,為了優(yōu)化人們的操作把将,JS 官方給了 new
方法轻专,用于省去人們創(chuàng)建對象忆矛,會返回對象的操作。
# 類首字母一般大寫
var Man = function(age){
# 不需要了
# var obj = {age: age};
# this 指向的 Man 每次創(chuàng)建的實例 instance
this.obj = obj;
obj.agePlus = function(){
obj.age++;
}
# 不需要了
# return obj;
}
var man1 = new man(0);
man1.agePlus();
var man2 = new man(0);
man2.agePlus();
Pseudoclassical patterns
偽類模式提出了 Prototype 的概念请垛,起用于存儲公共方法催训,節(jié)省內(nèi)存空間,也是 JS 一個特性宗收,也便于對 JS 類的擴(kuò)展漫拭。
為了減少用戶的工作量,JS 定義了 prototype混稽, 用于存儲這里 Car.methods. 我的理解是采驻,把 prototype 想成一個單獨的對象,類通過 prototype 調(diào)用其方法匈勋,prototype 通過 constructor 查詢其構(gòu)造函數(shù)礼旅。二者沒有代理關(guān)系。但是通過 Class 創(chuàng)建的 instance 和 prototype 是代理關(guān)系洽洁,并可以直接調(diào)用其方法痘系。
# Function 版本
var Car = function(price){
# obj 繼承了 Car.methods 的所有方法
var obj = Object.create(Car.method);
this.price = price;
return obj;
}
# 定義公共方法
var Car.methods = {
showPrice: function(){
console.log(this.price);
}
}
var ford = new Car(1);
ford.showPrice();
# 下面是 prototype 版本
var Car = function(price){
# 不用了
# var obj = Object.create(Car.method);
this.price = price;
# 不用了
# return obj;
}
# 定義公共方法
var Car.prototype.methods = {
showPrice: function(){
console.log(this.price);
}
}
var ford = new Car(1);
ford.showPrice();
Pseudoclassical subclasses
有的時候人們會想定義幾個具有功能屬性的類,但是又不想重復(fù)類之間的屬性饿自。這時便有了父類汰翠,子類龄坪,繼承的編碼思想出現(xiàn)了。好比复唤,喜羊羊和灰太狼都是動物健田,它們有公共的屬性,可以設(shè)置在父類里佛纫,還可以添加一個共有的顯示價格方法, 但是它們也有各自獨特的屬性抄课。
# 定義父類
var Animal = function(price){
this.type = 'animal';
this.price = price;
}
# 定義父類方法
Animal.prototype.showPrice = function(){
console.log(this.price);
}
#定義子類
# 繼承父類的屬性, 同時繼承父類的屬性
var Chicken = function(price, wings){
# call()函數(shù)將 Animal.price 的執(zhí)行環(huán)境改成 this, 由于 this 指向 Chicken 的實例,
# 因此 Chicken 實例就繼承了 Animal 的屬性
Animal.call(this, price);
# 定義子類屬性雳旅,雞是有翅膀的
wings = true;
}
# 繼承父類的方法
# 把 Chicken.prototype 指向 Animal.prototype
# 從而 Chicken 的實例可以調(diào)用 Animal.prototype 的方法跟磨,真的膜拜 JS 發(fā)明人
Chicken.prototype = Object.create(Animal.prototype);
var chicken1 = new Chicken(10)
chicken1.showPrice();
總結(jié)
明確這些概念,以及這些概念背后的原因攒盈,對我下一步的學(xué)習(xí)有著很大的裨益抵拘。以前我覺得我看不懂的東西,耐心的思考一下型豁,是可以看懂的僵蛛。世上無難事,只怕有心人嘛迎变。
下一步打算把教程后面的游戲 Project 給完成充尉,用實戰(zhàn)再次強(qiáng)化自己編程能力,最后用 Framer 把游戲再轉(zhuǎn)到 Framer 平臺上衣形。自己畫圖驼侠,把游戲界面再做漂亮點。
希望一起練習(xí)的同學(xué)請和我聯(lián)系谆吴,共同進(jìn)步倒源。