拯救老款汽车的车载音响

目前开的是一辆2014款的别克小型SUV,安装了第三方倒车影像,车载蓝牙失效。需要找到一款蓝牙配件,让车载音响发挥作用。

AUX车载蓝牙音频线

最开始尝试带AUX接口的蓝牙配件,手机连接蓝牙配件,蓝牙配件通过AUX线连接汽车中控的AUX接口,可以听到声音,但是可能由于蓝牙配件功率不够,杂音很多,并且和车载收音机相比,音量明显偏小,达到60km/h以上车速后,存在胎噪、风噪,导航和音乐声几乎听不清。

某次在京东App首页推送中偶然发现,还有思路更巧妙的产品,通过车载收音机播放声音。这款配件的原理是,同时提供蓝牙连接、FM广播发送功能。手机通过蓝牙连接到这款配件,配件内部将手机声音转换成FM广播信号,再将车载收音机频率调整到(配件默认是87.5Hz),即可通过车载收音机播放导航、音乐、电话,音质和音量都完全正常,不受配件本身功率影响。小小的缺点是,如果手机没有正在播放的声音,收音机会存在杂音。

车载蓝牙转收音机信号

工作原理

病毒星球

疫情期间阅读量陡增,除了书架上陈封已久的技术书籍,还有一本“蹭热点”的小书:《病毒星球》。趁着还有记忆,记录一下阅读后的启发和感想。

Virus 这个词的双重含义

Virus 在拉丁文中同时具有蛇的毒液、人的精液两重意思。古罗马人让这个词同时具备了毁灭与创造的含义。

巧合的是,病毒学的研究表明,Virus 是 DNA 不断演化的动力,但同时也具有毁灭某些物种的破坏力,恰好与这个词的原本含义相响应。

关于病毒预防的成本与策略

此次疫情,精于商业计算的英国人在疫情早期提出的“群体免疫”,并不是毫无道理,只是当代价是上万人生命的时候,需要更仔细地掂量掂量,是不是所有代价都能用经济指标、用货币来衡量。

关于病毒/疾病的命名

书中提到1918年那场流感时,刻意避免了“西班牙流感”这一传统名称。这个细节体现了作者的严谨与体面,与2020年某些大国领导人形成了鲜明的对比。

进化的原动力

进化论有三个核心

  1. 过度繁殖
  2. 基因突变
  3. 自然选择

但长久以来,基因突变的原因却没有令人信服的解释。读完这本书后,我猜想:病毒对宿主的“篡改”,可能正是基因突变的原动力。

病毒怎么预防?

答案:防不住。

正如书中所说,生命的本质是DNA的组合。从这个视角看,自认为“万物之灵”的人,其实并不比病毒更高贵。

原本就没有什么“它们”和“我们”之分——生物在本质上只是一堆不断混合、不断闪转腾挪的DNA而已。

吃野味到底有没有风险

答案:有。

为什么有人要尝试制造病毒?

本州见闻

年前跟团(实在没有时间做自由行的攻略)去了一趟日本,趁着还有些许印象,写点零碎的见闻。

车让行人,不只是挂在嘴边。晚上在大阪市区散步,路过一个小巷子的路口时,一辆车正好从我们面前开过拐进巷子,应该是驾驶员没注意到我们在过马路,副驾驶上的女士发现我们停下脚步让车先过,一直不停地挥手哈腰道歉。
餐饮贵。一不小心就人均过百。
空气好,水好,极度干净。
城乡差距小。

上网用的是环球漫游随身 Wifi,15块1天,续租10块钱一天(这个定价很奇怪,我只租一天,然后一直续租,不是更便宜?)

大阪

亲身去了大阪,才更能理解大阪军团的故事。不过这些故事恐怕是中国人的意淫罢了,知乎上有更加客观独立的说法

京都

奈良

箱根

泡温泉十分考验身体素质,泡个几分钟就得出来休息。

在冰冷冬天的室外,泡着热水,一抬头就看到星空,是一种无法形容的神奇感觉。

此处本应有照片,无奈泡温泉不能带手机。

东京

城市规划有迹可循,整体格局依然延续了明治维新时定下的框架。反观国内的大拆大建,让人痛心。

晚上来到东京铁塔欣赏东京城市夜景,十分壮观。

东京夜景

阳光下的阴霾

下午太阳快落山的时候,我们来到了靖国神社。

门口的告示牌上用中日韩三国文字告诉中韩游客:“非参拜谢绝入内”。不过真要进去也只是有人远远地盯着,并不上前阻拦。

靖国神社里小路旁的展示牌上,日本人把近代对亚洲邻国的侵略,描述成“指导亚洲各国的民族独立运动”。可能指的是朝鲜、台湾、满洲、菲律宾等地方日占时期的傀儡政权。

从神社出门,经过长长的神道,可以来到神社入口处。入口两侧分别有一座纪念碑,纪念碑底部的浮雕描绘的是近代日本军人的“战功”,除了对马海战是关于俄国(露西亚)之外,其他浮雕全部都关于中国,有甲午战争(黄海海战)、长城、奉天、上海等等。下面是几块浮雕上的文字:

黄海海战
明治二十七年九月十七日我联合舰队清国北洋水师击破

上海事变动发
昭和七年一月二十八日我海军陆战队八十倍敌……武威发扬

一二八事变浮雕

我们被侵略的惨痛历史,对日本人来说却仍然是“帝国余晖”的残存记忆。

看到这些浮雕和文字,我们心里大概会明白,历史还没有结束,恩怨还没有了结。当前大家各自发展相安无事,等到下一个衰退期,历史又会转向何处呢?

彼得·蒂尔谈美国大选

谁是 Peter Thiel?

Peter Thiel 是 Paypal 联合创始人,硅谷投资人,《从0到1》作者。Peter Thiel 向来以敏锐的眼光和独到的见解出名,用他自己的话说,叫“反主流观点”。

2016年川普竞选期间,Peter Thiel 是唯一公开支持川普的硅谷大佬。

不妨阅读演讲原文,了解 Peter Thiel 的具体想法。

全文听译

Peter Thiel FULL Speech Supporting Trump at National Press Club - October 31, 2016

原视频链接:https://www.youtube.com/watch?v=AfYLEPRiIyE

Thank you very much for having me here.

有机会来到这里演讲,非常感谢。

Everybody knows we’ve been living through a crazy election year. Real events seem like a rehearsal for Saturday night live. Only an outbreak of insanity would seem to account for the unprecedented fact, that this year a political outsider manage to win a major party nomination. To the people who are used to influencing our choice of leaders, to the wealthy people who give money, and the commentators who give reasons why, it all seems like a bad dream. Donors don’t want to find out how and why we got here. They just want to move on. Come November 9th, they hope everyone else would go back to business, as usual.

我们刚刚经历了一次疯狂的大选。以前只在周六晚间剧场上演的情节,现在成了现实。一位毫无从政经验的人,赢得了主要党派的提名,这不仅史无前例,更是疯狂至极。对于那些习惯于舆论引导的大V、出钱资助的富豪,以及分析得头头是到的评论员们,这是一场噩梦。捐助者们不会去反思我们是如何走到这一步,他们只希望当大选结束的时候每个人都若无其事地回到自己的工作岗位上。

But it’s just this headlessness, this temptation to ignore difficult realities, indulged in by our most influential citizens, that got us where we are today. A lot of successful people are too proud to admit it, since it puts their success in question. But the truth is, no matter how crazy this election seems, it is less crazy than the condition of our country.

