JavaScript 中对变量和函数声明的“提前(hoist)”

 

hoist
vt.升起,提起;
vi.被举起或抬高;
n.起重机,升降机; 升起; <俚>推,托,举;

这篇文章不讲英语,但是对于某些英语单词找不到很好的翻译,一上来就列出“hoist”这个单词的释义是为了让大家有个准备,我在这里将此单词翻译为“提前”,是为了解释 JavaScript 语言中很“古怪”的一个特性。

变量声明“被提前”

JavaScript 的语法和 C 、Java、C# 类似,统称为 C 类语法。有过 C 或 Java 编程经验的同学应该对“先声明、后使用”的规则很熟悉,如果使用未经声明的变量或函数,在编译阶段就会报错。然而,JavaScript 却能够在变量和函数被声明之前使用它们。下面我们就深入了解一下其中的玄机。

先来看一段代码:

(function() {
  //ReferenceError: noSuchVariable is not defined
  console.log(noSuchVariable);
})();

运行上面代码立马就报错,不过,这也正是我们期望的,因为 noSuchVariable 变量根本就没有定义过嘛!再来看看下面的代码:

(function() {
  // Outputs: undefined
  console.log(declaredLater);

  var declaredLater = "Now it's defined!";

  // Outputs: "Now it's defined!"
  console.log(declaredLater);
})();

首先,上面这段代码是正确的,没有任何问题。但是,为什么不报错了?declaredLater 变量是在调用语句后面定义的啊?为什么居然输出的是 undefined

这其实是 JavaScript 解析器搞的鬼,解析器将当前作用域内声明的所有变量和函数都会放到作用域的开始处,但是,只有变量的声明被提前到作用域的开始处了,而赋值操作被保留在原处。上述代码对于解析器来说其实是如下这个样子滴:

(function() {
  var declaredLater; //声明被提前到作用域开始处了!

  // Outputs: undefined
  console.log(declaredLater);

  declaredLater = "Now it's defined!"; //赋值操作还在原地!

  // Outputs: "Now it's defined!"
  console.log(declaredLater);
})();

这就是为什么上述代码不报异常的原因!变量和函数经过“被提前”之后,declaredLater 变量其实就被放在了调用函数的前面,根据 JavaScript 语法的定义,已声明而未被赋值的变量会被自动赋值为 undefined ,所以,第一次打印 declaredLater 变量的值就是 undefined,后面我们对declaredLater 变量进行了赋值操作,所以,第二次再打印变量就会输出Now it's defined!

再来看一个例子:

var name = "Baggins";

(function () {
    // Outputs: "Original name was undefined"
    console.log("Original name was " + name);

    var name = "Underhill";

    // Outputs: "New name is Underhill"
    console.log("New name is " + name);
})();

上述代码中,我们先声明了一个变量 name ,我们的本意是希望在第一次打印 name 变量时能够输出全局范围内定义的 name 变量,然后再在函数中定义一个局部 name 变量覆盖全局变量,最后输出局部变量的值。可是第一次输出的结果和我们的预期完全不一致,原因就是我们定义的局部变量在其作用域内被“提前”了,也就是变成了如下形式:

var name = "Baggins";

(function () {
    var name;  //注意:name 变量被提前了!

    // Outputs: "Original name was undefined"
    console.log("Original name was " + name);

    name = "Underhill";

    // Outputs: "New name is Underhill"
    console.log("New name is " + name);
})();

由于 JavaScript 具有这样的“怪癖”,所以你会看到很多编码指南建议大家将变量声明放在作用域的最上方,这样就能时刻提醒自己注意了。

函数声明“被提前”

前边说的是变量,接下来我们说说函数。

函数的“被提前”还要分两种情况,一种是函数声明,第二种是函数作为值赋值给变量。

先说第一种情况,上代码:

// Outputs: "Yes!"
isItHoisted();

function isItHoisted() {  
    console.log("Yes!");
}

如上所示,JavaScript 解释器允许你在函数声明之前使用,也就是说,函数声明并不仅仅是函数名“被提前”了,整个函数的定义也“被提前”了!所以上述代码能够正确执行。

