RomeoMo

种一棵树最好的时间是十年前,而后是现在

说明: 本文来自Varvy,作者:Patrick Sexton

文章版权属于原网站/原作者。我依旧只是个搬运工+不称职的翻译。

前不久,在微博上看到貘吃馍香在吐槽

貘大的吐槽

于是去搜索和查阅了相关资料,也做了一些复习,加上 W3C Plus 相关文章收费,因此在此做个记录。

CSSOM 是什么?

  • CSSOM 代表着 CSS Object Model
  • CSSOM 基本上是页面中 CSS 的“映射”
  • CSSOM 与 CSS 的关系类似于 DOM 之于 HTML
  • CSSOM 与 DOM 相结合使浏览器渲染页面

CSSOM

CSSOM 是页面渲染不可缺少的部分。

CSSOM 是 关键路径渲染(critical rendering path)的基础和关键,理解 CSSOM 做了什么是对页面优化(页面加载更快)的重要部分。

CSSOM 做了什么?

CSSOM 将样式表中的规则映射到页面上需要样式化的内容。

为此,CSSOM 做了许多复杂的操作,但是 CSSOM 的最终是将样式映射到这些样式需要去的地方。

(更精确的说,CSSOM 定义了令牌(token)并将其隐藏的链接到树结构的节点中。页面中节点及其样式的所有映射就是 CSS Object Mode)。

浏览器使用 CSSOM 渲染页面

为了渲染页面,浏览器必须执行一些操作。此时,我们将其简化一下并讨论四个主要步骤,这些步骤将说明 CSSOM 的重要性。

  1. 浏览器执行 HTML 并构建出 DOM(Document Object Model)。
  2. 浏览器执行 CSS 并构建出 CSSOM(CSS Object Model)。
  3. 浏览器组合 DOM 和 CSSOM 用于创建渲染树。
  4. 浏览器展示 web 页面。

如上所示,CSSOM 确实是展示 web 页面的重要部分。

好消息

为了优化 web 页面,其实你不需要了解 CSSOM 到底是如何工作的。

你只需要知道 CSSOM 的几个关键点就可以对页面进行非常实际的优化。

  1. 知道CSSOM 阻止任何东西的渲染。
  2. 知道当载入新页面时,CSSOM 需要重新构建。
  3. 知道渲染页面时,javascript 和 CSS 之间的关系。

让我们快速的了解这几点,然后为了优化页面我们能做什么。

1. CSSOM 阻止任何东西的渲染

所有 CSS 是阻塞式渲染(意味着直到 CSS 处理完成,将不会展示任何东西)。

这样做的原因是,如果在 CSS 执行之前就展现 web 页面,那你看到的 web 页面是没有样式的,然后过了一会,页面有了样式。如果这样做的话,体验是相当糟糕的。

CSS 阻塞式渲染

由于 CSSOM 用来帮助创建渲染树,如果在页面中的 CSS 不能高效的完成,那么将会产生严重的问题。

主要问题是加载 web 页面时的白屏。

2. 当载入新页面时,CSSOM 需要重新构建

对你来说,这个可能不是相当明显,但确实是非常重要的一点。

意思是尽管你的 CSS 被缓存了,并不意味着 CSSOM 是针对每个页面构建的。

用户访问其他页面时,CSSOM 必须重新进行构建(尽管浏览器可能已经缓存了所需要的所有 CSS 文件)。

换句话说,如果你的 CSS 是劣质和庞大并且编写相当糟糕的,那么在渲染页面时会带来副作用。

3. 渲染页面时,javascript 和 CSS 之间的关系

在 web 页面中使用 javascript 可能(或者说经常)会阻塞 CSSOM 的构建。

简而言之—页面展现需要 CSSOM。如果 CSSOM 没有完成,页面将不会展现任何内容。如果阻塞了 CSSOM 的构建,那么 CSSOM 将会花费更长的时间,意思是页面展现将会花费更长的时间。如果 javascript 阻塞了 CSSOM 的构建,那么用户将会花费比原本更多时间停留在空白页面。

CSSOM 的优化方法

这里有些最佳实践用于加快 CSSOM 的构建(因此页面能加载的更快)。

说明: 本文来自scotch,作者:Austin Roy