我们中最有影响力的那些人倾向于忽视现实中的难题,正是他们的这种漫不经心,导致了我们当下的处境。「成功人士」们太过清高,不愿承认这一点,因为承认事实会让他们的成功受到质疑。但事实上,我们国家所面临的现状比这次选举本身更加疯狂。

Just look at the generation that supplies most of our leaders. The baby boomers are entering retirement in a state of actuarial bankrupcy: 64% of those over the age of 55 have less than a year’s worth of savings to their name.

看看正在领导国家的这代人吧,婴儿潮时期出生的人们正面临退休,但是他们却处于行将破产的境地:55岁以上的人中,有64%人名下的存款只能支撑不到一年。

That is a problem, especially when this is the only country where you have to pay up to 10 times as much for simple medicines as you would pay anywhere else. America’s over priced health care system might help subsidize the else of the world. But that doesn’t help the Americans who can’t afford it. And they’ve started to notice.

存款过少本身就是一大问题,何况我们的医疗费用比世界其他地方要贵10倍。美国过于昂贵的医疗系统或许可以补贴世界上的其他地区,但是对于负担不起的美国民众毫无意义。并且民众们已经开始意识到这个问题。

Our youngest citizens may not have huge medical bills, but their college tutition keeps increasing faster than the rate of inflation, adding more every year, to a 1.7 trillion dollar amount of student debt. America has become the only country where students take on loans that they can never escape, not even by declaring bankrupcy. Stuck in this broken system, Millennials are the first generation who expect their own lives to be worse than the lives of their parents.

年轻人没有这么大的医疗开销,但他们的学费增长速度却超过了通货膨胀率。美国的学生贷款已经达到了1.3万亿,并在继续逐年增长。美国的学生背负了无法摆脱的债务,也无法宣布破产,这在世界上其他国家闻所未闻。00后这代人深深地陷入了这种垮掉的体制当中,他们的生活水平可能会史无前例地低于自己的父辈。

While American family expenses have been increasing relentlessly, their incomes have been stagnant. In real dollars, the median household makes less money today than they made 17 years ago. Nearly half of Americans wouldn’t be able to come up with 400 dollars if they need it for an emergency.

美国家庭的开销急剧增长的同时,收入却停滞不前。折算成实际购买力,美国中产家庭的收入比17年前低。将近一半美国人拿不出400美元来应急。(注:该数据存疑,点此查看)

Yet our households struggle to keep up with challenges of everyday life, the government is wasting trillions of dollars of taxpayer money on faraway wars. Right now, we’re fighting five of them, in Iraq, Syria, Libya, Yemen, and Somalia.

面对国内民众生活上的挑战,政府却在遥远的 战争上浪费数万亿美元的税收。现在,我们正在五个地方打不宣而战的战争:伊拉克、叙利亚、利比亚、也门和索马里。

Now, not everyone is hurting. In the wealthy suburbs that ring Washinton D.C., people are doing just fine. Where I work in Silicon Valley, people are doing just great. But most Americansf don’t live by the belt way or the San Francisco Bay. Most Americans haven’t been part of that prosperity. It should’t be surprising to see people voting for Berny Sanders, or for Donald Trump, who is the only outsider left in the race.

但并不是每个人都能体会到生活的艰难。在环绕华盛顿的富裕地区,在我所工作的硅谷,生活水平依然很不错。但绝大多数美国人并不生活在这两个地区,他们是这场繁华盛世的局外人。看到人们把选票投给桑德斯,或者投给川普的时候,不应当感到奇怪,因为他是竞选中仅剩的「局外人」。

Very few people who vote for president have ever thought of doing something so extreme as running for president. The people who run are often polarizing. This election year, both major candidates are imperfect people, to say the least.

参与投票的普通选民中,很少有人会想着自己去竞选总统。参选的人往往是极端的。这次大选中两党的候选人,客气地说,都不太完美。

I don’t agree with everything Donald Trump has said and done. And I don’t think the millions of other people voting for him do, either. Nobody thinks his comments about women were acceptable. I agree they were clearly offensive and inappropriate. But I don’t think the voters pull the lever to endorse a candidate’s flaws.

我并不是同意川普说的每句话,也不赞同他做的每一件事。我想其他上百万投票给他的选民也不是这样。没人会接受川普关于女性的言论。我同意,这些言论显然是不恰当的。但选民把票投给他,不代表支持他的错误。

It’s not a lack of judgement that leads Americans to vote for Trump. We’re voting for Trump because we judge the leadership of our country to have failed. This judgement has been hard to accept for some of this country’s most fortunate, socially prominent people. It’s certainly hard to accept for Silicon Valley, where many people have learnt to keep quiet if they dissent from the coastal bubble.

让人把票投给川普的原因不是他们缺乏判断力。相反,投票给川普,正是因为他们认为目前的领导是失败的。对于某些最富有、最杰出的「精英」来说,这个结论难以接受。对硅谷人尤其如此,在硅谷,人们已经学会了当自己的意见与“海岸泡沫”相背时保持沉默(具体怎么理解?)。

Louder voices have sent a message that they do not intent to tolerate the views of one half of the country. This intollerance has taken on some bizzare forms. The Advocate, a magazine which once praised me as a ‘gay innovator’, even published an article saying that as of now I am, and i quote, ‘not a gay man’, because I don’t agree with their politics. The lie behind the buzzword ‘diversity’, could not be made more clear. If you don’t conform, then you don’t count as diverse, no matter what your personal background.

已经有人大张旗鼓地宣称,不能容忍另一半美国人的观点。他们对这种不宽容甚至不加任何掩饰。The Advocate 杂志曾经称赞我是「同性恋中的革新者」,现在发文称目前,不再承认我属于“同性恋者”的一员,因为我不赞同这家杂志所持的政见。他们鼓吹的「求同存异」的口号只是一个谎言。如果你不向他们政见妥协,那你就不再是「求同存异」的对象,无论你的出身、背景如何。

Faced with such contempt, why do voters still support Donald Trump? Even if they think American situation is serious, why do they think that Trump, of all people, could make it any better? I think it’s becaouse of the big things that Trump get right. For example, free trade has not worked out well for all of America. It helps Trump that the other side just doesn’t get it.

这样的蔑视并没有阻止选民们投票给川普,为什么?就算他们认为美国正面临着严重的问题,凭什么认为在所有候选人中,川普能带来改观呢?我觉得是川普在一些重大问题上做对了。举个例子,自由贸易并没有让所有美国人受益。川普能赢,是因为竞争对手没有认识到问题所在。

All of our elites preach free trade. The highly educated people who make public policy explain that cheap imports make everyone a winner, according to economical theory. But in actual practice, we’ve lost tens of thousands of factories and millions of jobs to foreign trade. The heartland has been devastated. Maybe policy makers really believe that nobody loses, or maybe they don’t worry about it too much, because they think they’re among the winners.

所有精英都是自由贸易的布道者。政策制订者受过良好的教育,根据他们学到的经济学理论,便宜的进口商品能让每个人受益。但是实际上,由于进口商品的冲击,我们失去了数以千计的工厂,数百万的工作岗位。中部地区的经济被完全摧毁。或许执政者们真的认为没有人受到了进口的影响,或许他们只是不在乎,因为他们自己是受益者。

The sheer size of the US trade deficit shows that something has gone badly wrong. The most developed country in the world should be exporting capital to less developed countries. Instead, the United States are importing more than five hundred billions dollars every year. That money flows into financial assets. It distorts our economy in favor of more banking and more financialization. And it gives the well connected people who benefit a reason to defend this status quo. But not everyone benefits, and the Trump voters know it.

