尤克李李图标x

今天我27岁了。生日快乐。

昨天是2016年7月31日,阳历生日;今天是农历六月甘九,恰好又到了农历生日。两个生日前后到来,我即迷迷糊糊给自己放了一个大假。

想来这两天放假,我暂停了Udacity的Nanodegree课程、新旧单词的学习与巩固、读英语,替代的是两款游戏、几则视频,和大片无所事事不思进取的时间。本来计划在生日期间,给自己做个阶段总结,但一直拖到这半夜,13分钟后今天即结束。显然这篇文章今天是写不完了。但转念想,两日的荒废换来一个自省,也是不错的。

既然是自省,那就要从我对自己不满意的地方说起了。自认为自己一直是个“不安分的保守派”。“保守派”,即自己有完美主义作祟,一件事情到来,要么不敢去做,要么就想把每个细节做好;换言之,若有一星半点的细节自己未能处理妥当,很可能全盘皆被我放弃。所以我很喜欢跟老师学习(因为老师已经把前路探明了),而自学能力至少自己不能满意(作为保守派,总是裹足不前害怕撞钉)。而“不安分”,也是我的一大特质。可能是种天分:从小我就喜爱当孩子王,带着一众发小在藏猫猫的时候指引方向;高中大学特立独行,总要倒腾出一些事情让自己不一样,让自己闪光;工作的这4年,从未在一家公司超过1年——中途甚至二度辞职:第一次,和老婆一起疯玩一年;第二次,跑到美国匹兹堡修炼我在大学就应该学好的码农技能。

这两个截然矛盾的词语就这样在我身上有机结合。因此我也时常自我战争,有时认为自己犹豫不定实在是有欠魄力,有时又感觉自己明明应当善于坚持,却到如今好似并没有积累到什么。27岁了,还没有找到安身立命的实力。转念一想,矛盾也是正常。总是要有矛盾,才会有故事。没有矛盾就是一切宗教的理想状态了。

庆幸自己有一颗虽多愁善感却坚忍乐观的性格,又不断遇到或制造善良进步的周身环境,27年来,除却少不更事记忆寥寥的时代,偶尔能想到的总是正面的形象:坚持,行善,奋斗,反思,五月天,祝福。自认为我一直在向身边的人,和我自己,传递着正能量的东西。如今这个词语在信息的爆炸中几近枯涩,大有赴“心灵鸡汤”后尘的感觉,而我,也时不时感觉到自己焦急的心念和弱小的驱动力。我想说:我也做得不好。

看看微信里收藏的文章,哪一篇最后真正被我学习了?看看最近的前端工程师学习成果,为什么我总会在一开始就被未知吓退?自己那可怜巴巴的英语水准,究竟什么时候决心奋不顾身?网络自我初中以来倏忽而至,极大改变了我的世界;而我却总在学习与收集中岌岌可危。大量的知识并没有深印脑海,我只是将它们收集起来,仿佛网络记住了,我就记住了。看着每天每秒都汹涌而至的信息,我唯恐在这洪流中被远远甩下,于是习惯性地,雁过无痕,浅尝辄止。

很庆幸现在能在匹兹堡,和老婆一起过上这段貌似与世隔绝、波澜不惊的“修炼”生活。在这几个月里,我们相互督促相互鼓励,如今坚持每天早晚各15分钟冥想;用7分钟锻炼身体;英语听说读写;前端技能修炼。在近期大量的学习实践中,有个词逐渐浮现:大道至简。

如果我想把前端学好,两个字:多练; 如果我想把饭菜做棒,两个字:多练; 如果我想把英语说好,两个字:多练; 如果我想在冥想集中注意力,两个字:多练……

听来貌似很简单,但这颠扑不破的道理却不是我能解释得清楚的。或许这也正是语言的弱点。哪怕在学习的路上有捷径,那也非得多加练习。这恰恰是绕不过去的——绕过去的话,我就从一个学习者变成了一个收集者——好像收集到了,我就学到了一样。从这么简单的道理到真正践行,我一直在探索。有三个资源对我帮助甚多: 1. 五月天的歌曲; 2. 学习如何学习(Learning How To Learn); 3. 李笑来的文字

简单地列出来固然容易,这是语言的优势;但正因语言也有弱点,我不能奢望它们对你能有裨益。列下来的原因,只是我对它们心存感激。感谢是它们在我生命的流逝中熠熠闪光,不时耐心劝诱,不时充盈能量;让我如今虽仍未有所成,却真的开始抓住时光。我愿意相信这样的踏实,终究会给我坚实的支撑,让我面对白驹过隙,而不必惶惶终日。

祝愿我和我老婆在这样金子一样的时间里,能一直坚持正在做的这些事情。

冥想,英语,前端。

坚持。

web-perf-opti

Udacity课程链接

Website Performance Optimization

工具

Chrome Dev Tools里的Timeline可用Flame Chart(火焰图)将网页渲染过程清晰显示出来。其中有3条垂直虚线:

  • 红色:load事件
  • 蓝色:DomContentLoaded事件
  • 绿色:第一次paint事件

flame chart

3个最主要的优化方法

  1. 压缩HTML、CSS、JS的体积
    在请求一个页面后,页面的建立遵循如下顺序: DOM — CSSOM — Render Tree — Layout DOM和CSSOM的体积占了很关键的角色。也就是HTML/CSS/JS。最小化 文件和 删除注释 可以减少浏览器加载的文件大小,从而优化性能。
  2. media queries(针对CSS)和defer/async(针对JS)避免无关代码对关键渲染路径对干扰
    • media queries可以将针对不同屏幕的CSS分到不同的CSS文件中,并在HTML中对相应CSS添加media属性,从而告知浏览器仅加载必须的CSS即可
    • defer/asunc可以将与构建网页无关的JS文件异步执行,或者等待网页渲染完毕后执行,从而达到不干扰网页渲染的效果。两者用法均为:在HTML的script标签中增加该属性。例子:<script src=”js/sample.js” async></script>
    • 关于deferasync的区别,详见此文:script的defer和async。也可参考MDN中script标签的解释
  3. 减少渲染请求次数
    • 若CSS是一个单独文件,则浏览器先请求HTML;读到CSS文件名的时候,会再请求一次,导致请求次数为2。
    • 若将CSS直接写到HTML中,则得到HTML和CSS时,请求次数仅为1。

