blog's People
Forkers
kevinge yj33123 tobyreynold ahhqcheng wdmchaft hacker84 pighy pianokey zhouali rockylo gaoshuo henryzp jsonxu songjin quincy0319 darkhorse007 steve-gu seonpiao jailecoeu nikon321 evilthedante cyendra jacksong19 0704681032 fe-ninja learn-blogs mr-l7 zhangjiandev edwardyoyou123 spidermanzy yunfour sjclijie bojuewjt kevinwang04 otobelikethee bajitanglang crzaz123 iamxujiajun wangjia9294 boyce-yijian ihaveyou zhangwenhua029 freeyiyi1993 peter-wf spectremercury suuzee nanioo solaris-meng vshangxiao luoxq fesource vtansen suplum tomfanxiaojun yunchihuang lmh2072005 gitfancc niudong2015 chentw0102 arzoochina gitbu libucha lorryislurui wmc425454438 changhaihe icarus-luoka apple01150525 499800157 qixiaosen guyicc dida1209 github1548236651 xiangxiaolong007blog's Issues
一种全新的UI架构——HSEJ模式
HSEJ模式是最新研究出来的先进UI架构,它的特点是基于群众基础广泛的jQuery,学习成本极低,代码极其轻量。
它先进的理念使得它比MVC、MVP、MVVM和FLUX、REFLUX、REDUX等框架不知高到哪里去了。
首先是代码量,HSEJ模式依赖的jQuery大小仅仅34.5k,而相比之下react.js竟然达到惊人的133k。
我们先来了解一下HSEJ的名词:
- H-HTML:就是我们写的HTML代码,这没什么好解释的。
- S-Selector:选择器,选择器是由jQuery首创的一种非常先进的操作HTML的方法。
- E-Event:事件,事件是jQuery的一些方法,经过高度封装之后,可以响应用户的各种操作。
- J-JavaScript:JavaScript是jQuery的一部分功能,提供了极其强大的图灵完备的拼接字符串的能力,其中最厉害的就是$字符。$在jQuery中有九种作用,其它任何一个框架的任何函数都没有这么强大。此外,JavaScript是基于对象的,而不是面向对象的。
下面我们来看看HSEJ模式的架构图,为了对比,我放上了最近特别火的FLUX的架构图:
两张图是如此之相似,那么各位一定有一个疑惑,那就是,到底为什么这么相似?
没错,跟你想的一样,HSEJ模式随着jQuery发布就已经普及了,只是开发jQuery的大师们担心你们前端太low才没好意思提出来,React不过是最近几年的事情,谁抄谁的一目了然。
由此可见,React不过是窃取了广大jQuery开发者的智慧,改了个名字重新卖卖概念的二道贩子罢了,Facebook公司这样的人品,怎么能让它来到**呢?
HSEJ的用户操作响应过程如下:
用户点击了HTML元素=>通过选择器和事件找到JavaScript代码=>在JavaScript中拼接HTML字符串=>通过选择器把字符串填回去
下面我们来看一段例子:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<div>
<p>
Clicked: <span id="value">0</span> times
<button id="increment">+</button>
</p>
</div>
<script>
$('#increment').click(function(){
$('#value').html(parseInt($('#value').html())++)
})
</script>
而同样的功能,用redux来实现,则是以下代码:
<script src="https://npmcdn.com/redux@latest/dist/redux.min.js"></script>
<div>
<p>
Clicked: <span id="value">0</span> times
<button id="increment">+</button>
</p>
</div>
<script>
function counter(state, action) {
if (typeof state === 'undefined') {
return 0
}
switch (action.type) {
case 'INCREMENT':
return state + 1
default:
return state
}
}
var store = Redux.createStore(counter)
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().toString()
}
render()
store.subscribe(render)
document.getElementById('increment')
.addEventListener('click', function () {
store.dispatch({ type: 'INCREMENT' })
})
</script>
你说他们是不是有病?
HSEJ模式的提出标志着前端进入了超越以往客户端UI架构的全新时代来临,希望大家好好学习,节日快乐。
阿里巴巴无线前端团队
题目来自阿里巴巴无线前端团队,我们招聘Web前端工程师。
为什么会有这些题目?这些题目代表了我看重的技能和方向,如果你觉得自己有能力有才华,但是苦于自己没有大公司经历简历被筛掉,请试试发这些题目的答案给我。
为什么没有职位描述?这些题目就是职位描述。
选择下面题目中的一个或者几个回答,可以直接写在评论里,并请留下邮箱。也可以把回答写在简历里直接发到我的邮箱 csf178 [at] gmail.com
- 你对前端职业发展有何看法?
- 前端和后端程序员应该如何合作?
- 讲几个你在项目中解决的让你印象最深的问题(难、匪夷所思、解决方案有趣都可以)
- 在JavaScript面向对象方面,你有什么体会和实践?
- 谈谈JavaScript中的闭包,以及你的实践。
- 说说 http://m.taobao.com 前端做的最烂的地方,以及你的改进。
- 谈几个有趣的html标签,以及它们的语义。
- 讲一讲CSS的position/float/display都有哪些取值,它们相互叠加时的行为都是什么?
- 说几个你觉得有趣的CSS3选择器,以及他们有趣的用法。
- 自己问自己一道代表你水平的面试题,然后回答。
一些提示 :
- 一个深入的答案强过十个正确的答案。
- 展现你的能力,有时候只需要一句话,有时候需要一篇长文
- 可以google,但是没有任何题目有标准答案
- 我保证认真看你的答案,但是不保证一一回复
手淘的滚动组件叫什么
不好意思,昨天没有记下来,以为你github里有
SUI库: http://m.sui.taobao.org/
闭包概念考证
闭包这个概念第一次出现在1964年的《The Computer Journal》上,由P. J. Landin在《The mechanical evaluation of expressions》一文中提出了applicative expression和closure的概念。(在计算机领域,closure还有两个完全不同的意义:计算几何中的凸包,和编译领域的包含集)
文中AE的概念定义如下:
We are, therefore, interested in a class of expressions about any one of which it is appropriate to ask the following questions:
Q1. Is it an identifier? If so, what identifier?
Q2. Is it a λ-expression? If so, what identifier or identifiers constitute its bound variable part and in what arrangement? Also what is the expression constituting its λ-body?
Q3. Is it an operator/operand combination? If so, what is the expression constituting its operator? Also what is the expression constituting its operand?
We call these expressions applicative expressions (AEs).
简单翻译
这样,我们对于能够适合提问以下问题的一类特性表达式感兴趣:
Q1. 它是否是标识符? 如果是的话,是什么标识符?
Q2. 它是否是λ表达式? 如果是的话,哪个或者哪些的标识符构成了它的绑定变量部分,范围是什么?还有是什么表达式构成了它的λ-body?
Q3. 它是否是操作符/操作数的组合?如果是的话,构成它的操作符的表达式是什么?还有构成它的操作数的表达式又是什么?
我们称这一类表达式为“适用表达式”(AE)。
在AE的基础上,闭包定义为
Also we represent the value of a λ-expression by a bundle of information called a "closure", comprising the λ-expression and the environment relative to which it was evaluated. We must therefore arrange that such a bundle is correctly interpreted whenever it has to be applied to some argument. More precisely:
a closure has an environment part which is a list whose two items are:
(1) an environment
(2) an identifier or list of identifiers
and a control part which consists of a list whose sole item is an AE.
翻译如下
此外,我们把带有一系列信息的λ表达式称作"闭包",其中包括λ表达式和它执行时的相关连的环境。于是我们要确保无论当它被用于什么参数时,这些信息都能够被正确解析。更精确地:
闭包包含环境部分,它是个只有两项的list,这两项分别是:
(1)环境
(2)一个标识符或者标识符列表
以及控制部分,他是个只有一项的list,唯一的项是个AE
在1975年,Scheme最早实现了闭包。
60年代,因为受到函数式思维影响,计算机软件领域的"表达式"一般是包括λ表达式,也就是函数式语言中的函数的。所以这个闭包的定义在80年代后被更多过程式语言借鉴,其中包括C语言的static全局变量机制、C++的成员函数、JavaScript的局部函数。对于过程式语言中,因为很少有函数以外的"表达式",所以闭包这个概念更多被用于指函数。
在JavaScript中,我们称函数对象为闭包。根据ECMA-262规范,JavaScript的函数包含一个[[scope]]属性。[[scope]]指向scope chain(ECMA-262v3)或者Lexical Environment(ECMA-262v5)。这对应于闭包的环境部分,[[scope]]中可访问的属性列表即是标识符列表,对象本身的引用则对应于环境。控制部分即是函数对象本身了。
响应式设计
Responsive Web Design
响应式Web设计
ETHAN MARCOTTE原作 于2010年5月25日
http://alistapart.com/article/responsive-web-design
设计师熟知的在印刷媒体的控制功能,常常也会期望Web媒体会有,但是他们仅仅限制在打印出来的页面上才能使用。我们必须接受这样的事实:web根本没有同样的限制和为这样的弹性准备的设计。但是首先我们必须接受这种落差和流程。
——John Allsopp, “A Dao of Web Design”
英国建筑师Christopher Wren有一次开玩笑说他选择了一个"以永恒为目标"的领域,而这样的原则也有它吸引人的一面:不像是Web那种总让人感觉是以下星期为目标的东西,建筑是一个以他的持久性来定义的学科。一个建筑的地基决定了它的底座,底座决定了他的结构,结构决定了它的外观。建筑的每一个阶段都比上一个阶段更固定,更难以改变。创造性的决定极其确切地决定了物理空间的形状,规划好了人们几十甚至几百年间在这个范围中活动的方式。
然而在Web上工作则是完全不同的事情。我们的工作内容由瞬时性定义,经常在一两年里就要调整或者替换。不一致的窗口宽度,屏幕分辨率,用户偏好以及我们用户安装的字体仅仅是在交付工作时要衡量的奇怪东西中的冰山一角。经年累月我们逐渐变得不可思议地精于此道。
但是形势在变化,而且可能比我们想要的还快。移动浏览量预计三到五年内会超过桌面访问。在三个具有支配地位的视频游戏平台中就有两个有Web浏览器(而且其中一个还非常棒。)。我们为了鼠标和键盘设计,为T9键盘设计,为手柄游戏控制器设计,也为触屏设计。简而言之,我们现在要面对比以往任何时候更大数量的设备、输入方式以及浏览器种类。
近年来,我见到更多公司开始要求"iPhone版网站"作为他们项目的一部分。这是一个很有趣的说法:从表面来看,当然,这是说移动版WebKit完全达到浏览器的品质,同时也是跳出桌面思考的一个强有力的商业案例。但是作为设计师,我觉得我们经常从这样明确的要求中寻找安慰,因为他们允许我们把面前的问题划分开来。我们可以把移动体验明确地隔离到单独的子域和空间中,跟"非iPhone版网站"分开。但是接下来呢?一个iPad网站?再来一个N90网站?我们真的能一直这样保证为每一种新的用户代理提供专门为之设计的体验?从某种意义上讲,这开始感觉像是一个零和游戏,但是我们——以及我们的设计——该如何适配呢?
弹性的基础
让我们考虑一个设计的例子。我创建了一个简单的幻想杂志页面。它是在流体格上的直接的两栏布局,其中到处散布着一些弹性的图片。作为非固定布局的长期支持者,我长期认为它们更加"面向未来"仅仅因为它们不针对特定布局。在某种程度上,规则是:弹性设计没有对浏览器窗口宽度做任何假设,并且非常漂亮地适配了具有人像和景物图模式的设备。
但是不论是固定设计还是流体设计,没有任何设计可以在超出它最初考虑的环境时缩放自如,示例中的设计在浏览器窗口大小改变时完美地缩放,但在更低分辨率下关键点很快出现了,当用比800x600更小的视口去观看时,logo后面的插图被截断了,导航文本则在不合适的地方换行,图片和按钮因为过于拥挤而失去易读性。而不仅仅是分辨率过小时的造成的影响:当用宽屏去看这一设计时,图片立刻变成了笨拙的尺寸,挤开了周围的内容。
总的来说,我们的弹性设计桌面环境工作良好,因为它原本就是为之设计的,但是不能够搞定差得太多的情况。
支持响应
最近,一个新兴的学科名为"响应式结构设计"(译者注:这是建筑学领域的概念)开始设问物理空间到底能用于让多少人通过它们。通过嵌入式机器人技术和伸缩性材料,建筑师试验使得艺术装潢和墙体结构在收到挤压时能够弯曲、弹性和扩展。在装满人的时候,运动传感器与气候控制器配合以控制温度和周围光线。一些公司已经生产出了"智能玻璃技术",能够在屋子里的居住人数量达到一定阈值的时候自动变得不透明,以给予他们一层额外的隐私保护。
在他们的书"响应式结构设计"中,Michael Fox 和 Miles Kemp描述这个更接近于"一个可以对话的多重循环系统;一个持续而有创造性的数据交换中心。"强调下我的看法,在我看来这是一个微妙但是强有力的区别:比起之前所说的固定的、不变的空间来规定特定的体验,他们揭示了居住者和建筑物之间可以,也应该动态地互相影响。
这就是我们要前进的道路。与其为每一种数目不断增加的web设备裁切出一种毫无关联的设计,我们可以将他们视为同一种体验的不同面。我们可以为最佳视觉体验来设计,但是在我们的设计中加入基于标准的技术是的它们不仅仅是弹性的,而且更好地适配到渲染它们的媒体上去。简单地说,我们需要实践响应式web设计。但是怎么做呢?
初识media query
在CSS2.1时代,我们的样式表可以通过媒体类型来判断设备。如果你有写过打印用的样式表,你应该非常熟悉这一概念:
<link rel="stylesheet" type="text/css" href="core.css"
media="screen" />
<link rel="stylesheet" type="text/css" href="print.css"
media="print" />
因为想要让我们设计出来打印格式更好的页面,CSS标准提供给我们一系列的可接受媒体类型,每一种都为特定的已知可以访问web的设备定制。但是多数浏览器和设备从来没有拥抱这一标准的精神,留下了大量实现不完整的媒体类型,或者根本就给忽略掉。
谢天谢地,W3C搞出来了media query作为CSS3标准的一部分,改进了媒体类型的承诺。media query允许我们不仅仅以特定设备类型为目标,还可以真正地检查设备用来渲染我们作品的具体物理特征。例如,随着移动WebKit的崛起,media query成为受欢迎的客户端技术,可以为iPhone、Android手机和他们的亲戚提供裁切讲究的样式表。要想做到这个,我们可以把一个查询条件写入外链样式表的media属性:
<link rel="stylesheet" type="text/css"
media="screen and (max-device-width: 480px)"
href="shetland.css" />
这个查询条件包含两部分:
- 一个媒体类型(screen), 以及
- 由圆括号括起来的真正查询条件,包括要检查的特定媒体特征(max-device-width)后跟目标值(480px)。
用通俗地话说,我们要求设备的水平分辨率(max-device-width)等于或者小于480px。如果这个检测通过——也就是说,如果我们的作品在小屏幕设备如iPhone上面,设备就会加载sheland.css。否则,外链就会被完全忽略。
设计师们过去就曾经实践过针对分辨率的布局,大部分都依赖像是Cameron Adams的nb脚本一样的JS驱动的解决方案。但是media query标准提供了一个媒体特性的宿主,它远不止屏幕分辨率那么简单,它极大地扩展了我们可以用查询来检测的范围。还有就是,你可以在一次查询中同时检测多个属性的值,只要使用and关键字链接起来就可以了:
<link rel="stylesheet" type="text/css"
media="screen and (max-device-width: 480px) and (resolution: 163dpi)"
href="shetland.css" />
还有更多,我们不仅仅可以在link标签中引入media query。我们也可以把它们直接包含在CSS中作为@media规则的一部分。
@media screen and (max-device-width: 480px) {
.column {
float: none;
}
}
或者作为@import指令的一部分。
@import url("shetland.css") screen and (max-device-width: 480px);
然而在每一种情况下,作用是一样的:如果设备通过了我们设置的media query检测,相关的CSS就会作用到我们的标签,简单来说media query对于其它人来说就是条件注释。并非针对特定版本的特定浏览器,我们可以以外科手术手法去纠正我们布局在缩放到并非原始和完美尺寸时出现的问题。
适配、响应与克服
现在我们转过来看看页面底部的图片。在他们默认的布局中,有关的CSS看起来像是这样:
.figure {
float: left;
margin: 0 3.317535545023696682% 1.5em 0; /* 21px / 633px */
width: 31.121642969984202211%; /* 197px / 633px */
}li#f-mycroft,
li#f-winter {
margin-right: 0;
}
我漏掉了几个排版属性而专注于布局:每个 .figure元素尺寸为包含它们那一列的大约三分之一,每一行的最后的图片(li#f-mycroft, li#f-winter)右侧的margin被清零。这个可以很好地解决问题,然而这可视区域一旦显著地小于或者宽于我们原本的设计就不行了。用media query,我们根据特定分辨率做定点修复,适配我们的设计以应对显示。
首先,在可视区域的分辨率降低到最低限600px的时候,让我们来把页面变成单栏。这样在样式表最底部,我们创建一个新的@media区块,像是这样:
@media screen and (max-width: 600px) {
.mast,
.intro,
.main,
.footer {
float: none;
width: auto;
}
}
如果你在一个现代桌面浏览器看我们更新后的页面,然后把窗口尺寸减小到600px以下,media query将会关闭设计中主要元素的浮动,在文档流中顺次堆叠这些区块。这样我们的小型化设计就很好地做出来了,但是图片还没有很智能地缩小。如果我们引入另一个media query,我们可以相应地改变它们的布局:
@media screen and (max-width: 400px) {
.figure,
li#f-mycroft {
margin-right: 3.317535545023696682%; /* 21px / 633px */
width: 48.341232227488151658%; /* 306px / 633px */
} li#f-watson,
li#f-moriarty {
margin-right: 0;
}
}
不要在意这个很丑的百分比;我们只是重新计算了流体格的宽度来适应新的单栏布局。简单地说,当可视区域的宽度下降到400px以下的时候,我们从三列的布局切换到二列的布局,让这个图片看上去更突出。
我们也可以给宽屏的显示切实地做一些事情。针对高一些的分辨率,我们可以把图片适配到六栏布局,把它们全都放在同一行:
@media screen and (min-width: 1300px) {
.figure,
li#f-mycroft {
margin-right: 3.317535545023696682%; /* 21px / 633px */
width: 13.902053712480252764%; /* 88px / 633px */
}
}
现在我们的图片在分辨率谱系中的两段都可以完美展现,可以根据窗口和设备分辨率自动优化它们的布局方式。
但是这只是个开始。通过我们嵌入在CSS中的media query,我们能改变的不仅仅是几张新图片的摆放:我们可以引入新的,可以更改的布局以搭配各种分辨率区段,可能使得导航在大屏幕视图下更加突出,或者在小屏幕中重新定位到Logo上方。
而响应式设计并不仅仅是布局改变。media query允许我们实践中改变自己的形态做到令人难以置信地高精确性适配页面:我们可以在小屏幕上增加目标区域或者链接,在触屏设备上更好地遵循费茨法则(译注:Fitts's law);有选择地展现或者隐藏用于改善页面导航元素。我们甚至可以实行响应式排版来更改文本的尺寸和框线,为提供显示的设备优化阅读体验。
一些技术摘记
值得一提的是,media query的健壮性在现代浏览器中令人难以置信。桌面浏览器如Safari 3+, Chrome, Firefox 3.5+, 和Opera 7+ 都原生地支持media query, 更近一些的移动浏览器如Opera Mobile和移动WebKit也是如此. 当然了,这些桌面浏览器的旧版本不支持media query。而虽然微软承诺在IE9中支持media query,但是Internet Explorer现在没有原生实现(译注:此文写的时候IE9还没出来,IE9和IE10确实已经完整支持了media query)。
尽管如此,假如你对于在遗老遗少级别的浏览器上实现media query,这里有JavaScript带来的一线曙光:
- 有一个2007年的jQuery插件提供了不完全的media query,仅仅在加到不同的Link元素时提供了支持min-width和max-width两个媒体属性的支持.
- 更近一点的事情,css3-mediaqueries.js已经发布,这是一个承诺要在使用@media块包含的时候“使得IE 5+, Firefox 1+ 以及Safari 2 对使用者透明地解析、检测和应用CSS3 Media Query”的库。在1.0版本发布的时候,我个人发现他很健壮,我计划要关注它的开发进程。
但是如果使用JavaScript无法引起你的兴趣,这也是完全可以理解的。然而,这可以加强在弹性格的基础上做布局的案例,确保你的设计在没有media query的浏览器和设备上也利用了一些弹性设施。
前路展望
流体网格,弹性图片以及media query是响应式web设计的三个技术要素,同时他要求一种新的思维方式。除了把我们的内容分成完全不同的、设备相关的体验之外,我们可以使用media query来对我们的工作在不同的视觉上下文中做渐进增强。这不是说没有适合将网站分成特定设备的商业案例;比如,如果用户到你的移动站点来的想要找的东西比桌面内容更少,那么提供不同的内容就是最合适的做法。
但是这样的设计**不应该是我们的默认选项。现在比起以往任何时候,我们的设计工作都更倾向于不同梯度的体验中展现。响应式web设计给我们提供了一个前进的道路,最终让我们能够做到"为事物的涨落而设计"。
HTML中的attribute和property
一、概述
attribute和property是常常被弄混的两个概念。
简单来说,property则是JS代码里访问的:
document.getElementByTagName('my-element').prop1 = 'hello';
attribute类似这种:
<my-element attr1="cool" />
JS代码里访问attribute的方式是getAttribute和setAttribute:
document.getElementByTagName('my-element').setAttribute('attr1','Hello');
document.getElementByTagName('my-element').getAttribute('attr1','Hello');
二、区别
多数情况下,两者是等效的。在web标准中,常常会规定某attribute“反射”了同名的property。但是例外的情况还是不少的。
1. 名字不一致
最典型的是className,为了回避JavaScript保留字,JS中跟class attribute对应的property是className。
<div class="cls1 cls2"></div>
<script>
var div = document.getElementByTagName('div');
div.className //cls1 cls2
</scrpit>
2. 类型不一致
最典型的是style,不接受字符串型赋值。
<div class="cls1 cls2" style="color:blue" ></div>
<script>
var div = document.getElementByTagName('div');
div.style // 对象
</scrpit>
3. 语义不一致
如a元素的href属性。
<a href="//m.taobao.com" ></div>
<script>
var a = document.getElementByTagName('a');
a.href // “http://m.taobao.com”,这个url是resolve过的结果
a.getAttribute('href') // “//m.taobao.com”,跟HTML代码中完全一致
</scrpit>
4. 单向同步关系
value是一个极为特殊的attribute/property。
<input value = "cute" />
<script>
var input = document.getElementByTagName('input');
//若property没有设置,则结果是attribute
input.value //cute
input.getAttribute('value'); //cute
input.value = 'hello';
//若value属性已经设置,则attribute不变,property变化,元素上实际的效果是property优先
input.value //hello
input.getAttribute('value'); //cute
</scrpit>
除此之外,checkbox的显示状态由checked和indeterminate两个property决定,而只有一个名为checked的property,这种情况下property是更完善的访问模型。
三、特殊场景
1.mutation
使用mutation observer,只能监测到attribute变化。
var observer = new MutationObserver(function(mutations){
for(var i = 0; i < mutations.length; i++) {
var mutation = mutations[i];
console.log(mutation.attributeName);
}
});
observer.observe(element,{attributes:true});
element.prop1 = 'aa' // 不会触发
element.setAttribute('attr1', 'aa') //会触发
2.custom element
在使用WebComponents时,可以定义attribute和property,两者可以互相反射,也可以全无关联。
var MyElementProto = Object.create(HTMLElement.prototype, {
createdCallback : {
value : function() { }
}
});
//定义property
Object.defineProperty(MyElementProto,'prop1', {
get:function(){
return //
},
set:function(){
console.log('property change');//do something
}
});
//定义attribute
MyElementProto.attributeChangedCallback = function(attr, oldVal, newVal) {
if(attr === 'attr1') {
console.log('attribute change');//do something
}
};
window.MyElement = document.registerElement('my-element', {
prototype: MyElementProto
});
谈谈UI架构设计的演化
谈谈UI架构设计的演化
经典MVC
在1979年,经典MVC模式被提出。
在当时,人们一直试图将纯粹描述思维中的对象与跟计算机环境打交道的代码隔离开来,而Trygve Reenskaug在跟一些人的讨论中,逐渐剥离出一系列的概念,最初是Thing、Model、View、Editor。后来经过讨论定为Model、View和Controller。作者自言“最难搞的就是给这些架构组件起名字”。
因为当时的软件环境跟现在有很大不同,所以经典MVC中的概念很难被现在的工程师理解。比如经典MVC中说:“view永远不应该知道用户输入,比如鼠标操作和按键。”对一个现代的软件工程师来说,这听上去相当不可思议:难道监听事件不需要类似这样的代码吗?
view.onclick = ......
但是想想在70年代末,80年代初,我们并没有操作系统和消息循环,甚至鼠标的光标都需要我们的UI系统来自行绘制,所以我们面对的应该是类似下面的局面:
mouse.onclick = ......
mouse.onmove = ......
当鼠标点击事件发生后,我们需要通过view的信息将点击事件派发到正确的view来处理。假如我们面对的是鼠标、键盘驱动这样的底层环境,我们就需要一定的机制和系统来统一处理用户输入并且分配给正确的view或者model来处理。这样也就不难理解为什么经典MVC中称"controller是用户和系统之间的链接"。
因为现在的多数环境和UI系统设计思路已经跟1979年完全不同,所以现代一些喜好生搬硬套的"MVC"实现者常常会认为controller的输入来自view,以至于画出model、view、controller之间很奇葩的依赖关系:
我们来看看Trygve Reenskaug自己画的图(这恶趣味的骷髅啊……):
值得一提的是,其实MVC的论文中,还提到了"editor"这个概念。因为没有出现在标题中,所以editor声名不著。MVC论文中推荐controller想要根据输入修改view时,从view中获取一个叫做editor的临时对象,它也是一种特殊的controller,它会完成对view和view相关的model的修改操作。
控件系统
MVC是一种非常有价值的架构思路,然而时代在变迁,随着以windows系为代表的WIMP(window、icon、menu、pointer)风格的应用逐渐成为主流,人们发现,view和controller某些部件之间的局部性实际上强于controller内部的局部性。于是一种叫做控件(control)的预制组件开始出现了。
控件本身带有一定的交互功能,从MVC的视角来看,它既包含view,又包含controller,并且它通过"属性",来把用户输入暴露给model。
controller的输入分配功能,则被操作系统提供的各种机制取代:
- 指针系统:少数DOS时代过来的程序员应该记得,20年前的程序中的“鼠标箭头”实际上是由各个应用自己绘制的,以MVC的视角来看,这应当属于一个"PointerView"的职责范畴。但是20世纪以后,这样的工作基本由操作系统的底层UI系统来实现了。
- 文本系统:今天我们几乎不需要再去关心文本编辑、选中、拖拽等逻辑,对web程序员可以尝试自己用canvas写一个文本编辑框来体验一下上个时代程序员编写程序的感受。你会发现,选中、插入/覆盖模式切换、换行、退格、双击、拖拽等逻辑异常复杂,经典MVC模式中通常使用TextView和TextEditor配合来完成这样的工作,但是今天几乎找不到需要我们自己处理这些逻辑的场景。
- 焦点系统:焦点系统通过响应鼠标、tab键等消息来使得控件获得操作系统级唯一的焦点状态,所有的键盘事件通常仅仅会由拥有焦点的控件来响应。在没有焦点系统的时代,操作系统通常是单任务的,但是即使是单一应用,仍然要自己管理多个controller之间的优先权和覆盖逻辑,焦点系统不但从技术上,也从交互设计的角度规范化了UI的输入响应,而最妙的是,焦点系统是对视觉障碍人士友好的,现在颇多盲人用读屏软件都是强依赖焦点系统的。
所以时至今日,MVC,尤其是其中controller的功能已经意义不大,若是在控件系统中,再令所有用户输入流经一个controller则可谓不伦不类、本末倒置。MVVM的提出者,微软架构师John Gossman曾言:“我倾向于认为它(指controller)只是隐藏到后台了,它仍然存在,但是我们不需要像是1979年那样考虑那么多事情了”
MVP
1996年,Taligent公司的CTO,Mike Potel在一篇论文中提出Model-View-Presenter的概念。
在这个时期,主流的view的概念跟经典MVC中的那个“永远不应该知道用户输入”的view有了很大的差别,它通常指本文中所述的控件,此时在Mike眼中,输入已经是由view获得的了:
Model-View-Presenter是在MVC的基础上,进一步规定了Controller中的一些概念而成的:
对,所以,不论你按照Mike还是Trygve的理解方式,**MVP和MVC的依赖关系图应该是一!模!一!样!的!**因为Mike的论文里说了“we refer to this kind(指应用程序全局且使用interactor, command以及selection概念的) of controller as a presenter”。presenter它就是一种controller啊!
把依赖关系画成这样也是醉了啊!不管你信不信我反正是不信啊!
标记语言和MVVM
随着20世纪初web的崛起,HTML跟JS这样标记语言+程序语言的组合模式开始变得令人注目。逐渐推出的Flex、Sliverlight、QT、WPF、JSF、Cocoa等UI系统不约而同地选择了标记语言来描述界面。
在这样的架构中,view(或者说叫控件,不但是从依赖关系上跟程序的其他部件解耦,而且从语言上跟其它部分隔离开来。
标记语言的好处是,它可以由非专业的程序员产生,通过工具或者经过简单培训,一些设计师可以直接产生用标记语言描述的UI。想要突破这个限制使得view跟其它部分异常耦合可能性也更低。
然而这样的系统架构中,MVC和MVP模式已经不能很好地适用了。微软架构师John Gossman在WPF的XAML模式推出的同时,提出了MVVM的概念。
WPF得MVVM正式说明了它的view的概念跟MVC中的view的概念的区别。这里简单画了一下:
在MVVM模式中,数据绑定是最重要的概念,在MVC和MVP中的view和model的互相通讯,被以双向绑定的方式替代,这进一步把逻辑代码变成了声明模式。
结语
从经典MVC到MVVM,UI架构经过数次重大变迁,一些概念也在不断变化,架构和底层环境互相影响、适配,我认为时至今日,经典MVC已经不再是UI架构的正常选项。
更糟糕的是,今天无数经过演绎的MVC实现(如backbone)和科普文,要么是原本作者概念已经很混乱,掺杂私货,要么为了适配现代的标记语言和控件模式,自己修改了经典MVC中的一些概念和耦合关系。实际上今天MVC已经没法作为一种交流的标准词汇了。
写此文,希望大家能了解些历史上的发展历程,莫被不严谨的文章误导。其实本文的相当多观点也是经过演绎的,所以我附上所有原始文献链接,希望大家看了以后能有自己的判断:)也欢迎大家据此指出我理解的错误之处。
参考资料
关于webp的请教
谈谈面试与面试题
起因,某日电话面试之后满心郁闷的我发了两条微博:
面试的时候问个css的position属性能刷掉一半的人这是啥情况……
其实这问题我本来打算的是可以顺着一路扯到normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi,这样一路问下去的,奈何第一个问题(亲我真的只问了position有哪些取值和行为啊)就悲剧了……
其中的一些回复让我认为非常有必要写这样一篇文章来说说面试和面试题的事情。
关于题目
什么样的面试题是好的?我认为有三点衡量指标:
- 区分度
- 深度
- 覆盖范围
是的,请注意我并没有使用“难度”这个词,因为这三个指标都与难度有关系。
css的position属性有哪些取值,它们的行为是什么?
这个题目几乎是我每次必问的,因为这个题区分度、深度和覆盖范围都很高。这个题的答案可以分成不同的层级:
- position属性常用的取值static、relative以及absolute和它们的基本行为是每个前端都应该掌握的。这包括relative和absolute的定位原点。
- fixed旧版本IE不支持,但是一个对技术有热情的工程师也是应该了解的。
- 有过研究工程师可以知道absolute的containing block计算方式跟正常流不同,当然如果没读过标准的话,表述方式不一定是这样。
- 对CSS布局有深入研究的工程师会知道position跟display、margin collapse、overflow、float这些特性相互叠加后的行为。
区分度可以让题目可以适用于入门级到专家级的各种面试者,深度可以保证有深度研究的面试者可以展示他们的才能,覆盖范围可以有效地了解面试者擅长的方向。
网上抱怨面试官以出难题展示自己技术为乐的声音颇多,虽然不排除这样的可能性,但是我认为这样抱怨的人多半自己没有做过面试官,实际上多数公司面试往往任务量很大,几乎不会有什么玩乐的心情。题目偏、难、怪的情况多半可能是面试官不太负责任随便从网上搜索"大公司面试题"来的——图省事是个比戏弄靠谱的多的动机。
关于过程
比起笔试,面试的最大好处是可以根据面试者的水平调节题目的难度,即使一个题目中,也可以通过提示和追问来调整难度。
一般来说,当面试者遇到困难或者长时间思考时,面试官应当给予提示来节约时间,而当面试者给出的答案不够具体或者回答得过于轻松时,可以适当追问。在我的微博中
其实这问题我本来打算的是可以顺着一路扯到normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi,这样一路问下去的,奈何第一个问题(亲我真的只问了position有哪些取值和行为啊)就悲剧了……
我提到了一些我准备的追问内容,这些知识点从前到后越来越细致,也越来越偏,从最开始的box排布,到后面的行模型,再到文本排版,基本上是网页排版从整体到细节的顺序。
当面试者前面回答的答案足够完美,我就会进行追问,确保问到我开始不懂或者面试者开始不懂为止,这样可以大大延展题目的区分度和深度。
关于评判
首先我希望表达的一点,就是面试的评判跟学校里的考试完全是两回事,太多的人把面试当做考试而把注意力放在题目上。
事实上面试中未必是所有题目全都回答"正确"就一定会通过或者较高评价。面试是面试官和面试者双方"挖掘与展示才能"的过程,参考前面提到的面试过程,全部回答正确的情况很可能是因为面试官不感兴趣懒得追问。
对于面试官而言,基本评判原则就是"我要不要这个人做我的同事?",多数情况下,这个答案会非常清楚。一些题目是充分的,也就是"回答对了说明这个人具有可以依靠的才能",一些题目则是必要的,也就是"回答错了说明这个人无法胜任我们的工作"。
在position一题的评判上,我一般认为能够答对static、relative以及absolute就已经可以达到必要标准。而因为CSS layout是我最擅长的部分(虽然还是很烂……),又考虑到误差,当面试者能回答80%以上的追问,我就会认为面试者水平远高于我,在工作中能够作为CSS方面的专家来依靠。
我在面试中之所以感到沮丧,是因为大部分的人仅仅在position的基本行为上就已经错了,多数人的回答都是笼统的"绝对定位"和"相对定位"两个词,问及具体行为我得到了五花八门的答案,甚至有看上去经历相当资深的工程师把absolute和relative搞混的。
而微博上一些人说"属性可以google搜索"则更离谱,position在CSS布局中是相当基础的知识,对它的行为理解深度实际上代表了一个工程师对于CSS布局系统的理解,这个理解需要长时期的学习,绝对不是可以临时google得来的。正如同考人英语,若是不认识visibility尚可以解释说确实没怎么用过,而不会写英文字母v则说明这个人根本没学过英语。
关于题目类型
面试题有很多种类型:项目细节、知识型问题,开放性问题,案例问题以及传说中的Funny Question。事实上网络上流传甚广的"大公司面试题",往往是Funny Question,而它们真正的应用,在任何公司都是非常少见和谨慎的。
一些人提到,面试应该更注重“考察能力”。是的,我认为
web前端工程师的竞争力 = web前端知识 + 能力
能力 = 编程能力 + 工程能力 + 架构能力
这其中不包括所谓的学习能力,因为我认为学习能力是通过已有知识来体现的,如果一个具有超强学习能力的人来应聘web前端工程师但是他具有如此强的学习能力却连position这么重要的属性都没学会,那是不是下一步该要求这人附上证明自己没有精神疾病的诊断书?
工程能力和架构能力一般针对层级较高的工程师,所以一般来讲所谓能力考察就是编程能力,然后呢,编程能力一般考查方式就是案例问题,也就是传说中的——“算!法!题!”
(当然我曾提到,它们与其说是算法题,不如说是稍微复杂点的小程序,它们之所以看上去不太有用是因为出题的人为了避免理解麻烦剥掉了实际的业务场景,毕竟各个公司的业务都不是一句两句可以讲清楚的)。
所以我估计教育我"考察能力"的各位,真的碰上这种题要骂死我了……
在题目类型的使用上,电话面试中我会以项目细节和知识性问题为主,一般当面面试中会使用案例问题(写程序或者架构case),开放性问题和Funny Question几乎不用。
考察能力的问题,一般我会控制在一道左右,最多不会超过两道题,因为这种问题往往非常消耗精力,过多会引起面试者抱怨。(当然有的公司专门这么干,同一天三轮技术面一轮AA面,每一轮都有算法题——这公司就是万恶的M$哈哈哈)
PS. position那道题目,我是不怕漏的,如果你要认真准备这道题的答案的话,基本等于学好了CSS的布局了,有兴趣的同学可以写篇文章并且发送简历到我的邮箱csf178 [at] gmail.com 写得好的话电话面试可以省了哦~ 阿里无线前端期待你的加入!
pp
;;
谈谈面试与面试题 II
声明:本文介绍的内容,不包含任何以伪造虚假信息为前提的技巧。
关于面试题
面试题往往是准备面试时最受追捧的东西。我这里却想提一个有点不可思议的观点:不要准备面试题。
“下水井盖为什么是圆的?”
“全世界有多少辆汽车?”
不知道有多少“微软面试题”,"google面试题"在网上到处流传。
其实恰恰反了,这些不着调的面试题,并不因为它是微软和google的面试题就变得高深莫测。之所以会有这样的题目出现,正是以其极度的不靠谱反衬了这些大公司对“过程比答案重要”的诠释,和对自己的面试官面试的把控能力的信心。
对于一个合格的面试官来说,问题只是话题的起点。所以精心准备的答案可能在面试官的一次追问后全盘崩溃,一开始支支吾吾的面试者,也可能在面试官逐渐的引导下展示出自己的能力。
我常常提一个观点,面试和考试不同,面试可能因为一个问题答得好而通过,也可能因为一个回答不好而通过。其实面试只有结果,没有分数。设想以下场景:
“能解释一下http协议中302这个状态码是什么吗?”,“我不记得了。” (0分)
“能解释一下http协议中302这个状态码是什么吗?”,“哦,记不清了,我只记得404是找不到页面,304是可以从缓存读取,5xx是服务端错误” (加分,了解一定http状态)
“能解释一下http协议中302这个状态码是什么吗?”,“啊,那个,应该是服务端错误吧?”(倾向于面试不通过,不了解的时候尝试猜测蒙混,这种特质对工作不利)
你看,同样的一个问题,同样是应聘者不知道问题的答案的情况,结果却大相径庭。
所以,面对面试题,过程重于结果,纠结于题目、准备答案是不会有任何意义的。
面试时该如何做呢?以下是我的几点建议:
- 厘清问题,必要时可以跟面试官沟通确认,避免误解,不但理解问题,还要同时思考面试官的意图
- 不急于开始回答,可以先分析问题,列举实际案例,争取思考时间
- 不限于回答问题,可以以对面试官意图的理解为基础,主动讲解相关知识,展示自己对相关领域的体系化思考
- 正面承认自己了解和不了解的东西,不敷衍,不猜测,有记不清的地方,可以正面要求面试官提示
以上四点,都是只有面试场景才能够使用的,这也是为什么我说“面试和考试不同”。
关于争论
技术相关岗位中,常常有这样的抱怨:“面试官技术比我弱怎么办?面试官跟我争论技术问题怎么办?”
通常情况下,面试官不应该也不会跟应聘者讨论技术问题本身,比如我,如果觉得应聘者回答错误,会尝试以追问的形式考查应聘者能否自圆其说,一些概念性错误,我则会追问其来源出处,直到对方无法回答。
当然,不怕一万,就怕万一,作为应聘者,万一遇到了这样的事情,而且面试官真的错了怎么办?
虽然面试官在这样的场景下天然强势,但其实也不是完全没有办法,有三点,至少可以缓解问题:
一、不要正面否定对方,尝试认同对方观点合理性,再从侧面反驳。
二、展示推理过程,从双方共同认可的观点出发,层层推理得出你的结论,在过程中,不断跟面试官讨论确认。
三、引述出处,使用专业词汇,使得面试官对你的观点天然产生敬畏,不敢草率否定。例如:
“说说为什么JavaScript是一门基于对象的语言而不是面向对象的语言?” “JavaScript明明就是面向对象啊?”(惨死,还是冤死)
“说说为什么JavaScript是一门基于对象的语言而不是面向对象的语言?” “哦,JavaScript的语言规范ECMA262的序章里面提到过JavaScript是面向对象的语言,而ECMA262名词解释里也提到了JavaScript是基于对象的语言。在它这个定义里面,面向对象是指以对象为主要抽象工具,描述逻辑,基于对象是指基础库和运行时设施,以对象为基础来设计。所以JavaScript既是面向对象,又是基于对象。JavaScript是基于对象的语言而不是面向对象这个说法我好像也听过,但是记不太清了,因为觉得语言规范比较权威嘛,呵呵”(说的有凭有据,又留足面子,至少得回去掂量一下……)
其实“不靠谱的面试官”很少出现,这样的突发情况并不是总能处理好,我们要尽最大努力,剩下的就凭运气了……
关于简历
一个人合适不合适,在面试前就决定了大半。一个简历看上去合格的应聘者,面试阶段可能只是确认简历上内容的真实性罢了。
有些应聘者,尤其是应届生特别容易受到各种传奇故事的感染,追求出位。其实简历只是信息的载体,不管它有多好看,不管你制作的多认真,最重要的还是它的内容。
所以,简历上最重要的是什么呢?各个岗位有所不同,下面是我对技术岗位的简历上比较看重的内容:
- 工作履历,尤其是上一份工作,公司名是否听过,公司档次,如BAT、FLG,岗位
- 教育经历,是否是top2 是否是国外名校,是否是985、211学校,是否有ACM竞赛获奖经历
- 技术社区贡献,blog是否有深度内容,是否有稳定更新,github上有没有高质量开源项目
- 项目经历,项目的规模,复杂程度,其中体现的
- 个性化内容:技术视野,个人成长经历,个人研究内容,学习方法
写简历的时候,首先要明白,HR或者主管查看简历的时候,一般只会花费1分钟,于是有以下几点建议
- 这其中次要信息越少,重要信息就越突出
- 任何复杂的排版方式,都会加大阅读困难
- 变色强调非常有用,可以突出重点,但是到处变色强调是灾难
- 技能列表,精通和熟悉,这些内容价值不高,偶尔还会惹麻烦
应届生常犯的错误是使用网上的各种简历模板,然后拼凑内容。没有项目经历硬造项目经历,找一些亲友开的公司硬挂靠顾问甚至总裁助理职位,这些东西会阻碍面试官看到真正有价值的内容。
正确的写简历方式是用一张白纸,先写好必要的个人信息和联系方式,然后列出所有你觉得自己做过的有价值的事和拿到的荣誉,按照从重要到不重要依次排列,再做简单的分类组织。
然后,问题来了,对很多人来说,这个列表是空的?怎么办?
我的建议是,既然是空的,那就不写,请把经历放在个性化内容上,从技术视野,个人成长经历,个人研究内容,学习方法中,选择一项,深入谈谈你做过的努力,这些也有可能打动面试官,比硬性拼凑的内容强过百倍。
了解招聘方
了解每个企业的部门结构和招聘节奏,非常有利于拿到offer。咳咳,现在是广告时间:
阿里巴巴的校园招聘分为春秋两季,每一季招聘又分为提前批次、正式招聘和补招三部分。
提前批次招聘不论是否通过都不影响参加后续招聘,是阿里各部门独立运作的招聘阶段,可谓额外的福利,可以找阿里内部的师兄师姐帮忙推荐到想去的部门,注意这个时候是没法改部门的,如果你有明确意向,务必说明。
正式招聘是阿里集团统一的招聘,会到全国主要城市面试,需要先通过网上答题笔试。如果笔试不过,霸王面也有微弱几率获得面试机会。
补招只针对未能参加校招面试的同学,会持续比较长时间,但是除非有特别情况正式招聘不通过的情况下无法参加。
现在正是提前批次招聘,对阿里无线前端有兴趣的同学,请投简历到 [email protected]
今年我们前端团队也在尝试变革,所以有Java和全栈岗位开放,同样投 [email protected]
简历请投 [email protected] 重要的事情说三遍。
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.