美国巨大的贸易逆差说明了一定存在严重的问题。作为世界上最发达的国家,美国理应向其他国家出口资本,但是实际上却每年的进口都超过五千亿美元。这些资金流向金融机构,扰乱了我们的经济,催生出更多的银行,让我们的市场更加金融化。另外,这些资本给了那些彼此紧密联系的受益者理由,让他们去维护这一体系不被改变。但受益的是少数人,川普的支持者都看清了这一点。

Trump voters are also tired of war. We have been at war for fifteen years, and we have spent more than 4.6 trillions dollars. More than two million people have lost their lives, and more than five thousand Americans soldiers have been killed. But we haven’t won. The Bush administration promised that fifty billion dollars could bring democracy to Iraq. Instead, we’ve sqandered 40 times as much to bring about chaos.

川普的支持者们厌倦了战争。我们已经打了十五年的仗,花掉了4.6万亿美元。战争造成了两百万以上的伤亡,超过五千名美国士兵为国捐躯。然而,我们依然没有取得胜利。小布什政府承诺,五百亿美元可以建立一个民主的伊拉克。然而,我们已经花掉了比预算高出40倍的资金,却没能给伊拉克带去民主,只有混乱。

Yet even after these bipartisan failures, the Democratic Party is more hawkish today than at any time since it began the war in Vietnam. Harking back to the no-fly-zone that Bill Clinton enforced over Iraq before Bush’s failed war, now Hillary Clinton has called for a no-fly-zone over Syria. Incredibly, that would be a mistake even more reckless than invading Iraq, since most plains flying over Syria today are Russian plains. Clinton’s proposed course of action would do worse than involve us in a messy civial war, it will risk a direct nuclear conflict.

虽然经历了这么多失败,今天的民主党却比越战时更加鹰派。克林顿在伊拉克设立的禁飞区,后来布什打破了禁飞区,发起战争,但最终失败,然而现在希拉里却又提议在叙利亚设置禁飞区。希拉里的这一提议比克林顿的更危险,因为目前叙利亚上空的飞机大多是俄罗斯飞机。以前,美国只是卷入别国内战,但这次希拉里的鲁莽提议则会让我们面临直接的核战争威胁。

What explains this eagerness to escalate the dangerous situation? How can Hillary Clinton be so wildly over optimistic about the outcome of war. I would suggest it comes from a lot of practice. For a long time, our elites have been in the habit of denying difficult realities. That’s how bubbles form. Whenever there is a hard problem, but people want to believe a easy solution, they will be tempted to denying reality and inflate a bubble.

如何解释这种面临问题不缓解,却更加急切地让问题扩大的倾向呢?希拉里为何对她的政策可能导致的战争后果如此乐观?我认为,这跟决策者们此前的经历有关。长久以来,我们的「精英」养成了否认事实的习惯。泡沫就是这么产生的。一旦有棘手的问题,他们往往会否认问题的存在,并催生泡沫。

Something about the experience of the baby boomers, who’s lives have been so much easier than their parents’ or their children’s, has lead them to buy into bubbles again and again. The trade bubble says everyone is a winner. The war bubble says victory is just around the corner. But those over optimistic stories simply haven’t been true. And voters are tired of being lied to.

对婴儿潮时期出生的人们来说,生活比他们的父辈要容易得多,或许也会比他们的子女容易。这样的经历使得他们倾向于相信泡沫。贸易泡沫鼓吹者说,每个人都是赢家。战争泡沫鼓吹者说,胜利就在眼前。但这些只是过于乐观的故事,不是事实。选民们不想再上这样的当了。

It is both insane and somehow inevitable that D.C. insiders expect that this election to be a rerun between the two political dynasties who led us through the two most gigantic financial bubbles of our time. President George W. Bush presided over the inflation of a housing bubble so big that it’s collapse is still causing economic stagnation today. But what strangely forgotten is that last decade’s housing bubble was just an attempt to make up for the gains that had been lost in the decade before that. In the 1990s president Bill Clinton presided over an enormous stock market bubble, and a devastating crash in 2000 just as his second term was coming to an end. That’s how long the same people has been pursuing the same disastrous policies.

华盛顿的政客们希望这次大选只是正常的交替,之后我们自然就能渡过目前最大的两场金融泡沫,这样的想法虽然疯狂,但是也无可避免。布什任期内的房地产泡沫十分巨大,泡沫破灭的影响一起持续到今天,导致经济停滞不前。但难以理解的是,人们忘了这次泡沫的初衷是为了补偿更早一段时间的‘损失’。1990年代,克林顿总统任期内出现了一场巨大的股市泡沫,2000年他的第二个任期即将结束时,股市的破灭带来了毁灭性的后果。这几十年来,同一群人一直在坚持推行同样的错误政策。

Now that someone different is in the running, someone who rejects the false, reassuring stories that tell us everything is fine. His larger than life persona attacts a lot of attention. Nobody would suggest that Donald Trump is a humble man. But the big things that he is right about, amount to a much needed dose of humility in our politics. Very unusually for a presidential candidate, he has question the core concept of America exceptionalism. He doesn’t think the force of optimism alone can change reality without hardwork.

现在,终于有和他们不同的人参选了。这位候选人拒绝相信那些虚假的、安慰人心的、告诉人们一切都会好起来的说辞。他鲜明的个性吸引了很多注意力。没有人会认为川普是个谦逊的人。但他在重大问题上的正确立场,却展示出了当局在制订政策时所缺乏的低姿态。他对美国卓异的理念提出了质疑,认为美国不再伟大,这在总统候选人中很罕见。他认为,没有辛苦的付出,空有乐观精神,解决不了现实中的问题。

Just as much as it’s about to make America great, Trump’s agenda is about making America a normal country. A normal country doesn’t have a half a trillion trade deficit. A normal country doesn’t fight five simultaneous undeclared wars. In a normal country the government actually does it job.

尽管川普的口号是让美国再次伟大,他的政策实际上是让美国成为一个正常的国家。正常的国家不会有上万亿的贸易逆差。正常的国家不会同时打五场战争。在正常的国家中,政府需要有所作为。

And today it’s important to recognize the government has a job to do. Voters are tired to hear conservative politicians say that government never works. They know that the government was never this broken. The Manhattan Project, the interstate highway system, the Apollo Program, whatever you think of these ventures, you cannot doubt the competence of the government that got them done.

目前,重要的是承认政府理应有所作为。选民们厌倦了保守的政客们所鼓吹的政府无用论。选民们知道,纵观历史,政府从未这样破败。曼哈顿计划、洲际公路系统、阿波罗计划,不管你认为这些工程的实际价值如何,你必须承认,当时的政府有完成这些大型工程的能力。

But we have fallen very far from that standard. We cannot let free market ideology serve as an excuse for decline. No matter what happens in this election, what Trump represents isn’t crazy, and it’s not going away. He points toward a new Republican Party beyond the dogmas of Reaganism. He points even beyond the remaking of one party, to a new American politics that overcomes denial, rejects bubble-thinking, and reckons with reality.

然而,目前的政府远远达不到这个标准。我们不能让自由市场理论成为经济衰退的借口。无论这次选举的结果如何,川普所代表的理论念并不是一无是处,也不会凭空消失。在里根主义的教条之外,他指出了一个新的执政方向,一种新的政策思路:不否认困难不制造泡沫不忽视事实

When the distracting skeptical of this election seasons are forgotten, and the history of our time is written, the only important question will be: whether or not that new politics came too late.