术语

  • fps: frames per second
  • DOM: Document object model
  • TL;DR: Too long, don’t read,一般用在一篇文章的总述部分,只读这些,其他都不必读
  • CRP: critical rendering path 关键呈现(渲染)路径
  • 101: 最基本
  • orientation: portrait/landscope: 屏幕:竖屏/横屏
  • curl: Mac OS X中terminal的一个命令,用法:curl https://google.com 即可获得Google的html,并复制到terminal中

Snip20160623_1

在Udacity上学习了一点Grunt的皮毛,其实还不算会用,只是会拿现有的文件重新套用到新项目中去。将流程记录如下,慢慢增进。

  1. 安装node.js
    node.js链接
    安装完毕后,就能用npm了。查看npm的位置,可以在终端输入which npm
  2. 将Grunt命令行安装到全局环境中:
    npm install -g grunt-cli
  3. 初始化npm
    使用终端进入将要使用Grunt的项目根目录,输入npm init,初始化npm,将会输入必要信息(name, description, git repository, keywords, author需要手填,其他均直接回车即可),逐步建立package.json文件。
  4. 安装Grunt
    使用终端进入将要使用Grunt的项目根目录,输入npm --save-dev install grunt。此步骤会创建名为node_modules文件夹及运行Grunt所需的文件。
  5. 创建配置文件Gruntfile.js
    在项目根目录创建Gruntfile.js,此文件将包含未来要使用Grunt运行的功能。我现在的做法是复制之前的文件,内含4个插件:responsive-images, contrib-clean, contrib-copy, mkdir。
  6. 下载所需插件
    打开Grunt插件链接,寻找所需插件,并按每个插件的安装方式安装。一般方式是:npm --save-dev install pluginName
  7. 编辑配置文件Gruntfile.js
    一般情况下,所有插件的配置都被保存在module.exports = function(grunt) { }内部,并且分为2部分:

    1. 编辑具体功能选项;
    2. 注册该插件。
  8. 一切配置完成后,在终端输入grunt,即可运行Grunt,得到相应效果。

Snip20160615_22

I’ve learned “Intro to jQuery” in Udacity. Here is the link: Intro to jQuery.