再来看第二种情况:函数作为值赋值给变量。(还记得吗?在 JavaScript 中,函数也可以作为值赋予变量!)还是先上代码:

// Outputs: "Definition hoisted!"
definitionHoisted();

// TypeError: undefined is not a function
definitionNotHoisted();

function definitionHoisted() {  
    console.log("Definition hoisted!");
}

var definitionNotHoisted = function () {  
    console.log("Definition not hoisted!");
};

我们做了一个对比,definitionHoisted 函数被妥妥的执行了,符合第一种类型;definitionNotHoisted 变量“被提前”了,但是他的赋值(也就是函数)并没有被提前,从这一点上来说,和前面我们所讲的变量“被提前”是完全一致的,并且,由于“被提前”的变量的默认值是 undefined ,所以报的错误属于“类型不匹配”,因为 undefined 不是函数,当然不能被调用。

总结

通过上面的讲解可以总结如下:

  • 变量的声明被提前到作用域顶部,赋值保留在原地
  • 函数声明整个“被提前”
  • 函数作为值赋给变量时只有变量“被提前”了,函数没有“被提前”

通过练习上面的实例自己多感受一下。另外,作为最佳实践:变量声明一定要放在作用域/函数的最上方(JavaScript 只有函数作用域!)。

参考文献

来源:http://www.bootcss.com/article/variable-and-function-hoisting-in-javascript/

公司招聘

公司项目需要扩充2名PHP,1名前端,1名UI。有意请将简历发送到lmcdwd#gmail.com

工作地:成都  薪资待遇为成都地区中上水平

中级PHP开发工程师(2)

岗位职责

负责公司商城项目PHP开发,配合前端实现数据接口对接。

岗位要求

1. 两年以上php,mysql网站开发经验。

2. 熟悉至少一种PHP框架的使用

3. 熟悉LAMP环境搭建。

4. 有配合前端ajax开发网站经验

5. PHP项目性能优化有一定的了解。

6. 有多人共同开发项目经验;

7. 有良好的团队合作能力和学习能力。

 

加分项

1. 熟悉yii框架者优先。

2. 有商城相关开发经验者优先。

 

中级前端开发工程师(1)

岗位职责

负责公司商城项目前端开发,根据设计制作页面并实现JS交互效果。

岗位要求

1.  2年以上前端开发经验。

2. 熟练掌握DIV+CSS布局技巧。了解IE系列浏览器兼容性问题,熟练解决浏览器兼容性问题。

3. 熟悉javascript,熟练使用JQ完成动态交互功能。

4. 对前端性能优化有一定的了解。

 

加分项

  1. 了解模块化开发了解AMD,CMD规范。
  2. 会使用seajs
  3. 会使用FIS

UI设计师

任职要求:

1、精通 Photoshop、Flash、Dreamweaer、illustator 等;
2、熟悉 Html、css+DIV 、JavaScript;
3、有较强的平面设计感觉及良好的美术基础、审美能力和创意,色彩感强;
4、有良好的学习能力、沟通能力和领悟能力,能够承受较大的工作压力;
5、有良好的团队合作意识,耐心、诚恳,有强烈的责任心和积极主动的工作态度;
6、1年以上网站设计相关经验,熟悉网站建设流程,对设计潮流把握准确 ;
7、请投递简历时附带作品。界面设计经验,熟悉网站开发流程;
8、有团队合作精神,勇于学习专研;
9、有工作经验者优先录用。

阿里前端的困局与突围

c9b65e2c86bf60ac89a4bfef2f7cdbc691ae61d41848e-LdbCtj_fw580

  最近发了两条微博:

想起克军的一句话:前端研究,研究个屁~ 的确如此呀。补充下联:前端设计,设计个屁~

前端目前最大的困境是,如 HTML 一样,无论你承不承认,市场上并不太需要 HTML 高手。

微博上的回复大部分歪楼了。上面两句话乍看有点激进,却是我的真实想法。

背后是一个问题:

前端的价值究竟是什么?未来应该如何发展?

前端的价值