当后人书写这个时代的历史时,那些嘈杂的怀疑论调会被遗忘,唯一重要的问题是:这样的新政是否来得太晚。

Thank you.

谢谢。

《Python 基础教程》笔记

第1章

幂运算符:**,不是^
长整数:在整数结尾加上L,如:100000000000000000000L

Python 3中,print 从语句变成了函数,print 42 要写成 print (42)

在UNIX系统下,在脚本开头加上 #!/usr/bin/env python 可以让脚本像普通程序一样执行,不需要显式地使用Python解释器

Python 3.0 已不再使用反引号,应该使用 repr() 函数

inputraw_inputinput 需要用户输入合法的 Python 表达式。Python 3.0 中,raw_input 被重新命名为 input

原始字符串 r’c:\windows’(类似 Objective-C 中的 @“”?)
原始字符串的最后一位不能是’'
原始字符串在写正则表达式的时候很有用

Unicode 字符串 u’hello, world'

第2章 列表和元组

两种主要的容器:序列和映射。序列一共有六种,包括列表和元组(不可变列表),还有字符串、Unicode字符串、buffer对象、xrange对象。

注意:负数索引

通用序列操作:索引、分片(slicing)、加、乘;计算长度、最大最小值;迭代。

slicing 的应用:复制表

1
2
>>> x = [1, 2, 3]
>>> y = x[:]

检查成员资格(某元素是否在容器中):in 运算符。

list,将字符串转换为列表

1
2
>>> list(‘hello’)
[ ‘h’, ‘e’, ‘l’, ‘l’, ‘o’ ]

分片赋值。可插入与原分片不等长的列表。可以利用分片赋值实现删除元素。

列表方法:append, count, extend, index, insert, pop, remove, reverse, sort

tuple 函数(其实不是函数,是类)可以将序列转换为元组

关于元组,这句话很精辟:

除了创建元组和访问元素之外,也没有太多其他操作。

元组的作用:元组可以在映射中当作键使用(?);很多内建函数和方法的返回值是元组。

第3章 字符串

格式化字符串时,如果字符串本身包括 ‘%’,需要使用’%%’的形式。

字符串格式化(这部分写得很全面)

字符串方法:find, join, lower, replace, split, strip, translate

第4章 字典

字典是 Python 唯一的内建映射类型。

dict 函数,从列表或其他映射建立字典

?什么是关键字参数。例如:从关键字参数建立字典 d = dict(name='michael', age=42)

使用字典格式化字符串,%后面使用括号,表示这里是一个字典的 key

字典方法: clear, copy, fromkeys, get, has_key, items, iteritems, values, itervalues, keys, iterkeys, pop, popitem, setdefault, update,

注意,popitem 实际上是 随机 弹出一个值,因为字典不保存 items 的顺序(在 JavaScript、JSON 中也是这样)。

第5章 条件、循环和其他语句

赋值语句

交换两个变量的值:x, y = y, x。这里用到的特性叫做“序列解包(sequence unpacking)”。处理返回元组的函数,序列解包特性十分有用:key, value = dict.popitem()。。

Python 3.0 之前,不兼容类型比较(例如比较一个整形数和一个字符串)不会导致语法错误,但是结果是不可预期的。Python 3.0 起,不再允许比较不兼容类型。

短路逻辑(惰性求值)示例:name = raw_input('input name...') or 'unknown'

只要能使用 for 循环,就不要用 while 循环。

zip() 函数可以将两个序列压缩到一起。

使用 for item in list: 处理列表时,如果需要得到 index,可以使用 enumerate() 函数:for index, item in enumerate(list):

在循环中使用 else 子句,表示循环没有被 break 语句打断而跳出。

1
2
3
4
5
6
7
8
9
from math import sqrt
for n in range(99, 81, -1):
root = sqrt(n)
if root == int(root)
print n
break
else:
print "didn't find it!"

列表推导:用其他列表创建新列表。可以结合条件判断语句:

[x*x for x in range(10) if x % 3 == 0]

命令空间类似于不可见的字典。

第6章 抽象

文档字符串

1
2
3
def square(x):
'计算x的2次方'
return x ** 2;

函数的位置参数与关键字参数。关键字参数结合默认值使用,非常方便。

收集参数(不确定参数个数),将其后的所有参数收集到一个元组中。
关键字参数需要使用 **,将关键字参数整理到一个字典(不是元组)中。

作用域可以理解为一个不可见的字典。

嵌套作用域与闭包。

第7章 更加抽象

面向对象 三原则

  • 封装
  • 继承
  • 多态

封装和多态有些类似,但出发点不同。封装侧重于调用者不必知道方法的具体实现,多态侧重于要使用某个方法时不必去管对象具体属于哪个类型。

这里使用 isinstance 进行类型检查是为了说明一点,类型检查一般来说不是什么好方法,能不用则不用。

因为 isinstance 进行类型检查破坏了代码的多态性。

除非是遗留代码,不然应当使用新式类,在模块或脚本开头使用赋值语句:__metaclass__ = type

Python 并不直接支持私有属性或方法,要表明某个方法是私有方法时,可以在前面加上两个下划线。import 语句会自动忽略前面带有下划线的属性和方法。

尽量避免使用多重继承。

Python 不支持接口,但在调用方法之前可以确定是否存在该方法。

第8章 异常

Python 使用异常对象来表示异常情况。异常对象未被处理或捕捉时,采用回溯(traceback)来终止执行。

raise 语句

异常的捕捉与“上浮(propagate ouf of the functions where the’re called)”。如果在发生异常时未提供except语句,异常会上浮(bubble up)到调用该函数的函数中,一直到程序的最顶层。

查看 Python 内建的异常类型:

1
2
import exceptions
print dir(exceptions)

捕捉到了异常但是暂时不想处理,可以调用不带参数的 raise 对异常进行“转发”:

1
2
3
4
5
try:
// some code
except:
//
raise

一个 try 语句之后可以跟随多个 except 语句,用于捕捉不同类型的异常。

except 语句之后可以将多种类型的异常通过元组的方式列出:
except: (ZeroDivisionError, TypeError, NameError)

在异常处理代码中使用异常对象:

1
2
3
4
try:
// ...
except: (ZeroDivisionError, TypeError), e:
print e

Python 3.0 中的写法是 except: (ZeroDivisionError, TypeError) as e

try/except 语句可以加上else子句:

1
2
3
4
5
6
try:
// ...
except:
// ...
else:
// ...

这里的 else 只有在没有发生异常的情况下才会被调用。

finally 子句,用于在有异常发生的情况下的清理工作。finally 子句一般用于关闭文件、套接字连接、数据库连接等。

一般来说,使用 try/except 比使用 if/else 更 pythonic!
请求宽恕易于请求许可。

在 Objective-C 中正好相反吗?

第9章 魔法方法、属性和迭代器

这章讲得不是很细。要重读英文版

魔法方法:名字前后带下划线的、具有特殊作用的方法。

用得最多的魔法方法:__init__

调用父类构造方法的两种形式

  • Unbound Superclass Constructor (那么 Python 所有的方法都可以当作静态方法来调用?)
1
2
3
4
class SongBird(Bird):
def __init__(self):
Bird.__init__(self)
// ...
  • 使用 super 函数
1
2
3
4
5
__metaclass__ = type // super 方法只对新式类有效
class SongBird(Bird):
def __init__(self):
suepr(SongBird, self).__init__()
// ...

注意:Python 3.0 中 调用 super 函数不再需要提供参数。

应该尽量使用新式类。

Python 中的 protocol