文章版权属于原网站/原作者。我依旧只是个搬运工+不称职的翻译。

什么是闭包?

如果经常写 JavaScript 代码,大概率你会遇到一个既有用又经常引起困惑的概念—闭包。但什么是闭包?

闭包是函数和声明该函数的词法环境(lexical environment)的组合。

但这到底是什么意思呢?词法环境 由函数创建时的所有局部变量组成。通过闭包,可以引用函数下的所有局部变量。这实际上是通过在一个函数中定义另一个函数来实现的,在函数中的这一函数称为闭包。一旦父函数被调用,一个包含所有局部变量的全新拷贝的执行上下文将创建。在全部变量中引用局部变量可以通过与全局变量进行链接,或者是返回父函数中的闭包。

一个简单的示例将采用与此类似的:

1
2
3
4
5
function closuredFunc (){
function closure(){
// some logic
}
}

同样也可以通过以下方式让同一闭包返回多个方法:

1
2
3
4
5
6
function closure(){
function first() { console.log('I was declared first')}
function second() { console.log('I was declared second')}
function third() { console.log('I was declared third')}
return [first, second, third]
}

为了引用这些方法,我们将闭包分配给一个全局变量,然后将其指向一组公开的方法。如下所示,每个方法分配了唯一的变量名称,以将它们带入全局范围。现在,可以调用它们了。

1
2
3
4
5
6
7
8
9
let f = closure()

let one = f[0]
let two = f[1]
let three = f[2]

one() // logs I was declared first
two() // logs I was declared second
three() // logs I was declared third

为什么使用闭包?

你可能想知道为什么要花这么多时间来写闭包。然而,闭包具有许多用途与优点。

先前介绍了 ES6 中的 Class,闭包提供了类似于面向对象编程方法用于创建类似于类的隐私方法,允许我们遍历私有方法。这个也可称为 模块模式(module pattern),其允许我们更容易的维护代码,减少命名空间污染(namespace pollution)的同时增加可重用性。

让我们看一个这样做的栗子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
};

var counter1 = makeCounter();
var counter2 = makeCounter();

counter1.value(); // returns 0
counter1.increment(); // adds 1
counter1.increment(); // adds 1
counter1.value(); // returns 2
counter1.decrement(); //subtracts 1
counter1.value(); // returns 1
counter2.value(); // returns 0

在上面的例子中, 我们定义了一个公共函数同时也可以访问一些私有变量如 privateCounter 和其中的函数的方法 makeCounter。创建 makeCounter 模仿了类的行为,其具有内置的功能和变量。这可以在创建两个不同的计数器 counter1 和counter2 时看到。每个计数器(counter)是独立于其他计数器,指向不同状态下的变量。

闭包还允许我们使用函数来创建其他函数,这些函数会为其参数添加特定的值。在这种情况下,允许这种行为的父函数被称为 函数工厂 (function factory),因为它实际上会创建其他函数。

使用函数工厂,我们实现的这样行为称为 柯里化 (Currying)。我们将在下个部分详细描述。

柯里化

柯里化是一种函数模式用于立即执行并且返回其他函数。这使得 JavaScript 函数返回其他函数的表达式成为可能。

柯里化函数通过定义并立即返回其内部函数来链接闭包来构造。

这里有柯里化的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
let greeting = function (a) {
return function (b) {
return a + ' ' + b
}
}

let hello = greeting('Hello')
let morning = greeting('Good morning')

hello('Austin') // returns Hello Austin
hello('Roy') // returns Hello Roy
morning('Austin') // returns Good morning Austin
morning('Roy') //returns Good Morning Roy

从 greeting 创建了两个函数(hello and morning),每个返回函数处理提供的输入用来生成问候语。它们还接受了一个参数用于要打招呼的人的名字。

在上面的例子中,greeting 也作为函数工厂使用,hello 和 morning 由此生成。

在第一次调用之后,还可以继续调用内部函数,如下所示:

1
2
greeting('Hello There')('General Kenobi') 
//returns Hello There General Kenobi

柯里化认为是函数式编程的一部分,同时柯里化函数在使用 ES6 的箭头函数语法和新版本的 JavaScript 时,能更容易的书写清晰,优雅的代码。