如果你刚入行,或者从事专职前端工作未满 3 年,请忽略上面这个问题,并且尽量不要再往下看了。

我知道你会忍不住往下看,那就看吧。负能量有时也是正能量。真实面对所做的事,如实面对自己的真心,这是迟早的。有过痛,才真正懂得乐。

特别注意,下面说的前端,都是阿里的前端,其他公司切勿对号入座,每个公司的情况都不同。每个公司,前端的定位也会有差异。

阿里的前端,目前主要分两种:一种在 UX / UED 部门,另一种在技术部门,所做的事大同小异,都是负责界面交互层的开发。上游是 PD、交互、视觉等,下游是后端开发人员、测试等。技能主要是 HTML、CSS、JavaScript,有些前端团队比如支付宝还直接负责 Velocity 等模板层的开发。这是阿里目前前端的现状。

前端是后端数据的第一消费者,也是最贴近用户的程序员。

一切看起来很美。

前端的价值在哪呢?很多人会回答:

  1. 实现界面交互。
  2. 提升用户体验。

第一点是前端的本职工作,也是前端岗位存在的原因。第二点也不多说,前端做得好,对用户体验是有益的。

让人纠结的,是前端有价值,可是,这价值真的很重要吗?真的值得做为一个职业投入一辈子吗?

做技术的,可能都会有类似纠结。但传统技术,纠结相对少点。比如搞数据库的,有一堆牛人榜样,搞网络、安全等等的,也是如此。这个现实的背后,是因为:

这批传统技术的背后,无论是数据库底层优化,还是网络优化、安全防范等等,做得好,对业务都能直接产生影响,比如大幅度降低硬件成本等等。 价值是直接的,可见的,不太会被质疑。

然而前端的价值,没有人会直接否认,但看得明白的,都知道:

淘宝的核心用户体验,并非是 UI 层面带来的,而是 C2C 的模式,是同等品质下商品的价格,还有支付宝的便捷等等。前端的确很重要,但真的,也就那么着。比如京东,很多交互细节做得其实不咋的,但京东靠着靠谱的物流、货到付款等方式提升了整体购物体验。对阿里来说,用户体验非常非常重要,但前端在用户体验层面能做的其实很少很少。

一个事实:

把国内大部分公司的 UX 部门解散掉,也不会太影响产品的体验。在国内,UX 主要还是起到美工的作用,虽然我不想承认。

前端依旧是美工,而且仅仅是实现工。

在阿里,我们不得不承认一个事实:**前端的确有价值,但放在全局来看,前端产生的价值并非核心价值。** 在阿里,虽然前端的工作已经不可或缺,但对大公司而言,不可或缺的岗位多了去呢,不可或缺不代表有核心价值,我就不说了。

前端的未来发展

前端,往后是技术,往前是体验。我的理解,前端的未来发展,有两个方向:

  1. 前后端体系的融合,技术平台化。 范例是 Google、Facebook 等公司的技术体系,不细分前后端,都是 Web Developer,在整套技术平台上,Developer 都可以从后到前高效开发。技术平台本身由 Engineer 维护,有各个领域的高手,包括前端的。
  2. 前端技术带来的体验革新,成为某些产品的核心竞争力。 典型的比如 Path,国外有很多创新型项目,体验是核心竞争力之一。在这类产品中, 前端带来的用户体验很关键。