序列和映射成员访问规则:__len__(self), __getitem__(self.key), __setitem__(self.key, value), __delitem__(self.key)

property 函数:用于对 get/set 函数进行组织,最多接受4个参数:
property (fget, fset,fdel, doc)

静态方法与类成员方法

静态方法不需要self作为参数,类方法需要提供一个叫做 cls 参数。

正式的说法是,一个实现了 __iter__ 方法的对象是可迭代的,一个实现了 next 方法的对象是迭代器。

生成成器:包括 yield 语句的函数

生成器推导式(?)

生成器是由两部分组成的:生成器的函数和生成器的迭代器。

Generators are ideal for complex recursive algorithms that gradually build a result.

八皇后问题的例子:要多看几遍才能懂。bitbucket repo

第10章 自带电池

作为“主程序”或作为模块导入其他程序时,变量 __name__ 的值是不一样的。可根据 __name__ 来确定是否需要执行代码:

1
if __name__ == '__main__': test()

模块的文件名要和模块名称一致。

包就是一个目录,为了表明该目录是一个包,需要在其中创建一个名为 __init__.py 的文件(模块)。

导入模块的三种方式:

  • import drawing:只有 __init__ 模块中的内容可用。
  • import drawing.colors:只能通过全名 drawing.colors使用
  • from drawing import colors:可以通过短名称 colors 使用

使用列表推导式查看一个模块里的内容:

1
2
import copy
[n for n in dir(copy) if not n.startswith('_')]

使用 __all__ 变量,可以列出模块的所有“公有接口(public interface)”,也就是使用 import * 时导入的所有方法。如果模块中没有定义 __all__ 变量,那么 import * 会导入其中的所有方法。

1
2
import copy
print copy.__all__

查看包的源代码文件路径

1
2
import os
print os.__file__

标准库中的实用资源

sysargvpath

osenvironseqpathseplinesep

fileinput

高级数据结构

集合(Set)、堆(heapq,heap queue)、双端队列(deque, double-end queue)

time 模块

random 模块

shelve 文件存储模块

re 模块:escape() 函数

《黑客与画家》十周年访谈

注:原文是《黑客与画家》这本奇书出版十周年之际,Chris Castiglione 对原书作者 Paul Graham 的采访记录。

2003年,《黑客与画家》这本书问世了。不过黑客技术这个词还很不像现在这样高端洋气,计算机科学、创业公司也是如此。

就在这一年,我开始学习编程。
但我却栽在了计算机科学这门课程上,栽得很彻底:只得了F。
我灰心丧气,几乎决定要放弃计算机这条路。

然后,我读到了《黑客与画家》这本书,翻然醒悟:“作者才是真正的明白人。我学不好计算机科学,问题不是出在我自己身上,而是学校上课的方式本身就不对” [1] 。要作一个软件开发者,我不需要首先事无巨细地把所有计算机知识通通学一遍。我可以从软件开发的过程中学习需要的技能。认识到这一点之后,我从挫败与悲观中解脱出来。

《黑客与画家》让我开始思考软件开发人员的职责到底是什么。我要成为一名艺术家,而不是科学家。

十年后的今天,我已经在教别人学习编程。不过仍然有一些困扰我的问题;

  • 这十年来,计算机科学有没有发生变化?
  • 每个人都应该学习编程吗 [2] ?
  • Paul Graham 关于编程普及化 [3] 的预言实现了吗?
  • 为了得到答案,我找到了这些疑问的始作俑者。下面就是我对 Paul Graham 的采访。

关于‘计算机科学’

从你写《黑客与画家》到现在已经十年了。这篇文章里你设想了在不远的将来,计算机科学将不再只属于少数精英。并且会衍生出很多细分的领域。你觉得我们已经进入这样的时期了吗?

PG:这些似乎确实正在发生。以前,大量的研究局限在计算机科学家的小圈子里,今天的 GitHub 上正上演着类似的互动,而这些参与者根本没觉得自己在从事计算机科学的研究。

所以,我所说的变化其实已经成真了。

至于说细分的领域,可以说无处不在。现在有前端黑客、后端黑客,还有操作系统黑客,一直到硬件黑客。

过去十年里,编程好像是变成了系统维护。一大部分工作用在了安装和整合各种开发工具。以前,开发软件主要靠调用软件包,现在则更像是把别人写好的开源模块的代码整合到一起。

所以,很类似系统管理员的职责。过去,系统管理员负责安装工具,程序员负责写代码。而现在的程序员也都很擅长工具的安装,并且为能够优化这些工具的配置而深感自豪。

关于创业

CC:我想创业,但是我不会编程……怎么办?

PG:营销。早期的创业公司最需要做好两件事:拿出产品,说服用户。如果你的强项不是产品开发,那就要做好产品推广。

说服用户的意思是让他们愿意用你的产品。无论是不是你的强项,要是没有编程技能,你只能去做营销。

CC:非技术背景的创始人能招到好的开发人员吗?

PG:看情况。现在有些创业公司所做的业务本身就没有很强的技术性。比如零售行业,一般都用不到很尖端的技术。所以说,某种程度上而言,就算你没有技术背景,也可以招到能干活的程序员来做产品。但是没有技术背景会增加招聘的难度,因为很难对应聘者做出正确的判断。

我知道一些创始人正是被这个问题困扰:他们不清楚手下的程序员水平到底怎么样,他们自己无从判断。

CC:那么……你怎么判别开发人员的好坏?

PG:没有很好的办法。我们在 Y Combinator 孵化器所资助的那些只有一个创始人,并且创始人不具备技术背景的创业公司里,可能没有一家能解决好这个问题。判别开发人员好不好,这个问题非常难。

你需要一个技术很好的朋友。不过说回来,你又怎么知道你朋友是不是真的技术好呢?(哈哈哈)

要是你有这样一个朋友,那可以保证最先招进来的几个人是技术高手。然后,通过这些人可以完成其他岗位的招聘。实在没办法,只要保证至少有一个人技术过关就可以了。可是这个人又上哪里找呢?

要是你自己对去哪儿找优秀的程序员这件事没经验,那就需要找个经验丰富的人来负责招聘。

CC:通过 One Month Rails 的培训课程,我们发现有几个月的编程经验会对(管理人员)与程序员的沟通有所帮助。你觉得是这样吗?在运作科技公司的时候,懂得一点编程知识会使得管理更有成效吗?

PG:有帮助!有很大帮助。

实际上,如果有创业者面临去读商科学校还是去学编程的选择,我会建议学编程。商科学校能教会你什么呢?是如何去做一家大公司的管理层,如何管理下属,如何做报表……创业公司不需要这些技能。

CC:对想获得 Y Combinator 投资的小公司,你有推荐的编程语言吗?

PG:要是有人用 COBOL 开发产品,我会很担心他们的前途。并且要问一句为什么。(哈哈哈)

除此之外,我对编程语言没有倾向。有些创业公司用 PHP——我有点担心他们。不过,还有其他事情需要担心,编程语言不是最主要的。

CC:你会雇佣那些技术很好,但是大学没毕业的人吗?

PG:会!“我会雇佣比尔·盖茨吗?”,当然会。不过盖茨可不是什么公司都能有幸招到。他是我最想招的人。

上大学总归有好处。但是对于创业公司来说,大学文凭不是必需的。

大学可以开拓视野:可以学到以前闻所未闻的事情。所以说,上大学可以从总体上让人变得更聪明。

不过,那些中途退学的人,和一口气读到 PhD 的人比起来,我看不出任何高下之分。

CC:你的意思是,现在的开发人员已经是“即插即用”?