1
2
3
4
let greeting = (a) => (b) => a + ' ' + b 

greeting('Hello There')('General Kenobi')
//returns Hello There General Kenobi

总结

自从在 ES6 有了 Class,闭包可能不会经常使用,在编写清晰的可重用代码,闭包依旧占有一席之地。在本质上与面向对象编程中的私有方法具有相似用途的函数式编程中,闭包和柯里化是其重要的概念。

参考资料

  1. Closures - JavaScript | MDN
  2. A Beginner’s Guide to Currying in Functional JavaScript/中文版

Map, ForEach 及 Filter, Reduce

概念

map, foreach, 及 filter, reduce 为典型的函数式编程实践,均为高阶函数(Higher-Order Functions)。

高阶函数指的是一个函数能作为值传递到另一个函数中,或者,一个函数可以作为另一个函数的输出。

区别

  • map filter 和 reduce 均有返回值,而 forEach 是没有返回值的
  • forEach 能终止循化,而 map, filter 和 reduce 是无法终止的

map filter 和 reduce 的区别如图所示。
map, filter 和 reduce

map filter 和 reduce

map

map 是将数组的每一项通过同样的操作进行变换,得到一个新的数组,且新数组与原数组的长度是一致的。

1
2
3
4
5
6
7
var array1 = [1, 4, 9, 16];

const map1 = array1.map(x => x * 2);

console.log(map1); // 输出:[2, 8, 18, 32]

console.log(array1); // 输出: [1, 4, 9, 16]

filter

filter 是保留数组中符合条件的数据,得到一个新的数组,且新数组的长度不大于原数组的长度。

1
2
3
4
5
6
7
var array1 = [1, 4, 9, 16];

const filter1 = array1.filter(x => x > 0);

console.log(filter1); // 输出:[1, 4, 9, 16]

console.log(array1); // 输出: [1, 4, 9, 16]

reduce

reduce 是合并数组的每一项数据,最终返回一个新的数据。

1
2
3
4
5
6
7
var array1 = [1, 2, 3, 4];

const reducer = (accumulator, currentValue) => accumulator + currentValue;

console.log(array1.reduce(reducer, 5)); // 输出:10

console.log(array1); // 输出: [1, 2, 3, 4]

注意:三个例子中,原来的数组是没有发生任何改变的。

参考资料

  1. “You (Probably) Don’t Need For-Loops”

  2. “Breaking the Loop: How to use higher order functions to process arrays in JavaScript”;

  3. Higher-Order Functions

说明:这个系列来源于 Fun Fun Function 函数式编程系列视频,以《JavaScript函数式编程指南》和 《Hands-On Functional Programming with TypeScript》 等函数式书籍,加上在工作中总结的经验完成此系列。

注: 此系列文章的参考资料,是对文章的扩展及补充,请擅加利用。

总论

函数式编程是声明式编程的一种实践,声明式编程目标是将程序的描述与求值分离开来。

“To have a deep understanding of functional programs as a data transform pipeline, you need a way to define your data structures.”

(摘自 《Hands-On Functional Programming with TypeScript》 )

目录

  1. Map, ForEach 及 Filter, Reduce
  2. 纯函数(Pure Function)
  3. 闭包和柯里化

参考资料

  1. Fun Fun Function 函数式编程视频(需翻墙)
  2. 《JavaScript函数式编程指南》
  3. 《Hands-On Functional Programming with TypeScript》
  4. 《Professor Frisby’s Mostly Adequate Guide to Functional Programming》

说明: 本文来自Medium,作者:Anoop Raveendran

文章版权属于原网站/原作者。我依旧只是个搬运工+不称职的翻译。

“JavaScript 的异步和单线程是怎样实现的?”简单来说,JavaScript 是单线程的但异步并不是在 JavaScript 中实现的,而是基于浏览器中 JavaScript 内核之上实现的并且通过浏览器 APIs 进行访问。

现在我试着通过两个简单的片段详细解释事件循环。

基础结构