然而,上面两个方向,在阿里的现状下,困难重重:

  1. 技术平台化之路很难。 阿里现有的技术体系,前端只是薄薄的一层,要靠这薄薄的一层,来渗透甚至改革现有前后端开发模式,非常困难。支付宝算是走在前面,已经摸索了一年多,但越来越觉得,前端的绝大部分问题,其实都需要后端才能解决。去跨团队推动也可以,因为难,所以前行也挺有挑战挺有意义。可是,更悲催的事实是,技术平台化,前后端开发模式的融合,目前来看,并不是阿里的痛点,还没有到这一步,没这个强烈需求。需求不强烈,意味着缺了“天时”。很希望我的想法是错的。前后端的技术平台化之路,还有一个很现实的问题是,马云留下的隐患:平凡的人去做非凡的事。虽然现在有意不提这句话了。这句话很伤人,特别是技术人员,然而事实就是事实。即便技术平台能建成,在平台之上,阿里现有的开发人员,无论是前端还是后端,很多人可能还欠缺了不少能力。Facebook、Google 等玩起来,有个重要因素是精英文化。这话题不多说。现实的残酷,虽然也有方法是改变。
  2. 体验创新之路也非常难。 在淘系可能相对好点,在支付宝,前几年首要的问题是安全、稳定,接下来几年之内,依旧是安全、稳定。创新受产品形态的影响非常大,没有一个好的产品,妄谈创新。可以有不少微创新,可以有很多小而美,但目前都触不到痛点,隔靴搔痒。真正承担阿里用户体验的,是 CDN 团队、是数据库团队、是 PD、是运营、是大安全…… 继续希望我是错的。

以上两个方向,虽然困难重重,但在一些新领域,却充满机会与希望:

  1. 无线领域。 未来是属于无线的,这话说到心坎上。目前阿里的无线才起步,起步意味着百废待兴。无论是前后端的技术体系,还是产品的体验创新,在无线领域,前端的机遇与挑战都很多。并且其价值,有可能变成核心价值。这一点,希望我的判断是对的。(编者注:在阿里“移动”叫“无线”)
  2. Node.js 领域。严格来说是 JavaScript 程序员的新舞台。通过 Node,前端程序员可以摇身一变,变成传统程序员。数据库、网络、业务架构等等技术核心领域,都可以通过 JavaScript 来达成。Node 社区是迷人的。同样,希望我的判断是对的。

上面的分类有点混乱,下面继续乱谈:

  1. 创业。 在很多产品中,前端虽然很难产生核心价值,但在有竞争的地方,附属价值经常会成为核心竞争力。比如出去创业,如何在大量同类产品中脱颖而出,前端界面层的实现非常关键。可是,无论是淘宝,还是支付宝等,目前都已经过了初期创业期。有时真希望,易趣如果还强大着该有多好。
  2. 转行。 的确,没必要因为懂 JavaScript,就一辈子做前端。没必要限定自己的发展,可以做 2-3 年前端,然后再去做 2-3 年开发,还年轻的话,可以继续尝试各种岗位,说不定,10年后,就变 CTO 了。

从人的一生来看,前端只是一段很小的旅途。它能带给你我们的已经不少,舍弃惯性,脱离舒适区,长远来看才能走得更远。放弃有时也是坚持,重要的是你心中的梦是什么。

感悟与坚持

纯技术上,前端目前的很多发展,只是在满足业务,并没有真正对业务带来“从无到有、促进变革”的变化。从公司的角度讲,并不需要那么多前端牛人。这是我那条说 HTML 高手是屠龙术的微博的含义。

另一个角度上,前端技术这些年的变化,无论是 YUI 的发展、还是最近两三年兴起来的模块化开发理念、以及 Node.js 带来的前端工具变革、还有 Backbone 等类库背后的 MVX 的发展,这些都切实推动着前端往前发展,虽然很慢很慢,虽然短时间内很难直接影响业务价值,但我相信,这类工作的价值,也很大。

一类是直接促进业务发展,一类是缓慢带动人员的成长。这两类工作,都非常有价值。一个着力于现在,一个发力于未来。

看起来,路都很清楚。然而我们都是人不是神。最后以一段人与人之间的对话来结束这篇充满负能量的文章:

章小新:有一个现实是,如果在这块上长时间的价值不被认可,那很有可能真正产出的价值没有我们想想象的大,是否是我们自己深限其中? 有时虽然不想往这方面想,但又是不得不仔细深思的问题。

玉伯:毕竟我们都是人,要坦诚面对自己的真心,包括贪欲。比如一个事,如果做了 5 年,依旧得不到直接认可,也没更多物质上奖励,我估计你也很难做下去了,或者就是打着酱油,干着其他有意思的事情去了。

章小新:哈,今天的话题的确是沉了点,今天上午还和同事们讨论过~~~ 先认清自己,再从容微笑去面对。