What I’ve learned

  1. jQuery is a function as well as an object. It’s a JavaScript library.
  2. $ === jQuery.
  3. $(string) or $(function) or $(DOM Element)
  4. 3 ways to load jQuery:
    1. local file;  // <script src="js/jquery.js"></script>
    2. jQuery official;  // <script src="http://code.jquery.com/jquery-3.0.0.min.js" integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0=" crossorigin="anonymous"></script>
    3. Content Delivery Network(CDN), such as Google, Microsoft and so on. Or some Chinese friendly: // <script src="//cdn.bootcss.com/jquery/3.0.0/core.js"></script>
  5. jQuery Selector: $('tag') $('.class') $('#ID')
  6. $('#shisaq').parent() // chose the element who is the first level of #shisaq’s parent. 选择它上一级的元素
    $('#shisaq').parents() // chose all the elements who is the parent of #shisaq. We can specify a parent that we want, to add it into the parenthesis. 选择它的所有父级。可在括号中指定具体父级元素
    $('#shisaq').children() // chose it’s closest children. 选择它的直接下一级
    $('#shisaq').find() // chose all the children of #shisaq, or, if there is a specify element inside the parenthesis, we chose that one. 选择所有子元素。可在括号中指定具体子元素
    $('#shisaq').siblings() // chose brothers and sisters. 选择平级元素
  7. .addClass():
    1. add a class name into a tag or a property. 括号里是假如的class名称。 e.g: $('body').addClass('blue'); // <body class="blue"></body>
    2. We can add a function inside the parenthesis. But the function must return a string so that the string can be added as a class. 我们可以在括号里加入一个function。此function必须返回一个字符串,以便此字符串可以作为一个class名称加入
  8. .toggleClass() :
    Switch class. Cut the class if there exists; Add it if there is no. 切换class。如果有,就去掉;如果没有就加上。
    e.g: $('blue').toggleClass();
    We can also add parameters into the second parenthesis:
    1. $('#shisaq').toggleClass(className, addOrRemove);
    is equal to:
    if (addOrRemove) {
     $('#shisaq').addClass(className);
    } else {
     $('#shisaq').removeClass(className);
    }
    2. Add function:
    $('#shisaq').toggleClass(function() {
     if ( $(this).parent().is("nav") {
       return "happy";
     } else {
       return "sad";
     } // This will make a judgement on whether #shisaq‘s parent is nav . If it is, add class “happy” to #shisaq; If not, add “sad”. 判断shisaq的父元素是否是nav。如果是,加上happy给shisaq;如果不是,加sad给shisaq。
  9. .next() :
    Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector. 获取下一个平级(兄弟)元素。如果括号中有提供一个元素,则选中下一个可以匹配此内容的元素。

    <ul>
    <li>list item 1</li>
    <li>list item 2</li>
    <li class="third-item">list item 3</li>
    <li>list item 4</li>
    <li>list item 5</li>
    </ul>

    If we begin at the third item, we can find the element which comes just after it:

    $( "li.third-item" ).next().css( "background-color", "red" );
  10. .attr() :
    Get the value of the selected element, or change the value into other.
    $('.shisaq').attr('href'); // get the value of href in .shisaq 返回在shisaq中href的值
    $('.shisaq').attr('href', 'yeah'); // change the value of href into “yeah” 把shisaq的href的值改为“yeah”
  11. .css() :
    Similar with .attr() ,  but it adds values into style. 和attr()类似,不过它是向style里添加内容
  12. .html() and .text() :
    .html() returns the whole html, yet .text() returns the content inside the html. .html()返回选中元素的整个html,.text()返回选中元素的html里的内容
  13. .val() :
    get the value of the selected element 取选中元素的值
  14. .remove() :
    Remove the selected element from the DOM.
    e.g: $('nav').remove(); // remove the nav 移除nav
    $('nav').remove('li'); // remove all the li in the nav. 移除所有在nav里面的li
  15. .append() and .prepend() :
    .append()(.prepend()) inserts content to the end(beginning) of the selected element 在选中元素的末尾(prepend是开头)加入括号中的内容
  16. .insertAfter() and .insertBefore() :
    $( "<p>Test</p>" ).insertAfter( ".inner" ); // insert <p>Test</p> after every .inner class. 在每一个inner后面加入<p>Test</p>代码段
  17. .click() :
    A function will execute after clicked the selected element. 括号中的function会在被选中的元素被鼠标点击时执行。
    e.g: $("#target").click(function() {

    alert("Hello world!");
    }); // after clicked the #target element, the alert window will show.
    // 点击#target元素后,alert窗口会弹出

 

Snip20160614_21

I learned JavaScript Basics in Udacity. This is the link: JavaScript Basics.

What I’ve learned

  1. console.log(); //Let interpreter(Chrome dev tools) print out the content. 让解释器打印出括号里面的内容。
  2. var variableName = 'variableValue'; // define a variable and put a value to it. We can also just declare a variable without giving a value to it. 定义一个变量,并指定该变量的值。当然也可以只声明该变量不赋值。
  3. [string].replace([old], [new]); // return the changed value. See MDN link: String.prototype.replace()返回修改后的数值。最好定义一个变量接收该值。
  4. str.slice(beginSlice[, endSlice]); // extracts a section of a string and returns a new string. see MDN link: String.prototype.slice() 取出字符串里的一部分,并返回这个取出来的字符串。中括号内可选,如果没输入中括号内的值,则一直取到字符串末尾。不能用在数组里。
  5. str.toUpperCase(); // returns the calling string value converted to uppercase. See MDN link: String.prototype.toUpperCase() 返回该字符串的大写值。str.toLowerCase()返回小写。同理。
  6. Array: a group of objects. The items can be string, number, array, or function.
  7. str.length; // return the length of the string or array. 后面没有括号。
  8. arr.pop(); // removes the last element from an array and returns that element. See link: Array.prototype.pop() 剔除数组的最后一个元素并将该元素返回。括号中不能加参数。
  9. arr.push(); // adds one or more elements to the end of an array and returns the new length of the array. See link: Array.prototype.push() 把括号里面的元素加到数组最后,并返回该数组的长度。
  10. str.split([separator[, limit]]); // splits a String object into an array of strings by separating the string into substrings. See link: String.prototype.split() 把一个字符串按指定的分隔符分隔成一个数组。中括号里面的limit是可选内容。如果不写,则将整个字符串按分隔符操作一遍;如果写3,则仅返回前3个元素。
  11. str.trim(); //removes whitespace from both ends of a string. Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.) and all the line terminator characters (LF, CR, etc.). See link: String.prototype.trim() 去掉字符串最前和最后的空格。常和str.split()一起用,以此防止生成的数组中,数组头和数组尾含有空元素。举例说明:
    var str = " Today is Tuesday! ";
    var strArr1 = str.split(" ");
    console.log(strArr1); //  ["", "Today", "is", "Tuesday!", ""]
    var strArr2 = str.trim().split(" ");
    console.log(strArr2); // ["Today", "is", "Tuesday!"]
  12. str = arr.join([separator = ',']); // joins all elements of an array into a string. See link: Array.prototype.join()把数组中所有元素合并成一个字符串,并返回该字符串。方括号中是可选。如果加了内容,则每两个数组之间会加此内容。通常会加逗号或者空格。
  13. var objName = {
    "name": "shisaq",
    "age": 32
    }; // This is an object. A object is capable to  contain string, number, and array. It's like an array. But actually, array is a special object. Because an array just has a list from 0 to the length, but an object can define every value's name. 数组是一种特殊的对象。数组只是一个有序列表,而对象可以给任何值定义任何名字。
  14. JSON: JavaScript Object Notation. JavaScript对象标识法。跟上面举出的例子一样,JavaScript对象怎么写,JSON就怎么写。主要用来存取数据。注意最后一行末尾不要加逗号(,)。
  15. if Statements.
  16. === is safer than ==
  17. for in loops:
    Use forEach or for to iterate over arrays like:

    countries = ['Argentina', 'China', 'England'];

    Use for-in to loop over objects like

    countries = {'country1':'Argentina', 'country2':'China','country3':'England'};

    being careful to wrap the content of the for-in in a conditional statement that tests if the key is part of the object:

    myObj = {'country1':'Germany', 'country2':'Argentina'};
    for (key in myObj){
        if (myObj.hasOwnProperty(key)) {
            console.log(myObj[key]);
        }
    }

    For more information, please refer to the loop section of the Udacity Front End Style Guide.

Snip20160614_20

These days I’m learning “How to write readme in GitHub”, it’s time to give a collection of Markdown syntax.

# // 1st level caption 一级标题

## // 2nd level caption 二级标题

###### // 6th level caption 六级标题

`code` // inline code 行内代码

“` JavaScript

console.log(“code”);

console.log(“code”);

“` // snippet 代码段

*  // unordered list 无序列表

–  // unordered list 无序列表

1.  // list 有序列表

[Google](https://google.com) //link 链接

![image](https://image.url) //image 图片

> // quote 引用

** bold ** 粗体

_em_ // emphasized 斜体

\ //cancel markdown 取消使用markdown

[x] // checklist checked 选中清单选项

[ ] // checklist unchecked 未选中清单选项

—————- // horizon 分割线

dog | bird | cat
----|------|----
foo | foo  | foo
bar | bar  | bar
baz | baz  | baz  // table

 

Snip20160613_10

Now it’s time to sum up canvas :

  1. canvas (画布)is an element of html documents. When using it, we must define the width and height of it, so that the browser can know how large the canvas is;
  2. Actually, we need to use JavaScript to draw on canvas. Yeah, JavaScript looks like a pen;
  3. To start drawing, we need get the context of the canvas first. Here is a simple example:

    simple example

  4. Draw an image into the canvas:
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>demo</title>
    </head>
    <body>
      <canvas id="c" width="200" height="200"></canvas>
      <script>
        // connect the canvas that the id is "c"
        var c = document.querySelector("#c");
        // make canvas to 2d cavas.
        var ctx = c.getContaxt("2d");
    
        // define "image" to a brand new image object
        var image = new Image();
        // when image is loaded, run this function
        image.onload = function () {
          ctx.drawImage(image, 0, 0, c.width, c.height); 
        }
    
        image.src = 'abc.jpg'; // you can add local or online sources
      </script>
    </body>
    </html>
    
  5. We also can draw our own patterns onto the canvas.
    ctx.fillRect(100, 100, 100, 100); // this will draw a fufill rectangle
    ctx.strokeRect(50, 50, 50, 50); // this can draw a blank rectangle

    rectangle

  6. If you want to erase the entire canvas, you could call clearRect with the dimensions of canvas as follows:ctx.clearRect(0, 0, c.width, c.height);
  7. Draw paths!
    // Draw "天" by using paths
    ctx.beginPath();
    ctx.moveTo(10, 10);
    ctx.lineTo(30, 10);
    ctx.moveTo(5, 20);
    ctx.lineTo(35, 20);
    ctx.moveTo(20, 10);
    ctx.lineTo(5, 35);
    ctx.moveTo(15, 20);
    ctx.lineTo(35, 35);
    ctx.save();
    ctx.stroke();
  8. Canvas2D allows us to translate (move), rotate, or scale objects.

    Scaling

    scale(x,y) multiplies the x and y values by a given factor so

    ctx.scale(2,3);

    will make all values twice as large on the x axis and three times as large on the y axis.

    Translation

    translate(x,y) moves all subsequent draw commands by x number of pixels on horizontally and y pixels vertically.

    ctx.translate(20,40); moves all elements drawn after it 20 pixels to the rights and 40 pixels down.

    The translate() method remaps the (0,0) position on the canvas.

    translate

    Rotation

    ctx.rotate(angleRadians) rotates an object a certain number of radians (generally) about its center. You may have learned about radians in school but here’s a handy formula to convert a value from degrees to radians.

    radians = degrees * (Math.PI/180)

  9. Every canvas object contains a stack of drawing states. Stacks are data structures that only let you push new items at the end. When you retrieve an item, it’s the last item that was pushed or Last In-First Out(LIFO).
    var c = document.querySelector("#c");
    var ctx = c.getContext("2d");
    
    ctx.fillStyle = "blue";
    ctx.fillRect(0,0,50,50);
    
    // Save state with blue fill
    ctx.save();
    ctx.fillStyle = "green";
    ctx.fillRect(100,100,10,10);
    // Restore to blue fill
    ctx.restore();
    
    ctx.fillRect(200,10,20,20);
  10. Add color to the canvas:
    ctx.fillStyle = "green";
  11. Add text:
    ctx.strokeText("the text", 10, 10);
  12. We can make our own image effect program by dealing with the image data.
    e.g:
    image.onload = function () {
    console.log('loaded image');
    ctx.drawImage(image, 0, 0, image.width, image.height);
    var ImageData = ctx.getImageData(0, 0, image.width, image.height);

    // put image into grayscale
    var grayScale = function(imagedata) {
    for(var i=0; i<imagedata.data.length; i+=4) {
    var redItem = imagedata.data[i]; //red
    var greenItem = imagedata.data[i+1]; //green
    var blueItem = imagedata.data[i+2]; //blue
    // this is a Math: Gray = (Red + Green + Blue) / 3
    var grayItem = (redItem + greenItem + blueItem) / 3; //gray
    imagedata.data[i] = grayItem;
    imagedata.data[i+1] = grayItem;
    imagedata.data[i+2] = grayItem;
    }
    ctx.putImageData(imagedata, 0, 0);
    }
    grayScale(ImageData);

  13. requestAnimationFrame is an awesome engine that support almost all the modern browsers. It just redraw the canvas over and over again, depending the speed of the local computer. As I see, it’s a loop. There is a good interpreter that explained what requestAnimationFrame is and how to use it: Animating with requestAnimationFrame

Read more

window.requestAnimationFrame()

requestAnimationFrame for Smart Animating

Kibo: A simple JavaScript library for handling keyboard events

CanvasRenderingContext2D.drawImage()

Seven grayscale conversion algorithms

HTML canvas translate() Method

 

Snip20160613_10

Recently, on my way processing Udacity Front-end Nanodegree, I met a project called “Classic Arcade Game”, developed by Object Oriented JavaScript and HTML5. Here is my result : https://github.com/shisaq/frontend-nanodegree-arcade-game

In the beginning of this project, when I received the resources, opening index.html , wow what a pity! There was nothing except a totally blank white page. After a long time fighting against my hopeless, I started to dig into the project.

What I had learned:

  1. Object Oriented JavaScript, including scopes(作用域), closures(闭包), this keyword, prototype chains(原型链), object decorator pattern(对象修饰模式), functional classes(功能类), prototypal classes(原型类), subclasses and superclasses(子类和父类), and what’s more: pseudoclassical subclasses(伪类,不确定是否翻译正确).
  2. HTML5 canvas basics.

OK, now I want to explain the concepts to myself:

First, Object Oriented JavaScript:

  1. Scopes: define where can variable use. If the variable is defined out of any function, it may be in a global scope, and can be called by anyone. But it’s not a good idea to set too many variables cuz it will be easy to make conflicts.
  2. Closures: every function should have access to all the variables from all the scopes surround it. A closure is just any functions that somehow remains available after those after those outer scopes have returned. This can make every function run independent, which does make sense.
  3. this keyword: this is an amazing concept, which made me confused so much… Anyway, this will be inside of a function. If not, this means <global> . So if this is in a function, when the function is called by a entity, the keyword this means the entity. Other word, this . So the keyword this makes it possible for it to just build one function object, and use it as a method on a bunch of other objects. And every time we call the method, it’ll have access to whatever object it’s being called on. This can be useful for conserving memory, and it’s only possible because we have the parameter this .
  4. Prototypal chains: example: var A = Object.create(B); Use a link between 2 objects, whenever requesting a property that doesn’t in A, it’ll use B as a fall back source of properties.
  5. Object decorator pattern: for reusing code, and dynamically(动态地) adding some specific actions into an object at the same time, we can use this feature.

    object decorator pattern in the red box

  6. Functional Classes: a function that constructs all the common features in a class so that whatever instance(实体) built by this class, it’ll have the features from the function. And this class is called functional class. In JavaScript, we should make the first letter of the functional class name uppercase. We can say it’s a constructor.
  7. Prototypal classes: function sharing prototypal delegation(代表)is the very goal of the prototypal pattern. If method were defined inside the constructor, there really wouldn’t be any reason to delegate the instances any prototype at all. I think it is used as an action in order to manipulate the instance which belongs to the functional class.
  8. Subclasses and superclasses: the same as the literal meaning. Subclasses can get all the features that is in superclasses, but subclasses can have some particular features just for itself.

    subclasses and superclasses

  9. Pseudoclassical subclasses: according my understanding, pseudo means it’s not real. So that may means the subclass is not a real subclass of the superclass. But it still can use the features offered by the superclass, and what’s more important, the subclass can have its own functions. Actually it sounds just like there’s no difference between a pseudoclassical subclass and a real subclass. But it can save the memory, upgrade performance, and it’s actually easier to maintain because everything is connected, if you want to change one, you don’t need to change everywhere, just find the superclass, then change. Other word, pseudoclassical subclasses can not only add the features for itself, but can add the actions for the instances that belong to it.

    pseudoclassical subclasses

Read more

JavaScript闭包初探

JavaScript 物件導向

修饰模式

Function.prototype.call()

udacity

dot-notation

初学JS。在用for in循环的时候,对用点还是用中括号产生了困惑。

困惑阐述:

  1. 定义一个对象,含若干属性名称及属性值:
    var bio = {
      "name": "shisaq lee",
      "role": "Front-end Developer",
      "contacts": {
        "mobile": "123-456-7890",
        "email": "123@gmail.com",
        "twitter": "@123",
        "github": "1234",
        "blog": "123.com",
        "location": "Pittsburgh, PA, USA"
      }
    }
  2. for in 循环遍历此对象的名称及属性值:
      for (contact in bio.contacts) {
        if (bio.contacts.hasOwnProperty(contact)) {
          console.log(contact);
          console.log(bio.contacts.contact);
        }
      }
    
  3. 猜输出结果是什么?

这就是困扰我的问题, bio.contacts.contact 没有被定义,所以没有正常输出。

思考contact代表的是bio.contacts这个对象里每个属性的名称。当 for in 循环遍历到第1个时,contact代表的是mobile不,其实是"mobile"。因此,当代码进行到 console.log(bio.contacts.contact); 的时候,其实对应的是 console.log(bio.contacts."mobile"); 。但因其带有双引号,所以这时候用 . 是取不到mobile的值的。此时要想取mobile的值,就是用另一种方法的时候了。

for in 循环中的问题代码微调一下:

  for (contact in bio.contacts) {
    if (bio.contacts.hasOwnProperty(contact)) {
      console.log(contact);
      console.log(bio.contacts[contact]);
    }
  }

我仅把 . 换成了  [ ]

此时重新运行代码,结果如下:

看到正确结果,此时我的内心是激动的😄😄

当时改完,自己还挺不理解,[ ] 不是用在数组中的么?怎么能用在对象中呢?

在JavaScript里,有2种方法显示对象中某个属性的值:

  1. 对象.属性 === 该属性的值,用本文例子就是:bio.contacts.mobile === "123-456-7890"
  2. 对象[“属性”] === 该属性的值。用本文例子就是:bio.contacts["mobile"] === "123-456-7890"

关于以上两种方法的区别,请参考如下这篇文章:http://www.dev-archive.net/articles/js-dot-notation/。虽然是英文,但是不长,总结起来就是:

  1. . 速度更快,阅读也更容易;
  2. [ ] 可以允许含有特殊字符的属性名称。

结合到本文我就明白了,我在循环中犯了一个错误,contact代表的是"mobile" 而不是mobile。双引号当然是特殊字符,所以这里我只能用 [ ] ,而不能用 . 来获取mobile的值了。同时用中括号,仍然是对对象进行操作,并没有对数组进行操作。

 

换言之,在 for in 循环中,选取属性名称和属性值的时候一定要谨慎。若for in 的目标是一个对象而不是一个数组,那就只能用中括号了。换言之,如果要操作一个数组,其实是有更好的方法的: for循环 或 forEach循环 。参见:Udacity关于for-in循环的参考指南。并且,在火狐MDN关于for in的例子中,也用的是中括号,参见这里:Mozila Developer Network for…in(中文版)。

 

如果对这两种表示方法感兴趣,可以读一读如下文章:

1. JavaScript property access: dot notation vs. brackets?
2. JS dot-notation vs. bracket notation

rainbow

这篇文章虽然已经写得非常棒了,我还是没能看得很懂。。。中文版摘自陈三的blog,附上原文链接

译注:本文译自 Srcset and sizes,原文使用 CC BY 3.0 许可。感谢作者额外提供一套灰色背景图片。

陈三的补充:如果你只是想了解 srcset 与 sizes,可以直接跳到第二部分,或扩展阅读的链接,第一部分作者只是在论证,在响应式图片里如果使用媒体查询会有什么样的困难。

第一部分:媒体查询有什么问题?

且说你是在 1993.2.232010.5.25 期间制作网页。图片真是太简单了!无非就是:

  • 看看你的定宽布局
  • 量一量,要塞入你手上这张图片,究竟每个用户屏幕上固定需要多少个像素
  • 打开 Photoshop
  • 根据量好的尺寸保存图片
  • <img> 标签中引用
  • 给自己倒一杯啤酒(或是打开一罐豌豆罐头),庆祝任务完成

 

在偶尔会有一些先知从荒原里走出,吐露真相,指出这个方法与生俱来的问题以前,这个方法已经服侍普通的 Web 设计者们二十年了。

只是,时代正在改变。

四年前,Ethan Marcotte 发表了一篇文章;13 天后,Steve Jobs 发布一台手机;突然之间,弹性和/或高清屏图片就成形了。随后,各种咬牙切齿

 

碰上响应式图片,我们的第一直觉,是试试我们在响应式布局上用到的工具:媒体查询。

浏览器无法知道它尚未加载的网站的一切。但它们对自身的渲染环境却总是了解:视口的尺寸,用户屏幕的分辨率,等等。媒体查询的思路是这样的:让 web 开发者根据特定环境做特定的事情。如果视口宽于 1000 像素,那么侧边栏就显示在左边。否则,将它推到主栏下方。如果用户的屏幕是高清屏,那就使用一张大图,否则使用小图。

太简单啦。

但不幸的是,响应式图片的情况里,使用媒体查询通常是非常糟糕的。

这值得花些时间解释。基于媒体查询的响应式图片选择之所以糟糕,是因为大部分响应式设计者是基于一个变量(视口宽度)来决定如何改变页面布局的,而对于响应式图片,我们实际上需要关心三个变量:

  • 布局中图片的渲染尺寸(CSS 像素尺寸)
  • 像素密度
  • 我们手头可支配的不同尺寸的图片

…这些被微妙地简缩成媒体查询。

一旦我们知道这三种东西,那么解法就简单了。从给定的资源里,挑出一张最小的,但是尺寸又要比渲染尺寸 * 像素密度 大。

但是,很不幸,要确定渲染尺寸是一件非常困难的事。Web 开发者没法知道它。弹性图片会伸缩;在响应式布局中,一张图片的渲染尺寸什么可能性都有。还有一点可能也让人吃惊,就是浏览器在加载图片时,也不知道渲染尺寸渲染尺寸依赖于页面 CSS,通常浏览器是在页面开始加载图片后很久才分析 CSS 的。

运气好的是(看起来如此),给我们的源文件附加媒体查询可以绕过这问题,只是要把渲染尺寸分成两个:

  • 视口尺寸
  • 相对于视口,图片大小将如何变化

…当然,还需要作者在完成一些许多简单复杂的计算后指定视口尺寸与像素密度。

怎样的计算呢?让我们看一个例子。

(请注意,虽说我会尽量简化,但这个例子存在的理由,只是想告诉你,亲爱的读者们,基于媒体查询的计算过程是繁杂且易出错的。如果你很快就确认了这一点,请跳到第二部分。)

假定你有一张图片的三个版本:

  • large.jpg (1024 x 768)
  • medium.jpg (640 x 480)
  • small.jpg (320 x 240)

然后在弹性网格 – 一种开始只一列,大视口中切换成三列的网格,比如这样,你想要挑选一张图片并加载它。

你想要支持 1x 和 2x 的设备像素比

怎样构造媒体查询?让我们从上开始。

large.jpg 只有在绝对必要 – small.jpgmedium.jpg 都太小的时候才加载。更确切说,我们只需要如下情况加载large.jpg

渲染尺寸 x 像素密度 > 尺寸仅次于它的文件长度

我们的示例布局里,渲染尺寸只是视口尺寸的一个简单百分比。因此:

渲染尺寸 = 图片相对视口的比例 x 视口尺寸

尺寸仅次于它的文件medium.jpg,所以:

尺寸仅次于它的文件长度 = 640px

汇合一下,则我们得到以下的不等式:

图片相对视口的比例 x
视口尺寸 x
像素密度
> 640px

重排一下:

视口尺寸 >
  640px ÷
  (图片相对视口的比例 x 像素密度)

要构建媒体查询,我们需要求解每个可能的图片相对视口的比例像素密度值下的视口尺寸

图片相对视口的比例有两个可能取值:到达断点(36em)前的 100vw及到达断点后的 33.3vw。

至于像素密度…呃,取值可能无数,不过我们前面已经说过,只要支持设备像素比 1x 和 2x。

两种图片相对视口的比例 x 两种设备像素比 = 四种需要我们考虑的情形。且一个一个地来看。

1x,断点前

因为我们的断点是 36em,所以很明显地:

视口尺寸 < 36em

图片相对视口的比例 = 100vw 和像素密度 = 1x 代入我们此前的不等式中:

视口尺寸 >
  640px ÷ ( 100vw x 1x ) = 640px = 40em

结合两个不等式,我们得到一个不可能的东西:

36em > 视口尺寸 > 40em

所以我们可以不用考虑这种情况 – 即单列布局下,1x 的设备像素比不需要 large.jpg

2x,断点前

再来:

视口尺寸 < 36em

但这回我们代入 2x:

视口尺寸 >
  640px ÷ ( 100vw x 2x ) = 320px = 20em

结合起来我们得到:

36em > 视口尺寸 > 20em

于是视口尺寸在这个范围中时,2x 屏幕上我们要加载 large.jpg

1x,断点后

现在我们要比断点宽了:

视口尺寸 > 36em

而且我们是在 1x 屏幕上的三列布局:

视口尺寸 >
  640px ÷ ( 33.3vw × 1x ) = 1920px = 120em

当视口大于 120em 时,它始终是大于 36em的,因此我们可以把 36em 丢掉不管。在 1x 屏幕上,我们要加载 large.jpg的条件:

视口尺寸 > 120em

Ok,最后一个。

2x,断点后

视口尺寸 > 36em

…而且…

视口尺寸 >
  640px ÷ ( 33.3vw × 2x ) = 960px = 60em

…结论是,以下情况下在 2x 屏幕加载 large.jpg

视口尺寸 > 60em

把所有的组合一起放入媒体查询:

( (min-device-pixel-ratio: 1.5) and (min-width: 20.001em) and (max-width: 35.999em) ) or
( (max-device-pixel-ratio: 1.5) and (min-width: 120.001em) ) or
( (min-device-pixel-ratio: 1.5) and (min-width: 60.001em) )

medium.jpg 的计算过程就留给读者做练习。

使用最初的 <picture> 提案来标记我们的图片,结果是:

<picture>

  <source src="large.jpg"
          media="( (min-device-pixel-ratio: 1.5) and (min-width: 20.001em) and (max-width: 35.999em) ) or
                 ( (max-device-pixel-ratio: 1.5) and (min-width: 120.001em) ) or
                 ( (min-device-pixel-ratio: 1.5) and (min-width: 60.001em) )" />
  <source src="medium.jpg"
          media="( (max-device-pixel-ratio: 1.5) and (min-width: 20.001em) and (max-width: 35.999em) ) or
                 ( (max-device-pixel-ratio: 1.5) and (min-width: 60.001em) ) or
                 ( (min-device-pixel-ratio: 1.5) and (min-width: 10.001em) )" />
  <source src="small.jpg" />

  <!-- fallback -->
  <img src="small.jpg" alt="A rad wolf" />

</picture>

让人头痛!

另外,有一堆的标记不支持超过 2 的设备像素比,或是低于 1 的设备像素比,通常是不完美地支持这两者间的数值。如果我们要扩展设备像素比的支持,则要考虑的情景数量就会陡增。

关于标记最糟糕的部分是,如果我们改变任何一个基础变量 – 源图片的尺寸,要支持的设备分辨率… 或者影响图片尺寸的布局的任一方面 – 我们需要重新做过所有的算术。

快,还是早点跳到第二部分吧!

第二部分:srcset + sizes = 太棒了!

那么,如果媒体查询不是正确的工具的话,现在怎么办?

让我们先回到响应式图片的几个基本变量上,这一次,考虑下它们什么时候变,以及谁知道了什么。

变量 作者在写代码时是否清楚? 浏览器加载页面时是否清楚?
视口尺寸 no yes
图片相对视口的比例 yes no
像素密度 no yes
源文件尺寸 yes no

注意了!一列 yes 时,另一列总是 no:作者与浏览器所了解的不一样,它们是互补的。我们是钥匙主人,它们是看门人;把我们的力量结合起来,如此,如此。

怎样联合起来?

媒体查询就像一套紧急预案,“你看,”我们跟浏览器说,“我不清楚视口会有多大,但如果有这么大,那就用这个文件。如果还要大,用那个。如果屏幕是高清屏,那也用那个,但如果我切换到三列布局,那还是不要用那个…”我们是在给杂七八可能的文件贴标签,根据浏览器知道而我们写代码的无法知道的理由。

如我们所见的,实际上,这有太多工作要做。

那么,如果我们反过来呢?

譬如不再提供给浏览器一些乱七八糟的预案,只是告诉它它所不知道的东西?也就是说,图片相对于视口将怎样变换大小,以及源文件的尺寸。如果我们有办法把这些知识分享给浏览器,那选择源的条件不都就有了吗?

是的!实际上,这也是最新的 <picture> 细则中 size 属性和 srcset 中的 w 描述符所做的事。再来看一张表:

变量 作者在写代码时是否清楚? 浏览器加载页面时是否清楚?
视口尺寸 no yes
图片相对视口的比例 yes noyes! 通过 size
像素密度 no yes
源文件尺寸 yes noyes! 通过 srcset

在我们深入以前,且先搞明白三件事。

第一个,也是最重要的,目前(译注:原文写于 2014.3.24,译文的时间里 Chrome 34、Firefox 33 中已经实现)没有一个浏览器实现了它们,但前景看起来很不错,只是规范还没稳定。因此且慢使用。现在不能用,未来也只会出问题。

第二:曾经有一个叫 srcset 的响应式图片提案。我们要讲的全新提案依赖的属性也叫 srcset。新旧 srcset 均在逗号分隔的资源 URLS 列表中使用 w 描述符,但新旧 w 所代表的意思完全不一样!旧的 w 是媒体查询的简写形式:它描述的宽度是指视口宽度。新 w 则表示文件的宽度。我们随后就会详细解释新的 w,但现在,且让我掏出《黑衣人》中的记忆消除棒,消除掉你所有关于srcsetw 的知识。

都忘了?很好。

第三点:如果你一路看下来,对之前的 <picture> 细则燃起过希望的话,那么你要知道,新的 <picture> 细则中,仍然允许你使用媒体查询切换源,也可以附加分辨率描述符给源 URLs。如果你是在做艺术指导或是固定大小的分辨率切换,那你绝对应该使用这些特性。但如果你只是想让你的图片伸缩,则别有新工具可用。

Okay。我想我已经扫清障碍,做好准备。让我们处理下我们的案例,这次使用 srcsetsize

回顾一下,我们的图片有三个版本:

  • large.jpg (1024 x 768)
  • medium.jpg (640 x 480)
  • small.jpg (320 x 240)

还有一个 36em 的断点位置,我们的布局从一列切换到三列。

下面是标记:

<img src="small.jpg"
     srcset="large.jpg 1024w,
             medium.jpg 640w,
             small.jpg 320w"
     sizes="(min-width: 36em) 33.3vw,
            100vw"
     alt="A rad wolf" />

你可能注意到,虽然这段标记取自 picture 细则,但我们却没见到 picture 元素。srcsetsize 属性是应用到 <img>的,对于类似这个的简单的非艺术指导,非类型切换的案例,你可以也应该使用我们的老朋友 <img> 的实例来标记你的响应式图片。

一样的旧 <img>,全新的属性;让我们一个个看过去。

src="small.jpg"

这个一点都不新鲜嘛。正是我们的回落(fallback) src,功能照旧,在浏览器不识 srcset & size 的时候加载该图片。

下一个!

srcset="large.jpg 1024w,
        medium.jpg 640w,
        small.jpg 320w"

这个也是不说自明的。srcset 接受一个逗号分隔的 URLs 列表,指向当前图片的所有版本;每个图片的宽度由 w 描述符确定。因此,如果你”保存为 Web…“时图片为 1024×768,那么就在 srcset 中将其标记为 1024w。简单。

你可能注意到,这里我们只指定了宽度。为什么不一起指定高度?我们的布局中,图片是由宽度限定的,它们的宽度通常由 CSS 明确指定,但高度不是。大部分的响应式图片也是由宽度限定的,因此细则中为了简单就只处理宽度。

展望未来,我们有(我看来,非常棒的理由)使用 h 描述符来描述文件的高度,只是,还不到时候。

让我再强调一遍,你可以在 srcset 源中使用 1x/2x 这样的分辨率描述符替换 w 描述符,但不要在 srcset 中混合使用它们。真的。

Okay,这就是 srcsetw 了。

最后,浏览器在知道如何选择一个源文件前还需要知道图片在布局中的渲染尺寸。对于这个,我们有 sizes。从例子中看:

sizes="(min-width: 36em) 33.3vw,
       100vw"

格式是这样的:

sizes="[media query] [length], [media query] [length] ... etc"

我们让媒体查询与长度成对出现。浏览器检查每个媒体查询,直到碰上匹配的,就使用配对的那个长度作为源文件选择难题的最后一个因素:图片相对于视口的渲染比例。

“那是什么?”你说,“媒体查询?我以为你说过它们非常糟糕?!”

我确实说过,在选择源上,它们是非常糟糕的一种机制。但这里媒体查询所做的并不一样,它们只是让浏览器提前一点(也是非常关键的)时间知道它将要在页面 CSS 碰到的断点情况。记不记得,我们第一个例子中的各种查询,根本与页面的唯一断点(36em)毫无关系?我是说,60em,20em,10em – 它们到处都是。sizes 中的断点必须准确反应你的页面断点。媒体查询后的长度表示的是,媒体查询判断为真时,图片在布局中的长度。

于是,浏览器就有了所有必要的信息,来做第一部分中我们这又拖、又懒、还易出错的人类需要做的那种种计算。于是我们就得以轻松,然后如上帝所愿去吃豆子。

而且!还记得不我们的媒体查询示例只覆盖 1x & 2x 的屏幕?这个标记却可以在任何设备像素比上使用。不用再猜测它可能或不太可能支持哪些分辨率了。2016 年 4.8625x 的智能手表出来时,srcset & sizes 也已覆盖。

再者!这个办法也给了浏览器一些空间。指定给源的媒体查询或为真或为假,如果为真,则浏览器必须加载相应的源文件。sizessrcset 没那么死板。规范允许浏览器当带宽或慢或贵的时候加载较小的源文件。

“嗯,所有这些无疑地听起来很棒,”你说,缓缓地点着头,开始理解描述性的而非条件方法的好处。“可是等等,什么是长度?”

长度可以千奇百怪!一个长度可以是绝对的(比如 99px16em)或是相对的(33.3vw,就像我们的例子中)。你可能会注意到,不跟我们的例子一样,许多布局会结合使用绝对和相对单位。这也是意外地支持性特别好calc() 函数的用处。比如说我要给我们的三列布局增加一 12em 的侧边栏。我们这样调整我们的 sizes 属性:

sizes="(min-width: 36em) calc(.333 * (100vw - 12em)),
       100vw"

好了!

“Okay,okay,”你深思着说,摸了摸下巴,对这知识的涌入感到疲倦(也觉得激动)。“最后还有一件事:那个孤零零的 100vw是什么?你是不是忘了媒体查询?

在规范里,没有和媒体查询一同出现的长度是一个”默认长度“。如果没有匹配到哪个媒体查询,就使用默认的。这意味着,一张巨大的全宽横幅图片,你的标记可以如下简单:

<img src="small.jpg"
     srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"
     sizes="100vw"
     alt="A rad wolf" />

简单。

扩展阅读

  1. Responsive Images Done Right: A Guide To And srcset – Smashing Magazine