浏览器主要组件概述

  • 堆(Heap)—— 对象存储在堆中,堆表示了内存中一个大的非结构化的区域。
  • 栈(Stack)—— 这个表示了 JavaScript 代码执行时的单线程。函数的调用组成了栈的帧(详情见下面的描述)。
  • 浏览器或是 Web APIs 是在浏览器中实现的,能从浏览器和电脑系统得到数据并且在此基础上执行复杂的事情。这些并不属于 JavaScript 语言本身,而是基于浏览器中 JavaScript 内核之上实现的,为你在使用 JavaScript 代码提供了额外的超能力。 举个栗子🌰,地理位置定位 API 提供了一些简单的 JavaScript 方法来检索位置数据,例如在 Google Map 中标记你的位置。在其背后的实现,浏览器其实是调用了一些复杂的底层代码(比如 C++)和设备的 GPS 硬件(或是任何可以定义位置信息)来获取位置信息,返回到浏览器中并在你的 JavaScript 代码中使用。对开发者来言,这些 API 抽象了复杂度。

片段1:详细解释

现在我们有一个主函数包含了在两个 console.log 语句分别在控制台输出 “A” 和 “C”。在两者之间,有一个等待 0 毫秒的 setTimeOut 打印 “B” 的函数。

执行过程的内部实现

  1. 首先是调用主函数(作为帧)加入到栈中。随后浏览器把 console.log(‘A’) 作为第一条语句加入到栈。这条语句执行完成并且此帧弹出。于是在控制台展示了字母 “A”。
  2. 下一条语句( 回调为 exec() 且等待0毫秒,执行的setTimeout() ),推入了执行栈(call stack)并开始执行。setTimeout 函数调用的浏览器的 APIs 用于等待执行回调函数。这一帧(使用 setTimeOut)弹出并且完成交由浏览器。
  3. 当浏览器的定时器(timer)执行回调方法 exec() 时,console.log(‘C’) 加入到栈中。在特定的时候,正如延迟 0 毫秒的时候,(理想情况下)一旦浏览器收到回调,这个回调函数加入到消息队列(message queue)。
  4. 当执行完成主函数的最后一个语句时,这个 main() 函数从执行栈弹出,因此执行栈为空。浏览器从队列向执行栈传递数据时,必须执行栈为空作为前提。这就是为什么就算 setTimeout() 的等待时间为 0 毫秒,它的回调 exec() 必须等到执行栈的所有帧完成。
  5. 现在回调函数 exec() 调入到执行栈并开始执行。控制台显示字母 “C”。这就是 JavaScript 的事件循环。

所以在 setTimeout(函数,延迟时间)中的延迟参数,并不是函数延迟执行的准确时间。它代表在此之后某个时间点执行功能的最短等待时间。

片段2:深入理解

深入解释事件循环

  • runWhileLoopForNSeconds() 函数表示的和名字一致。其会不停的检查经过的时间是否等于此函数传入的第二个参数。重要的是记住 while 循环(与其他语言类似)是一个阻塞语句,意味着,它的执行是发生在执行栈中并且不会使用浏览器 APIs。所以它会阻塞后续的语句,直到完成执行。
  • 所以就上方的代码,尽管 setTimeout 只需等待 0 毫秒并且 while 循环执行 3 秒, 回调函数 exec() 语句卡在消息队列 3 秒。直到 3 秒以后 while 循环一直在执行栈中运行(单线程)。在执行栈为空之后,回调函数 exec() 才移动到执行栈并开始执行。
  • 所以 setTimeout() 的等待参数并不保证一定等于执行开始到结束的时间。它是等待部分的最短时间。

参考资料:

  1. 详解JavaScript中的Event Loop(事件循环)机制
  2. JS Event Loop(需翻墙,强烈推荐 12:50~17:20 之间的内容)
  3. JavaScript 事件循环可视化(”JS Event Loop” 演讲示例)

说明: 本文来自SitePoint,作者:M. David Green

文章版权属于原网站/原作者。我依旧只是个搬运工+不称职的翻译。

柯里化(Currying),或称为偏函数应用(Partial Application),是函数式编程中会给听起来给更熟悉传统的JavaScript编程的人带来困惑。但只要使用得当,柯里化会让你的函数式JavaScript更加易读。

更易读以及更具有扩展性