PG:更深层的原因是,软件开发不像以前那么难。不是说从事软件开发已经今不如昔了,这个现象只是说明整个行业在不断前进……对我来说这个进程有点出乎意料,特别是在明明知道未来不可预测的前提下。

CC:我们听过很多(One Month Rails 的)学员说,“我是 Rails 高手,但我不想成为计算机科学家”。他们不追求计算机科学家这样的名号,不以为耻反以为荣,这是一种自暴自弃吗?

PG:那到底什么样的人才能算计算机科学家呢?既能编得一手好程序,又能搞得定自动化理论。(哈哈哈)

CC:在《黑客与画家》中你写过“画家比黑客更酷”。你现在还这么觉得吗?

PG:现在,当个黑客已经比当时高大上多了。不过聚会上勾搭妹子的时候我还是会说自己是画家。

CC:我们在课堂上把学员定位为“黑客”会怎么样?比说“开发人员”或者“计算机科学家”更好吗?

PG:说“黑客”当然很好。就连白宫有时候都会用“黑”这个词。“黑客”现在不光能用来形容软件领域的活动,而且已经具备了更加广泛的内涵。

无论是狭义的黑客还是广义的黑客,都已经成为了流行词。

TOEFL 官方指南(脱水版)

根据自己看完 TOEFL Official Guide 之后的笔记整理。Could be helpful.

1 题型与时间

  • 要练习 Paraphrase
  • 加快阅读速度。一篇文章不超过20分钟
Test Section Number of Questions Timing
Reading 3 – 5篇 每篇12 – 14个问题 共36-70题 60 – 100 分钟
Listening 4 – 6 篇演讲,每篇6个问题
2 – 3 则对话,每则对话5个问题
共34-51题
60 – 90 分钟
BREAK 10 分钟
Speaking 6个tasks,2 independent and 4 integrated 20 分钟
Writing 1 integrated task
1 independent task
20 分钟
30 分钟

考试时间最长不超过 100 + 90 + 10 + 20 + 20 + 30 = 270分钟 = 4.5 小时。实际考试时间可能在3小时左右。

2 阅读

详情

阅读有3 – 5篇文章,每篇文章大约700词。所有文章都属于下面三种类型之一 (All TOEFL passages are classified into three basic categories based on author purpose):

  • 解释 (exposition): an explanation of a topic
  • 议论 (argumentation): a point of view about a topic and evidence to support it
  • 历史 (historical):不是一般概念上的历史学科,而是一种文体,介绍某件现象或理论的起源、发展一直到现状。

每篇阅读至少有一个问题涉及文章的组织结构。四种基本的文章组织结构是(Common types of organization you should be able to recognize are):

  • classification
  • compare / contrast
  • cause / effect
  • problem / solution

阅读部分要注意:

  • 只有读完文章(滚动条拉到底部)时才可以看到问题。
  • 特殊题型:Read to Learn questions | Paraphrase questions

3 听力

详情

听力部分共有4 – 6 篇演讲(文章),每篇 500 – 800 词,每篇6个问题;以及2 – 3 则对话,每则约三分钟,12 – 25 个“回合”,每则对话有5个问题。

听力素材类型

学术演讲 / 小组讨论
学校环境下的对话(例如和TA或university staff的communication,主题包括但不限于租房、选课、在图书馆查询信息等)

题目类型

单选
多选
排序
归类

  • 特殊题型:Chart Question

4 口语

详情
答题模板

场景设定:inside / outside the classroom
时长:20 min
题型:

  • Independent Tasks 准备时间15s,回答时间45s
    • Task 1: Talk about a person, place, object, or event that is familiar to you. 准备一系列熟悉的话题,平常多练习。Describe something and give reasons.
    • Task 2: Which of the actions is more preferable, or which opinion you think is more justified. (类似GRE写作的 argument?)Provide reasons and details. 注意表达个人观点的短语,如 In my opinion, I believe…。练习 Making a recommendation。
      Integrated Reading/Listening/Speaking Tasks
    • Task 3: Campus-related interest. 阅读材料(如学校通知)+ 对话 + 问题。准备时间30s,回答时间60s。
    • Task 4: Academic subject. 阅读材料(75-100词)+ excerpt from a lecture by a professor + 问题。准备时间30s,回答时间60s。
  • Integrated Listening/Speaking Tasks
    • Task 5: Campus-related situation. 对话时间在 60 – 90 s 之间。Typically a problem with two possible solutions. 回答时要对问题作简要介绍,同时给出自己的 solution。准备时间20s,回答时间60s。
    • Task 6: Academic content. 注意材料开头 defining a concept, highlighting an issue, or introducing a phenomenon。准备时间20s,回答时间60s。

5 写作

详情
综合写作模板
独立写作

题型

  • integrated writing | Read/Listen/Write
    • 阅读,200 – 300 词的文字材料,3 min。需要做笔记
    • 听力,200 – 300 词的lecture, 2 min。播放 lecture 时,阅读材料不会继续出现在屏幕上。
    • 建议的 response 长度为150 – 225词,但超过长度不会扣分。
  • independent writing | Writing from Experience and Knowledge
    • 写一篇文章来阐述观点,至少300词。
    • organize the essay with an outline
    • linking words ( transitional phrases )

写作部分总共用时50 min。

6 分数构成

  • Listening: 30
  • Reading: 30
  • Speaking: 30
  • Writing: 30

Total: 120

总得分为四个部分得分相加。

在线练习:www.ets.org/toeflpractice

《jQuery 基础教程》习题解答

最近在学《jQuery 基础教程》(第4版),Google 了一圈没找到完整的习题解答,所以放在这里作个参考。

Chapter 2 选择器

1.给位于嵌套列表第二个层次的所有 <li> 元素添加 special 类

1
$('li').children().find('li').addClass('special');

2.给位于表格第三列的所有单元格添加 year 类

1
$('tr').find('td:eq(2)').addClass('year');

3.为表格中包含文本 Tragedy 的第一行添加 special 类

1
$('td:contains(\"Tragedy\")').first().parent().addClass('special');

4.(挑战)选择包含链接(<a> 元素)的所有列表项(<li> 元素),为每个选中的列表项的同辈列表项元素添加 afterlink 类

1
$('a').parent().nextAll().addBack().addClass('afterlink');

5.(挑战)为与 .pdf 链接最接近的祖先元素 <ul> 添加 tragedy 类

1
$('a[href$=\"pdf\"]').closest('ul').addClass('tragedy');

Chapter 3 事件

1.在 Charles Dickens 被单击时,应用 selected 样式

1
2
3
4
5
6
7
$('div.author').click(function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
} else {
$(this).addClass('selected');
}
});

2.双击章节标题(h3)时,切换本章文字的可见性

1
2
3
$('h3.chapter-title').dblclick(function () {
$(this).parent().addClass('hidden');
});

3.当用户按下向右方向键时,切换到下一个 body 类,右方向键的键码是39

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var bodyClasses = [
'default',
'narrow',
'large'
];
$(document).keyup(function (event) {
if (event.which === 39) {
for (i = 0; i < 2; i++) {
if ($('body').hasClass(bodyClasses[i])) {
$('body').removeClass().addClass(bodyClasses[i + 1]);
break;
}
}
if (i == 2) {
setBodyClass(bodyClasses[0]);
}
}
});

上面这种写法比较“笨拙“。这里有更灵巧的写法,妙用switch case语句。

4.(挑战)使用 console.log() 函数记录在段落中移动的鼠标的坐标位置