玉伯:从容微笑谈何容易。从容微笑的一个前提是,认清了自己,找到了今后要走的方向,知道接下来该怎么走下去。

李牧:这么说好像我有多么淡定一样。。其实没有了。会很计较,但是现实面前了。

玉伯:从容不是有希望,也不是在路上,而是自己喜欢自己做的事情。又变鸡汤了,不过发现很多鸡汤越来越有道理,得真心去信。真正的认可是自己给自己的。

柏林:我不是做前端的,一直在关注大家。 呵呵。看到这句话蛮有感触,要体验过鸡汤的过程,才能品味到真实的味道。(说得不好哈)

(完)文 / 玉伯

PS:把这篇文章发出来,很犹豫。把这些想清楚的事情说出来,虽然可能会影响团队士气,会打击工作不久的前端,但隐瞒更不可取。 前端还很年轻,如何发展,如何前行,需要所有前端们一起来思考。我们需要未来,也需要真实。我们不需要的是混日子。我们往哪里去,取决于我们自己。

来源:http://kb.cnblogs.com/page/190205/

图片裁剪项目 Tclip

名字说明:

T开头,代表是淘宝开源
clip,读[klip],译为裁剪。
Tclip,意为淘宝开源的图片裁剪项目。

概要:

用于图片裁剪。有以下特点:
1.能进行人脸识别。图片中有人脸,将自动视为人脸区域为重要区域,将不会被裁剪掉。
2.自动识别其它重要区域。如果图片中未识别出人脸,则会根据特征分布计算出重区域。
总而言之,自动识别图片中的重要区域,并且在图片裁剪时保留重要区域。
目前已经用于一淘玩客  http://wanke.etao.com

效果演示:

原图:

如果按照从中间截取为 400 * 225 大小大图片。效果如下:

使用tclip裁剪图片效果如下:
 原图:

如果按照从中间截取,效果如下:

使用tclip裁剪图片效果如下:

在线演示  http://demo.bo56.com/tclip

安装步骤:

源码下载

opencv2 下载地址  http://www.opencv.org.cn/index.php/Download

安装opencv2

此扩展依赖于opencv2.0 之上版本。因此安装前先安装opencv。opencv的安装步骤如下

  1. yum install gtk+ gtk+-devel pkgconfig libpng zlib libjpeg libtiff cmake
  2. 下载 opencv2 安装包
  3. 解压安装包
  4. cd 进入安装包文件夹内。
  5. cmake CMakeLists.txt
  6. make && make install
  7. vim /etc/profile
  8. 在 unset i 前增加
  9. export PKG_CONFIG_PATH=/usr/lib/pkgconfig/:/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
  10. 保持退出后,执行如下命令
  11. source /etc/profile
  12. echo “/usr/local/lib/” > /etc/ld.so.conf.d/opencv.conf
  13. ldconfig

安装tclip扩展

  1. cd 到源代码目录中的php_ext文件夹
  2. phpize
  3. ./configure
  4. make
  5. cp modules/tclip.so 到 extension 目录
  6. 修改php.ini。加入 extension=tclip.so
  7. 重启fpm

安装命令行

如果想使用命令行方式,可以进行如下安装

  1. cd 进入安装包soft文件夹内
  2. chmod +x ./tclip.sh
  3. ./tclip.sh

使用方法说明

第一种:在php中使用格式:
tclip(文件原路径,裁剪后的图片保存路径,裁剪后的图片宽度,裁剪后的图片高度)
示例:
$source_file = “/tmp/a.jpg”;
$dest_file = “/www/a_dest.jpg”;
$width = 400;
$height = 200;
tclip($source_file, $dest_file, $width, $height);
第二种:命令行
参数说明:
-s 原图路径
-d 裁剪后的图片保存路径
-w 裁剪后的图片宽度
-h 裁剪后的图片高度
./tclip -s a.jpg -d a_dest.jpg -w 400 -h 200

除非注明,本站文章均为原创或编译,转载请注明:

文章来自KENGINE | Kankanews.com