函数式JavaScript的一个显而易见的优点是代码量更少、代码内聚更高、代码更少的重复,在代码行更少的情况下,也能输出正确的结果。在不熟悉函数是编程如何实现之前,有时会多花一些时间去阅读理解代码,代码的书写也会变得难以理解。

如果你对柯里化这个词有影响,但从来不知道它的意思,你完全不用担心你曾经认为它是一种陌生或者神奇的技术。其实柯里化是一个相当简单的概念,当处理函数参数,它能处理一些常见的问题,并且为开发者开辟了更多的选择。

什么是柯里化?

简而言之,柯里化是一种允许偏函数应用作为参数组成新的函数。意味着为了获取函数结果,你可以传递函数所需要的所有参数,或者也可以传递一部分参数得到结果作为其余函数的参数。情况就是这么简单。

柯里化是如Haskell和Scala这样的函数式语言的基础。JavaScript具有函数式编写的能力,但柯里化并不实现于其中(至少在目前版本是这样的)。但我们已经知道一些函数式的方法,能让我们能在JavaScript中使用柯里化。

为了给你展现柯里化是如何实现的,我们写了JavaScript中第一个入门的柯里化函数,使用熟悉的方法创建了柯里化函数。我们想通过名字用来打招呼作为例子。我们知道如何通过创造一个简单的、包含使用名字和处理的打招呼的函数,并使用控制台打印名字。

1
2
3
4
5
var greetCurried = function(greeting) {
return function(name) {
console.log(greeting + ", " + name);
};
};

这个函数需要两个参数–名称和方式才能正常的使用。但是我们可以仅通过简单的嵌套柯里化重写此函数,使之基本函数只需要传递方式,返回一个函数用于接受我们任意传递的名称。

第一次柯里化

1
2
3
4
5
6
var greetCurried = function(greeting) {
return function(name) {
console.log(greeting + ", " + name);
};
};

这个小小的改变,让我们创建了一个可为任何类型方式的新函数,并且接受我们任意传递的名称。

1
2
3
var greetHello = greetCurried("Hello");
greetHello("Heidi"); //"Hello, Heidi"
greetHello("Eddie"); //"Hello, Eddie"

我们也可以对原始函数进行柯里化调用,只需要使用左到右的方式从传入参数的集合中分离参数。

1
greetCurried("Hi there")("Howard"); //"Hi there, Howard"

为何不在浏览器中尝试一下此代码呢?

此为JS Bin的链接

全部柯里化!

最酷的是,现在我们学习了可以使用这种方式处理参数用于改变传统函数,我们能对任意数量的参数使用此方法:

1
2
3
4
5
6
7
8
9
10
var greetDeeplyCurried = function(greeting) {
return function(separator) {
return function(emphasis) {
return function(name) {
console.log(greeting + separator + name + emphasis);
};
};
};
};

我们四个参数的函数和两个参数的函数有同样的灵活度。无论嵌套有多深,我们都可以创造出一个包含任意人数的函数来满足我们的预期:

1
2
3
var greetAwkwardly = greetDeeplyCurried("Hello")("...")("?");
greetAwkwardly("Heidi"); //"Hello...Heidi?"
greetAwkwardly("Eddie"); //"Hello...Eddie?"

此为JS Bin的链接

柯里化传统函数

你能看到这样的尝试非常强大,特别是如果你需要创造一堆具体的函数的情况下。唯一的问题在于语法。一旦写出柯里化的函数,你需要不停地嵌套返回函数,调用每个都包含自有参数变量的新函数。这样会变得相当复杂。

为了解决这个问题,创造出一个包含不用包含所有嵌套返回的现存函数名称的快速和脏的柯里化函数。一个柯里化的函数需要放出参数列表,并且使用它们用于返回原始函数的当前版本。

1
2
3
4
5
6
7
8
9
var curryIt = function(uncurried) {
var parameters = Array.prototype.slice.call(arguments, 1);
return function() {
return uncurried.apply(this, parameters.concat(
Array.prototype.slice.call(arguments, 0)
));
};
};

为了使用这个,我们设定号存放任何参数数量的函数,和我们初始设定的参数一致。然后我们获得了一个包含等待剩余参数的函数。

1
2
3
4
5
6
7
8
var greeter = function(greeting, separator, emphasis, name) {
console.log(greeting + separator + name + emphasis);
};
var greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); //"Hello, Heidi."
greetHello("Eddie"); //"Hello, Eddie."