1
2
3
$('p').mousemove(function (event) {
console.log(\"eventXY: (\" + event.pageX + \",\" + event.pageY + \")\");
});

5.(挑战)使用 .mousedown().mouseup() 跟踪页面中的鼠标事件。如果鼠标按键在按下的地方被释放,则为所有段落添加 hidden 类。如果是在按下的地方之下被释放,删除所有段落的 hidden 类

1
2
3
4
5
6
7
8
9
10
11
12
13
var mouseDownX, mouseDownY;
$(document).mousedown(function (event) {
mouseDownX = event.pageX;
mouseDownY = event.pageY;
});
$(document).mouseup(function (event) {
if (event.pageX === mouseDownX && event.pageY === mouseDownY) {
$('p').addClass('hidden');
} else if (event.pageY > mouseDownY) {
$('p').removeClass('hidden');
}

});

Chapter 4 样式与动画

1.修改样式表,一开始先页面内容,当页面加载后,慢慢地淡入内容

1
$('#container').hide().fadeIn('slow'); // 其实不需要修改样式表

2.在鼠标悬停到段落上面时,给段落应用黄色背景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var oldBackgroundColor;
$('div p').hover(
function () {
// hover 中使用 animate() 有问题???
/*
$(this).animate({
backgroundColor: 'yellow'
}, 'fast');
*/
oldBackgroundColor = $(this).css('backgroundColor');
$(this).css({
backgroundColor: 'yellow'
});
}, function () {
/*
//var backgroundColor = $('p').css('backgroundColor')
$(this).animate({
bacgroundColor: 'transparent'
}, 'fast')
*/
$(this).css({
backgroundColor: oldBackgroundColor
});
});

3.单击标题 <h2> 时将不透明度变为 25%,同时增加 20px 的左外边距,这两个效果完成后把讲话文本变成 50% 不透明度

1
2
3
4
5
6
7
8
9
10
11
12
$('h2').click(function () {
$(this).animate({
opacity: .25,
paddingLeft: '+=20px'
}, 'slow', function () {
// 不同要素的动画默认是同步进行的
// 使用回调函数,保证上面的动画完成后再设置 div.speech 动画
$('div.speech').animate({
opacity: .5
}, 'slow')
})
});

4.按下方向键时,使样式转换器 #switcher向相应的方向平滑移动20像素。
注意:这里使用 .filter(':not(:animated)') 可以防止按键过快导致动画“堆积”。

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
$(window).keydown(function (event) {
var switcher = $('#switcher');
switch (event.which) {
case 37:
switcher.css('position', 'relative').filter(':not(:animated)').animate({
left: '-=20px'
}, 'fast');
break;
case 38:
switcher.css('position', 'relative').filter(':not(:animated)').animate({
top: '-=20px'
}, 'fast');
break;
case 39:
switcher.css('position', 'relative').filter(':not(:animated)').animate({
left: '+=20px'
}, 'fast');
break;
case 40:
switcher.css('position', 'relative').filter(':not(:animated)').animate({
top: '+=20px'
}, 'fast');
break;
default:
}
});

Chapter 5 操作 DOM

1.修改添加 back to top 的代码,以便这些链接只从第四段后面才开始出现。

1
2
3
4
5
$('div.chapter p').each(function (index) {
if (index >= 3) {
$(this).after($('<a href=\"#top\">back to top</a>'));
}
});

2.在单击 back to top 链接时,为每个链接后面添加一个新段落,其中包含 you were here 字样

1
2
3
4
5
6
7
8
9
10
11
// 给提示文字添加了一个类,以便在需要的时候清除
$('a[href*=\"#top\"]').click(function (event) {
var clickedLink = event.target;
$('.scrollLocationTip').remove();
$('<p class=\"scrollLocationTip\">you were here</p>').insertAfter(clickedLink);
event.stopPropagation();
});
// 不在这些链接上点击时,将提示文字清除
$('body').click(function () {
$('.scrollLocationTip').remove();
});

3.单击作者的名字时,把文本改为粗体(通过添加一个标签,而不是操作类或 CSS 属性)
4.(挑战)在随后单击粗体作者名字时,之前添加的 <b> 元素(也就是在文本与正常文本之间切换)

1
2
3
4
5
6
7
8
9
10
// 题干中用的是 <b> 标签,实际上为了语义与样式分离,用 <strong> 更合适
$('#f-author').click(function () {
if ($(this).children('strong').length == 0) {
// wrapInner(),不改变外部的 DOM 结构
// 判断 length 的目的是,防止多次 wrapInner()
$(this).wrapInner('<strong></strong>');
} else {
$(this).children('strong').contents().unwrap('<strong></strong>');
}
});

这两个练习还有另外一种写法,在两种状态之间“切换”可以使用 toggle() 方法来实现。

1
2
3
4
5
6
7
8
$('#f-author').toggle(
function () {
$(this).wrapAll('<b></b>');
},
function () {
$(this).unwrap()
}
);

5.(挑战)为正文中的每个段落添加一个 inhabitants 类,但不能调用 addClass() 方法。确保不影响现有的类

1
2
3
4
5
6
7
8
9
// $('.chapter p').addClass('inhabitants');
// 用 $(this).className += 'inhabitants 为什么不行???
$('.chapter p').each(function () {
if (!$(this).hasClass('inhabitants')) {
$(this).attr({
class: $(this).attr('class') + ' inhabitants'
});
}
});

Chapter 6 通过 Ajax 发送数据

1.页面加载后,把 exercises-content.html 的主体内容(body)提取到页面的内容区域

1
2
// .load() 中的选择器为什么不能是 body???
$('#dictionary').load('exercises-content.html .letter');

2.不要一次显示整个文档,为左侧的字母列表创建“提示条”,当用户鼠标放到字母上时从 exercises-content.html 中加载与该字母有关的内容

1
2
3
4
5
6
7
8
9
10
11
12
/*
$('.letter a').hover(function () {
$('#dictionary').load('exercises-content.html #' + $(this).closest('.letter').attr('id'));
}, function () {
$('#dictionary').html('');
});
*/
$('.letter').hover(function () {
$('#dictionary').load('exercises-content.html #' + $(this).attr('id'));
}, function () {
$('#dictionary').html('');
});

3.为上面的页面加载添加错误处理功能,在页面的内容区显示错误消息。修改脚本,请求 does-not-exist.html 而不是 exercises-content.html,以测试错误处理功能。

1
2
3
4
5
6
7
8
9
10
11
$('.letter').hover(function () {
$('#dictionary').load('does-not-exist.html #' + $(this).attr('id'), function (response, status, xhr) {
if (status === 'error') {
$('#dictionary').html('错误:' + xhr.status).append(xhr.responseText);
} else {
$('#dictonary').html(xhr.responseText);
}
});
}, function () {
$('#dictionary').html('');
});

4.页面加载后,向 GitHub 发出一个 JSONP 请求,取得某用户的代码库列表。把每个代码库的名称和 URL 插入到页面的内容区。例如 jQuery 项目代码库的 URL 是 https://api.github.com/users/jquery/repos

1
2
3
4
5
6
7
8
9
10
11
12
var repoURL = 'https://api.github.com/users/jquery/repos';
$.getJSON(repoURL + '?callback=?', function (response) {
var html = '';
$.each(response.data, function (entryIndex, entry) {
html += '<div class=\"entry\">';
//给内容加上 term、part 类,是为了直接使用样式表中的样式
html += '<div class=\"repoName term\">' + entry.name + '</div>';
html += '<div class=\"repoURL part\">' + '<a href=\"' + entry.url + '\">' + entry.url + '</a>' + '</div>';
html += '</div>';
});
$('#dictionary').html(html);
});

Chapter 7 使用插件

1.把幻灯片的切换周期延长到 1.5 秒,把动画的效果修改为下一张幻灯片淡入之前,前一张幻灯片淡出。

1
2
3
4
5
6
7
8
9
$books.cycle({
timeout: 2000,
speed: 1500,
pause: true,
fx: 'fade', // 添加这一行
before: function () {
$('#slider').slider('value', $('#books li').index(this));
}
});

2.设置名为 cyclePaused 的 cookie,将它的有效期设置为30天

1
2
3
$.cookie('cyclePaused', null, {
expires: 7
});

3.限制书名区域,每次 resize 只允许以10像素为单位

1
2
3
4
$books.find('.title').resizable({
handles: 's',
grid: [10, 10] // 添加这一行 | 好像不起作用
});

4.修改 slider 的动画,让滑块平滑地移动到下一个位置。

1
2
3
4
5
6
7
8
$('<div id=\"slider\"></div>').slider({
min: 0,
max: $('#books li').length - 1,
animate: true, // 添加这一行
slide: function (event, ui) {
$books.cycle(ui.value);
}
}).appendTo($controls);

5.幻灯片播放完最后一张后停止。停止播放时,也禁用相应的按钮和滑动条。

1
2
3
4
5
6
7
8
9
10
$books.cycle({
timeout: 2000,
speed: 1500,
pause: true,
fx: 'fade',
nowrap: true, // 添加这一行
before: function () {
$('#slider').slider('value', $('#books li').index(this));
}
});

7.修改 mobile.html 中的 HTML 代码,让列表视图根据书名的第一个字母分隔开来。
可以在 html 中添加几个带有 data-role=\"list-divider\" 属性的标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div data-role=\"content\">
<ul data-role=\"listview\" data-inset=\"true\" data-filter=\"true\">
<li data-role=\"list-divider\">D</li>
<li><a href=\"#drupal-7\">Drupal 7 Development by Example</a></li>
<li data-role=\"list-divider\">J</li>
<li><a href=\"#jq-game\">jQuery Game Development Essentials</a></li>
<li><a href=\"#jqmobile-cookbook\">jQuery Mobile Cookbook</a></li>
<li><a href=\"#jquery-designers\">jQuery for Designers</a></li>
<li><a href=\"#jquery-hotshot\">jQuery Hotshot</a></li>
<li><a href=\"#jqui-cookbook\">jQuery UI Cookbook</a></li>
<li data-role=\"list-divider\">M</li>
<li><a href=\"#mobile-apps\">Creating Mobile Apps with jQuery Mobile</a></li>
<li data-role=\"list-divider\">W</li>
<li><a href=\"wp-mobile-apps.html\">WordPress Mobile Applications with PhoneGap</a></li>
</ul>
</div>

Chapter 8 开发插件

1.创建 .slideFadeIn().slideFadeOut() 的插件方法,把不透明度动画方法 .fadeIn().fadeOut() 以及高度动画方法 .slideDown().slideUp() 结合起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function ($) {
$.fn.slideFadeIn = function () {
return this.each(function () {
// 用 fadeIn() 效果不明显
$(this).slideDown('slow').fadeTo('slow', 1.0);
});
};
$.fn.slideFadeOut = function () {
return this.each(function () {
// 用 fadeOut() 效果不明显
$(this).fadeTo('slow', 0.5).slideUp('slow');
});
};
})(jQuery);