和之前一样,我们使用从原始函数中分离出没有限制参数的函数。

1
2
3
4
5

var greetGoodbye = curryIt(greeter, "Goodbye", ", ");
greetGoodbye(".", "Joe"); //"Goodbye, Joe."


此为JS Bin的链接

开始严肃对待柯里化

我们的小柯里化函数并不包括所有情况,比如没有或者可选参数,但是它做的有意义同样严格按照语法传递参数。

以**Ramda**为代表的一些函数式JavaScript库又更灵活的柯里化方式以至于可以用来打破函数所必须的参数,并且可以让你挨个或者组团传递参数用于生成自定义的柯里化参数。如果你想更广泛的柯里化,这个可能是一种方法。

不管你在自己的程序里如何增加柯里化,无论你想使用嵌套参数或者更喜欢健壮的柯里化函数,为当前的柯里化函数提出一个组合化的名称将会让你的代码更具有可读性。每一个参数都需要一个让其具有明确行为以及期望传递的名字。

参数顺序

一个需要注意的是柯里化时参数的顺序。正如我们的描述,你显然希望参数大多数情况下是一个接着一个传递直到原始函数最后一个。

提早思考参数顺序会让你在工作中更容易的使用柯里化。并且思考参数顺序在设计函数大多数情况下都不是坏习惯。

小结

柯里化在函数式编程中是一项难以置信的有用办法。它允许你生成代码少、易于配置且运行稳定的库,同时易于使用,让你的代码更易理解。在实际代码编写时,实现柯里化会让你更容易的在代码中使用偏函数应用,避免有可能产生的重复,并且能让你在命名和处理函数参数时养成良好习惯。

传统CSS书写

存在的问题

  1. 就算加了注释,代码也很难维护
  2. 为了保证样式被覆盖,CSS的权重可能会变得非常⾼

Sass方式书写

何为Sass?

Sass是CSS的预处理程序,其思想是用一种专门的编程语言,进行网页样式设计,然后再编译成正常的CSS文件。同样也有Less,Stylus等其他预处理程序,而本人在平常中没有实践过其他预处理程序,所以在此按下不表。SCSS实现了Sass的所有功能,并且有类似于css的句法,所以在工作中,我更偏爱SCSS。

存在的问题

使用SCSS容易造成嵌套层级过多,导致 CSS 权重过高的问题。大漠在知乎上的回答写着**“别让你的嵌套层级超过四层”**,而腾讯的AlloyTeam在Code Guide上写着”嵌套最多不能超过5层“。为了减少嵌套层级,我认为解决方法为:提取公因式

提取公因式就是把相同表现类似的css用同一个class表示,而独特表现的元素单独写。要熟练使用此方法需要透彻了解css的权重。

使用Compass