// 练习1 测试代码
$('#container h1').click(function () {
$('#inventory').slideFadeOut();
$('#inventory').slideFadeIn();
});

2.扩展 .shadow() 方法的可定制能力,让插件用户可以指定元素副本的 z 轴索引。为提示条控件添加一个 .isOpen() 子方法,在提示条正在显示的时候返回 true,而在其他时候返回 false

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
(function ($) {
$.fn.shadow = function (opts) {
var options = $.extend($.fn.shadow.defaults, opts);
return this.each(function () {
var $originalElement = $(this);
for (var i = 0; i < options.copies; i++) {
var offset = options.copyOffset(i);
$originalElement
.clone()
.css({
position: 'absolute',
left: $originalElement.offset().left + offset.x,
top: $originalElement.offset().top + offset.y,
margin: 0,
// ========== 练习2
zIndex: options.zIndex,
// ==========
opacity: options.opacity
})
.appendTo('body');
}
});
}
})(jQuery);

$.fn.shadow.defaults = {
copies: 5,
opacity: 0.1,
copyOffset: function (index) {
return {
x: index,
y: index
};
},
// ========== 练习2添加
zIndex: -1
// ==========
};

(function ($) {
$.widget('ljq.tooltip', {
options: {
offsetX: 10,
offsetY: 10,
content: function () {
return $(this).data('tooltip-text');
}
},
_create: function () {
// ========== 练习2
this.isTooltipOpen = false;
// ==========
this._tooltipDiv = $('<div></div>')
.addClass('ljq-tooltip-text ' + 'ui-widget ui-state-highlight ui-corner-all')
.hide().appendTo('body');
this.element
.addClass('ljq-tooltip-trigger')
.on('mouseenter.ljq-tooltip', $.proxy(this._open, this))
.on('mouseleave.ljq-tooltip', $.proxy(this._close, this));
},
destroy: function () {
this._tooltipDiv.remove();
// this.element 不就是 $(this) 吗?
this.element
.removeClass('ljq-tooltip-trigger')
.off('.ljq-tooltip');
$.Widget.prototype.destroy.apply(this, arguments);

},
// ========== 练习2
isOpen: function () {
return this.isTooltipOpen;
},
// ==========
_open: function () {
if (!this.options.disabled) {
var elementOffset = this.element.offset();
this._tooltipDiv.css({
position: 'absolute',
left: elementOffset.left + this.options.offsetX,
top: elementOffset.top + this.element.height() + this.options.offsetY
}).text(this.options.content.call(this.element[0]));
this._tooltipDiv.show();
// ========== 练习2
this.isTooltipOpen = true;
// ==========
this._trigger('open');
}
},
open: function () {
this._open();

},
_close: function () {
this._tooltipDiv.hide();
this._trigger('close');
// ========== 练习2
this.isTooltipOpen = false;
// ==========
},
close: function () {
this._close();
}

});
})(jQuery);

// 练习2 测试代码
$('a').tooltip().hover(function () {
console.log('Is Tooltip Open? : ' + $(this).tooltip('isOpen').toString());
});

3.添加代码监听 tooltipOpen 事件,并在控制台中记录一条消息

1
2
3
$('a').bind('tooltipopen', function() {
console.log('tooltipopen event triggered');
});

4.**(挑战)**自定义提示条部件的 content 选项,通过 AJAX 取得链接的 href 属性指向的页面的内容,将取得的内容作为提示条的文本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$('a').tooltip({
content: function () {
var url = $(this).attr('href');
var result = null;
$.ajax({
url: url,
type: 'get',
dataType: 'html',
async: false,
success: function (data) {
result = data;
}
});
return result;
}
});

5.**(挑战)**为提示条部件提供一个新的 effect 选项,如果指定该选项,则用该名字指定的 jQuery UI 效果显示或隐藏提示条。

1
2
3
4
5
6
7
8
9
// 在 _open 方法末尾加上:
// ========== 练习5
if (this.options.effect) {
this._tooltipDiv.effect(this.options.effect, {distance: 10, duration: 80});
}
// ==========

//练习5 测试代码
$('a').tooltip({effect: 'shake'});