在使用SCSS中,最实用的是[@mixin](http://sass-lang.com/guide#topic-6 “Mixins”), 类似于c语言中的宏,使用@mixin能大大提升写代码的效率。

在平常工作中,特别是在使用css3时需要注意浏览器前缀问题。如果不想手写 CSS3 的浏览器前缀,想让工具生成这些属性,那Compass 就是一个很好的选择。

关于Compass应该知道的知识

Compass是Sass的一种工具库(toolkit),引用阮一峰博客上的一句话:“Sass是一种”CSS预处理器”,可以让CSS的开发变得简单和可维护。但是,只有搭配Compass,它才能显出真正的威力”。

Compass主要分为七部分

  1. reset(normalize)*:重写浏览器的默认样式
  2. layout:⻚面布局
  3. CSS3:跨浏览器的CSS3**(使用最为频繁)**
  4. typography:文本样式
  5. helper:类似于Sass语法的,一系列函数,
  6. utilities:除去以上5点的其他工具,多为@mixin
  7. Browser Support:浏览器支持,直接决定了以上6点的表现

PS:reset与Normalize的区别:reset是“暴力”的重写浏览器默认样式。而Normalize分为8个部分进行重写,分别为:base, html5, links, typography, embeds, groups, forms以及tables。Normalize可以整体引入也可以分开引入。所以是使用reset还是Normalize,就看各位看官了(本人更偏向于Normalize)。

使用SCSS+Compass的总结

优点

CSS 权重尽可能低,容易修改、覆盖。加上适当注释后,更容易阅读代码
不⽤担⼼ CSS3 兼容性问题,直接配置解决

缺点

从 CSS 到 SCSS,再到 Compass, 难度逐渐增加。

**说明:**本文来自SitePoint,作者:Tim Evko

文章版权属于原网站/原作者。我依旧只是个搬运工+不称职的翻译。

Web开发者是由多种职位构成的。你可以是前端开发者,用户体验设计师,软件工程师,或者是后端开发者。如果这样说太笼统了,你也可以自称为JavaScript 专家,Bootstrap 开发者甚至是Node 明星。 在Web开发中包含着无止境(甚至是奇怪)的职位名称。那么,为何会有这么多职位的存在?它们的存在是由于在建设Web时某个职位只能做很少的事情。过去在前端和后端开发者之间有着一条明显的分界线。同样这些种类也有自己的分支。前端开发者专长于CSS或者工作在基于UI设计的JavaScript,然而后端开发者专注Ruby或者其他语言。这样在Web开发者中产生了很多争论。如果你想在领域中取得成绩,你应该专注于那些方面?需要专注所有方面吗?需要成为在前端和后端环境都突出的全栈开发者,还是杰出于在某个方面?

雇主的要求

我认为真正的问题在于单一类型的开发者是否更容易雇佣。基于这种想法,有意义的回顾一下以及试图找出当前雇主的要求。

随着Web发展,雇主希望熟悉于更多技术和框架的开发者。这是由于站点变的越来越变幻莫测,并且在原生应用以及浏览器应用的程序之间的分界逐渐模糊。正如我工作的公司,越来越多的用户要求网站胜任现代的Web应用,而不仅仅是单传的静态站点。

那些主要以静态为主的网站,其在持续减少对Web开发者的需要。事实上,其中几个公司的产品能符合建立静态站点商城的需求,使客户能够创建自己的网站,而自己无需编写一行代码。WordPress.com、Squarespace,和Wix,这些都能降低成本,每个平台都有简单的学习曲线和普通的UI。不要求编程能力。

然而我不认为这些站点能在商业上使用,我很确定它们降低了HTML,CSS和JavaScript 能力的价值,同样我认为雇主开始意识到这个问题。他们开始寻找懂得整个架构的更全面和更有经验的开发者,从下拉菜单样式到部署服务器。

然而,我不认为真正的全栈开发者是实际存在的,我相信了解整个架构的开发者更容易被雇佣。而这并不意味着你需要知道Web开发的方方面面。取而代之的是,我认为应该有清单能让每个开发者开发的去学习,并且随着时间逐渐提高。

清单

Javascript Jabber 最近放出的播客就是专注于这个话题。他们列出了大量的技术要求Web开发者应该知道的。我总结了一下最重要的技能列表如下。

  • HTML, CSS, Javascript
  • 一门后端语言
  • 版本控制
  • 命令行使用
  • Node/Ruby 工具
  • 客户端MVC框架
  • 流行的工具和框架,例如Angular,Laravel,Rails等
  • 数据库知识
  • 服务器知识
  • 站点部署策略
  • 搭建和使用REST API
  • 响应式Web开发
  • 易用性
  • 代码测试

这有另外一张Louis Lazaris的清单。虽然有一些年份了,但其中很多技术现在依然很常用。

不要害怕

看到表中列的技术,你应该开始意识到,最基本的,应该听过它们之间的绝大多数。 此外,没有人能精通每个Web开发工具或者技术。反而,我们应该开放的去学习Web开发,尽可能的知道更多的技术和工具。

还有记住普遍水平的了解技术就已经很好了。比如开发者能熟练运用复杂的CSS布局,同样也能通过JavaScript 增加一个新的功能。一些公司或者机构由一个开发者写前端代码,另一个写后端。如团队基础的工作流就很好,这能让开发者大致了解其他部分的工作。

总结

以某些具体的工具或者技术为中心的思想会产生不良影响以至于组织技术的提高。随着Web技术的发展,要求Web开发者需要更多的懂得整个架构。我们依然有在特定领域做的更好的自由,但是正如排版变得越发容易以及交互性的更大的需求,基本的前端技能以及应用开发会受到更多的追捧。听到雇主雇佣全栈而不是专业的开发者可能会令人不安,但Andy Shora的结论揭示了这样的状况。

的确,没有人能指望你能从前端到后端,开始到结束只靠一个人完成。同样你也不应该为提这样需求的人工作。如果你熟练五到十种技术/工具,同样也有意愿去了解其他100多种你不熟悉的,那么你就是高价值的商品了。

**说明:**本文来自SitePoint,作者:Adam Bretz

文章版权属于原网站/原作者。我依旧只是个搬运工+不称职的翻译。

自从1995年发布以来,JavaScript 有了很大的发展。我们已经看到了ECMAScript 规格的几个重要版本及单页Web应用的崛起,这些都被客户端的JavaScript 架构支持。起初,所有的JavaScript 开发和创新都只能在浏览器实现,这是由于浏览器是支持这种语言的唯一环境。随着时间的推移,Web开发者开始意识到JavaScript 的很多实用的特性(没有块级作用域,事件驱动以及与许多其他语言相似)使其能对其他环境而不仅仅是浏览器。这促使JavaScript 社区进行了第二轮创新最终使JavaScript 运行于服务端和数据库。

突然,了解JavaScript 不会把你自动归类在“前端开发者”中。如果你熟悉这门语言,你能建立服务器和数据库,以及丰富前端用户体验。现在,第一次有了开发者能通过只用JavaScript 就能建立整个Web应用。这种趋势常常被称为“全栈的JavaScript”或“纯JavaScript解决方案”。组合了四种流行的JavaScript 技术:MongoDB, Express, AngularJS, and Node.js 建立Web应用受到欢迎了,这被成为“MEAN 全栈”。

MEAN

  1. MongoDB - MongoDB 是一种NoSQL的数据库。它是一种文件导向数据库管理系统, 而不是由行、列和表格组成的。主要用于存储JSON 数据;这完美契合由JavaScript 编写的应用。数据的关系性操作和严厉遵守图式的缺乏,这使MongoDB 具有快速,伸缩性强及易用的特性。
  2. Express - Express是一种轻量级的服务器级框架,被用来使Node 搭建的Web服务更简单及更强的可维护性。框架的灵活性提供给开发者高度的可定制性以及足够“低端”的用于操作Node 框架。Express 提供简单方式使用路由,cookie管理,静态文件服务和其他HTTP模块用于搭建企业级的服务。
  3. AngularJS - AngularJS 是一种客户端富应用的MVC JavaScript 框架。它可用于建立健壮的和复杂的单页Web应用。双向数据绑定和基于HTML的框架语言。AngularJS 也有称为“命令”的特性允许你拓展HTML的新的属性,甚至是新的元素。AngularJS 同样也经过了高强度的测试,这可能不会成为开发的有趣方面,但这对于AngularJS 来说是重要的并且经常管理客户端代码。最后,AngularJS 提供了协议和最佳实践用于帮助开发者建立客户端的解决方案。
  4. Node - Node 是JavaScript 的运行环境用于建立服务及网络应用。它提供了在客户端的所有JavaScript 的特性并且加入了文件以及网络I/O。Node使用了Google 的V8引擎(同样也用于Google Chrome)用于执行JavaScript 。其同样也是非常活跃的开发者社区和Node 模块的生态系统(Express就是其中一个模块)的基础。与此同时,也有很多其他在客户端的JavaScript 实践,到目前为止,就粉丝和大公司而言都成功采用的。

如果你像我一样都是JavaScript 的粉丝,你应该兴奋于只用JavaScript 就可以建立整个Web应用的前景。MEAN全栈是相当受欢迎的话题,在网络上也有很多如何开始这些技术的信息。事实上,有很多关于这项技术的信息,仅仅是有关“开始”的就可以“令人畏惧”。

译者按

最后作者介绍自己和Colin Ihrig共同编写的“MEAN全栈”书籍 有兴趣的朋友可以关注一下。

正如作者所说,仅仅使用JavaScript 就能建立这个Web应用是一件令人兴奋地事情。

0%