首页

你不知道的JavaScript:有趣的setTimeout

周周

     话不多说,先上代码

     for(var j=0;j<10;J++){

         setTimeout(function(){console.log(j);},5000)

     }

     看到这三行代码,你也许会不耐烦道:又要讲闭包?要吐槽了好么?别急,让我们先来思考一下,这段代码在浏览器中的执行结果是什么?

     <!-- more -->

     甲:顺序打印0到9?

     乙:这题我见过,打印十个10!

     哪个答案正确?

     执行结果显示,浏览器打印出十个10,貌似乙对了,但是如果你足够细心,你会发现几个问题:为什么会循环打印十个10,而不是0到9?

     从结果来看,for循环执行完跳出之后,才开始执行setTimeout(所以j才等于10),为什么不是每次迭代都执行一次setTimeout呢?

1、为什么会循环打印十个10?

      许多人习惯用第二个问题中的执行结果来回答这个问题:“for循环执行完毕跳出之后才开始执行setTimeout,所以才打印了十个10”。这样的答案,只能说是既应付了自己,又应付了别人。其实,要解答第一个问题,首先要解答第二个问题。

2、为什么不是每一次迭代都执行一次setTimeout?

     大家都知道,JavaScript在ES6出现以前,是没有块状作用域的,这就意味着,在for循环中用var定义的变量j,其实是属于全局的,那其实整个全局作用域中只有一个j,每次for循环都是更新这个j。

       那么现在的关键问题在于,为什么整个for循环会先于setTimeout执行,而不是我们正常理解的,一次迭代执行一次。这就涉及到了JavaScript的核心特性:单线程。

       JavaScript设计的初衷,是浏览器用来与用户进行交互和DOM操作的,这就决定了它必须是单线程的。设想JavaScript同时有两个线程,一个线程在DOM节点内添加内容,一个线程删除该节点,浏览器就会出现混乱。所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成为了这门语言的核心特征,将来也不会改变。

      单线程就意味着,所有任务需要排队,前一个任务结束,才会执行下一个任务,如果前一个任务耗时很长,后一个任务就不得不一直等着。

      为了优化单线程的性能,JavaScript将任务分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程,而进入“任务队列(task queue)”的任务,只用主线程中的同步任务执行完毕,异步任务才会进入执行队列执行。只要主线程空了,就会去读取“任务队列”,这就是JavaScript的运作机制。这个过程会不断重复。

       而setTimeout就被JavaScript定义为异步任务。每次for循环的迭代,都将setTimeout中的回调函数加入任务队列等待执行。也就是说,只有同步任务中的for循环完全结束,主线程中才会去任务列表中找到尚未执行的十个setTimeout(十次迭代)回调函数并顺序执行(先进先出)。而此时,j已经经过循环结束变成了10,所以此时主线程执行的,是十个一模一样的打印i的回调函数,即打印十个10,。至此完美回答了第一和第二个问题,文章开头的代码与下面的代码其实是等价的:

       for(var i=0;i<10;i++){

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

            setTimeout(console.log(i),5000);

}

       小小的一个setTimeout,牵扯出了很多JavaScript的深层次问题,可见JavaScript还有许多地方是值得深入探究的。



HTML条件注释用法诠释

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

HTML条件注释用法诠释

注释内容以样式为例,如下:

1、支持所有IE浏览器

<!--[if IE]>
<link rel="stylesheet" href="all-ie-only.css" type="text/css"/>
<![endif]--> 
  • 1
  • 2
  • 3

2、支持非IE浏览器

<!--[if !IE]>
<link rel="stylesheet" href="not-ie.css" type="text/css"/>
<![endif]--> 
  • 1
  • 2
  • 3

上面是除了IE浏览器外所有浏览器都识别这个样式,另外CSS-TRICKS《How To Create an IE-Only Stylesheet》一文中提供了另一种写法:

<!--[if !IE]><!--> <link rel="stylesheet" type="text/css" href="not-ie.css" /> <!--<![endif]--> 
  • 1
  • 2
  • 3

3、仅仅支持IE10

<!--[if IE 10]>
<link rel="stylesheet" type="text/css" href="ie10.css">
<![endif]--> 
  • 1
  • 2
  • 3

4、支持IE10以下版本(IE9以及IE9以下版本)

这种方法是样式表使用在低于IE10的浏览器,换句话说除了IE10以外的所有IE版本都将被支持。

<!--[if lt IE 10]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]--> 
  • 1
  • 2
  • 3

也可以写成

<!--[if lte IE 9]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]--> 
  • 1
  • 2
  • 3

前面我们也说过了lt和lte的区别,lt表示小于版本号,不包括条件版本号本身;而lte是小于或等于版本号,包括了版本号自身

上面这几种方法,使用的是低于(lt)和低于或等于(lte)的方法来判断,我们也可以使用大于gt和大于或等于gte达到上面的效果:

5、高于IE9的版本(IE10以及IE10以上版本)

<!--[if gt IE 9]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]--> 
  • 1
  • 2
  • 3

<!--[if gte IE 10]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]--> 
  • 1
  • 2
  • 3

6、指定多种IE版本

<!--[if (IE 6)|(IE 7)|(IE 8)]>
<link rel="stylesheet" type="text/css" href="ie6-7-8.css">
<![endif]--> 
  • 1
  • 2
  • 3

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务




javascript中数组和对象的深拷贝和浅拷贝

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

1、首先理解一下“深拷贝”和“浅拷贝”的区别:

浅拷贝:a = b;//a和b中存的是相同的地址,该地址指向堆内存中相同的地方,即a和b就是一个东西,改变a的值b的值也会跟着改变,同理改变b的值a的值也会发生改变;

深拷贝:a和b中存的地址不同,但是地址对应的堆内存中的内容完全一致,即b是a的副本

2、

(1)数组和对象的浅拷贝一样  ,简单的赋值操作

var b = a;

如数组的浅拷贝:

[javascript] view plain copy
  1. var a = ['1','2','3'];  
  2. var b = a;  
  3. b[0] = '5';  
  4. console.log('a',a);  
  5. console.log('b',b);  

输出的值为:

对象的浅拷贝:

[html] view plain copy
  1. var a = {name:'1',age:'2',color:'3'};  
  2. var b = a;  
  3. b.name = '5';  
  4. console.log('a',a);  
  5. console.log('b',b);  

输出的值为:

(2)数组的深拷贝

ES5:var b = a.concat();

[javascript] view plain copy
  1. var a = ['1','2','3'];  
  2. var b = a.concat();  
  3. b[0] = '5';  
  4. console.log('a',a);  
  5. console.log('b',b);  

输出的结果为:

ES6 let [...b] = a;

(3)对象的深拷贝

ES5: 

[javascript] view plain copy
  1. var a = {name:'1',age:'2',color:'3'};  
  2. function copyObj(a) {  
  3. var b = {};  
  4. for(var key in a) {  
  5. b[key] = a[key];  
  6. }  
  7. return b;  
  8. }  
  9. var c = copyObj(a);  
  10. c.name = '5';  
  11. console.log('c',c);  
  12. console.log('a',a);  

输出的结果为:

ES6:

let {...b} = a;


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


jQuery选择器(二)基本选择器+层次选择器

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

1:获取所有的<p>元素,对<p>元素继续循环,因为获取的是数组对象,给每个<p>元素添加行为事件

var items=document.getElementsByTagName("p"); for(var i=0;i<items.length;i++){
    items[i].onclick=function(){ //do something  }
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2:根据表格id获取表格,在表格内获取<tbody>元素,在<tbody>元素下获取<tr>元素,循环输出获取的<tr>元素,对元素的索引值除以2取模,然后根据奇偶设置不同的背景色。

var item=docuement.getElementById("tb"); var tbody=item.getElementsByTagName("tbody")[0]; var trs=tbody.getElementByTagName("tr"); for(var i=0;i<trs.length;i++){ if(i%2==0){
      trs[i].style.backgroundColor="#888";
   }
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3:新建一个空数组,获取所有name为”check”的多选框,循环判断多选框是否被选中,如果被选中则添加到数组里,获取输出按钮,然后为按钮添加onclick事件,输出数组长度即可。

var btn=document.getElementById("btn");
btn.onclick=function(){ var array=new Array(); var items=document.getElementsByName("check"); for(i=0;i<items.length;i++){ if(items[i].checked){ array.push(items[i].value);
     }
  }
  alert(array.length);  
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

基本选择器:

#id  $("#test")选取id为test的元素 .class $(".test")选取所有classtest的元素 element $("p")选取所有的<p>元素 $("div,span,p.myClass") 选取所有的<div>,<span>和拥有classmyClass<p>标签的一组元素
    
  • 1
  • 2
  • 3
  • 4
  • 5

层次选择器:

$("ancestor  descendant") $("div span")选取<div>里面所有的<span>元素 $("parent>child") $("div >span")选取<div>元素下元素名为<span>的子元素 $("prev+next") $(".one+div")选取classone的下一个<div>同辈元素 $("#two~div")选取id为two的元素后面的所有<div>同辈元素

后面两个用得少,因为在jQuery里可以用更加简单的方法代替 $(".one+div") $(".one").next("div"); $("prev~div") $("#prev").nextAll("div");
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


HTML基础应用

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

本篇文章基本介绍了学习HTML的一些基础的语法与标签,标签包括换行</br>,加粗<b>,下划线<hr/>斜体字<i>,字体<h1....6>,标题<title>......

<small>

<small> 标签呈现小号字体效果

。如果被包围的字体已经是字体模型所支持的最小字号,那么 <small> 标签将不起任何作用。

<small> 标签也可以嵌套,从而连续地把文字缩小。每个 <small> 标签都把文本的字体变小一号,直到达到下限的一号字。

<sub>表示下标<sup>表示上标。

<p>与<pre>有些类似

pre 元素可定义预格式化的文本。被包围在 pre 元素中的文本通常会保留空格和换行符。而文本也会呈现为等宽字体。

<pre> 标签的一个常见应用就是用来表示计算机的源代码。

p 元素会自动在其前后创建一些空白。

<ul>与<ol>

两者都指列表,前者是无序的,后者是有序的。

[html] view plain copy
  1. <html>  
  2. <head>  
  3. <span style="color:#33ff33;"><title></span>HTML 5 Tag Reference</title>  
  4. </head>  
  5. <body>  
  6. <span style="color:#33ff33;"><h1></span>The content of the document......<span style="color:#33ff33;"><br/></span></h1>  
  7. <h2>The content of the document......<br/></h2>  
  8. <h3>The content of the document......<br/></h3>  
  9. <h4>The content of the document......<br/></h4>  
  10. <h5>The content of the document......</h5>  
  11.   
  12. <h1>The content of the document......<br/></h1>  
  13. <h1><span style="color:#33ff33;"><small></span>The content of the document......</small><br/></h1>  
  14.   
  15. <span style="color:#33ff33;"><pre></span>  
  16. HTML基础应用  
  17.   
  18. HTML基础应用学习和掌握HTML语言的基本语法,常用的标签的使用方法;学会使用HTML设计基本的简单  
  19.   
  20. 网页。  
  21.   
  22. </pre>  
  23. <span style="color:#33ff33;"><hr/></span>  
  24. <span style="color:#33ff33;"><p>  
  25. <i></span>This is some text in a very short paragraph</i>  
  26. </p>  
  27. <span style="color:#33ff33;"><b></span>The content of the document......</b></br>  
  28.   
  29. a<span style="color:#33ff33;"><sup>2</sup><sub>0</sub></span>+b<sup>2</sup><sub>0</sub>=c<sup>2</sup><sub>0</sub>  
  30.   
  31. <span style="color:#33ff33;"><ul></span>  
  32. <li>sports</li>  
  33. <li> food </li>  
  34. <li> drink </li>  
  35. <li> friends </li>  
  36. </ul>  
  37. <span style="color:#33ff33;"><ol></span>  
  38.     <li>sports</li>  
  39.     <li> drink</li>  
  40.     <li> friends</li>  
  41. </ol>  
  42.   
  43. <span style="color:#33ff33;"><dl> </span>  
  44. <dt>计算机</dt>   
  45.     <dd>用来计算的仪器 ... ...</dd>   
  46. <dt>显示器</dt>   
  47.     <dd>以视觉方式显示信息的装置 ... ...</dd>   
  48. </dl>   
  49.   
  50. </body>  
  51. </html>  

效果:

其中<title>体现在最上方的搜索栏中。

 


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

用Flow提升前端代码健壮性

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

看一段常见代码:

//例1 function foo(x) { return x + 10 }
foo('Hello!') //例2 function main(params){ //fn1函数获取了一个数据 var object = fn1(params) //fn2根据获数据,产生一个结果 var result = fn2(object) return result
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

例2很明显,这个过程非常的‘黑’,如果你想知道object包含什么数据的话,可以:

  1. 打印一下 console.log(object)
  2. 查看fn1的注释,并且保佑它的注释是正确,全面的
  3. 或结合1,2,然后仔细查看fn1的源码,希望它不是很复杂

被上述步骤折磨完之后,终于能真正的写点代码了,但是依旧得非常小心,因为这里还有另一个函数:fn2

在修改代码的时候,得保证result这个结果没有被影响,那么如何保证呢?

很简单,重复上面的步骤,搞清楚result包含的数据,在测试的时候确保其数据跟原先的相同。 

动态类型一时爽,代码重构火葬场 
知乎传送门:为什么说“动态类型一时爽,代码重构火葬场”

是时候彻底优化这个烦人的问题了

引入类型系统

其实问题的根源就是因为javascript太灵活了,在代码运行期间几乎可以做任何的修改,

没有东西可以在代码层面保证 某个变量,某个函数 跟预期的一致

所以要加入类型系统来确保代码的可靠性,在后期维护的时候同样能够传达出有效的信息

Flow & TypeScript

Flow是个JavaScript的静态类型检查工具,由Facebook出品的开源码项目,问世只有两三年,是个相当年轻的项目。简单来说,它是对比TypeScript语言的解决方式。

会有这类解决方案,起因是JavaScript是一种弱(动态)数据类型的语言,弱(动态)数据类型代表在代码中,变量或常量会自动依照赋值变更数据类型,而且类型种类也很少,这是直译式脚本语言的常见特性,但有可能是优点也是很大的缺点。优点是容易学习与使用,缺点是像开发者经常会因为赋值或传值的类型错误,造成不如预期的结果。有些时候在使用框架或函数库时,如果没有仔细看文件,亦或是文件写得不清不楚,也容易造成误用的情况。

这个缺点在应用规模化时,会显得更加严重。我们在团队开发协同时,一般都是通过统一的代码规范,来降低这个问题的发生,但JS语言本身无法有效阻止这些问题TypeScript这样的强(静态)类型的JavaScript超集语言就开始流行,用严格的角度,以JavaScript语言为基底,来重新打造另一套具有强(静态)类型特性的语言,就如同Java或C#这些语言一样,这也是为什么TypeScript称自己是企业级的开发JavaScript解决方案。

TypeScript存在的问题

TypeScript自然有它的市场,但它有一些明显的问题:

  • 首先是JavaScript开发者需要再进一步学习,内容不少
  • 有一定陡峭的学习曲线
  • 已经在使用的应用代码,需要整个改用TypeScript代码语法,才能发挥完整的功用。这对很多已经有内部代码库的大型应用开发团队而言,将会是个重大的决定,因为如果不往全面重构的路走,将无法发挥强(静态)类型语言的最大效用eg:angular2

*所以许多现行的开源码函数库或框架,并不会直接使用TypeScript作为代码的语言,另一方面因为TypeScript并非是普及到一定程度的语言。 
当然TypeScript也是个活跃的开源码项目,发展到现在也有一段时间,它的背后有微软公司的支持,全新打造过的Angular2框架中(由Google主导),也采用了TypeScript作为基础的开发语言*

Flow你的新选择

现在,Flow提供了另一个新的选项,它是一种强(静态)类型的辅助检查工具Flow的功能是让现有的JavaScript语法可以事先作类型的声明(定义),在开发过程中进行自动检查,当然在最后编译时,一样可以用babel工具来移除这些标记

相较于TypeScript是另外重新制定一套语言,最后再经过编译为JavaScript代码来运行。Flow走的则是非强制与非侵入性的路线。

Flow的优点

  • 且易学易用 
    它的学习曲线没有TypeScript来得高,虽然内容也很多,但半天学个大概,就可以渐进式地开始使用
  • Flow从头到尾只是个检查工具 
    不是新的程序语言或超集语言,所以它可以与各种现有的JavaScript代码兼容,如果你哪天不想用了,就去除掉标记就是回到原来的代码,没什么负担

so

选择flow.js工具而不选择TypeScript强类型语言的原因显而易见? 
flow.js对工程的侵入性很小,无需大量的额外工作就能使用起来

从一个小例子演示

这种类型不符的情况在代码中非常容易发生,例如上面的例1:

function foo(x) { return x + 10 }

foo('Hello!')
    
  • 1
  • 2
  • 3
  • 4
  • 5

x这个传参,我们在函数声明时希望它是个数字类型,但最后使用调用函数时则用了字符串类型。最后的结果会是什么吗? “Hello!10”,这是因为加号(+)在JavaScript语言中,除了作为数字的加运算外,也可以当作字符串的连接运算。想当然这并不是我们想要的结果。

聪明如你应该会想要用类型来当传参的识别名,容易一眼看出传参要的是什么类型,像下面这样:

function foo(number) { return number + 10 }
    
  • 1
  • 2
  • 3
  • 如果在复合类型的情况,例如这个传参的类型可以是数字类型也可以是布尔类型,你又要如何写得清楚?
  • 如果是个复杂的对象类型时,结构又该如何先确定好?
  • 另外还有函数的返回类型又该如何来写?

利用Flow类型的定义方式,来解决这个小案例的问题,可以改写为像下面的代码:

// @flow function foo(x: number): number { return x + 10 }

foo('hi')
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

当使用非数字类型的值作为传入值时,就会出现由Flow工具发出的警告消息,像下面这样:

[flow] Cannot call foo with 'hi' bound to x because string 1 is incompatible with number 2. (a.getting-start.js:6:5)

如果是要允许多种类型也是很容易可以加标记的,假使这个函数可以使用布尔与数字类型,但返回可以是数字或字符串,就像下面这样修改过:

// @flow function foo(x: number | boolean): number | string { if (typeof x === 'number') { return x + 10 } return 'x is boolean' }

foo(1)
foo(true)
foo(null) // 这一行有类型错误消息
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在多人协同开发某个有规模的JavaScript应用时,这种类型的输出输入问题就会很常遇见。如果利用Flow工具的检查,可以避免掉许多不必要的类型问题

真实案例

可能你会认为Flow工具只能运用在小型代码中,其实不然,Vue源码中大量使用flowjs中类型检测: 
此处输入图片的描述

Flow使用

此处输入图片的描述 
1. flow init 
2. // @flow 或 /* @flow */ 
3. IDE插件 或 flow check 
在Visual Studio Code中因为它内建TypeScript与JavaScript的检查功能,如果要使用Flow工具来作类型检查,需要在用户设置中,加上下面这行设置值以免冲突:

“javascript.validate.enable”: false

4 . babel插件在编译时就会一并转换Flow标记

{
  "plugins": [ "transform-flow-strip-types" ] }
    
  • 1
  • 2
  • 3
  • 4
  • 5

Flow支持的数据类型

Flow支持原始数据类型,如下面的列表:

  • boolean
  • number
  • string
  • null
  • void

类型别名&常见语法

// @flow export type Test = {
  titleOne?: string,
  titleTwo: ?string
} var a: Test = {titleOne:"3",titleTwo:4} var b:string = "" //any export type NavigationGestureDirection = 'horizontal' | 'vertical';

type T = Array<string> var x: T = []
x["Hi"] = 2 //有Flow警告 type TT = Array<Test> var xx:TT = []
xx = [{titleOne: '1',
  titleTwo: false}]

type MyObject = {
  foo: number,
  bar: boolean,
  baz: string,
};

let val:MyObject = {foo:2,bar:false,baz:'444'}; var val1: MyObject = {foo:2,bar:false,baz:null}; var val2: MyObject = {foo:2,bar:false}; function method(val: MyObject):MyObject { return {foo:2,bar:false,baz:'2'}} class Foo { constructor(val: MyObject) { /* ... */ } }
    
  • 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

React中的应用

如果你在React class里面使用了React.PropTypes规范,你可以对JSX上的attributes做静态类型检查:

var Hello = React.createClass ({
  propTypes: {
    name: React.PropTypes.string.isRequired
  } ... });
//<Hello/> //Flow就会发现 缺少属性的错误
//<Hello name={42}/>//属性类型的错误
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
import * as React from 'react'; type Props = {
  foo: number,
  bar?: string,
}; function MyComponent(props: Props) {
  props.doesNotExist; // Error! You did not define a `doesNotExist` prop. return <div>{props.bar}</div>;
}

<MyComponent foo={42} />
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

更多关于支持React的细节 请移步 https://flow.org/en/docs/react/components/

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

如何看待CSS中BEM的命名方式?

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

BEM的意识就是块(block)、元素(element)、修饰符(modifier),是由yandex团队提出的一种CSS Class命名方法。

任何一个东西的存在都有其存在的道理,如果他毫无价值,那么肯定会被淘汰,后人可能都不了解,甚至都不会出现在后人的世界里。

如何看待CSS中BEM的命名方式?

关于BEM命名其最大的争议就是其命名风格,它鼓励一级一级的写的非常具体,但是会很长。如此常的命名会影响书写效率,名称过长代码量就会增多,文件体积就会变大(在gzip下这个不算是个问题),从而会影响传输速度,用户体验度就低,但是作为一个职业人我们都不能单纯把个人喜好和习惯作为借口来拒绝或否定其用途。

风格对于使用者来说并不是很重要,关键的是看其效果。正所谓人们常说的“不看疗程,看疗效”。

从扩展性上来看,嵌套过多阅读性差,超过3层就很难阅读了;嵌套越多,选择器的层级也会随之增多,那么性能不知不觉就会变差;如此长的名字,书写上想冲突都难。

从编程原则上来说,这种命名方式不会暴露抽象类。假如样式变了需要继承另一个抽象类,不需要改HTML,只需要改css即可。

团队开发中,风格无非是一种形式,可以约束人们达到一定程度上的统一。内部沟通会极大降低沟通成本。

BEM命名的方法虽然有自身的不足之处,但至少他可以使我们命名的时候达到一定的统一,我们可以学习其优秀的方面将其纳为己用。在实际项目开发中将其巧妙而又灵活的运用起来也未尝不是一件坏事。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

JS作用域、立即执行函数、闭包

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

作用域    

首先先介绍一下作用域等一些基础概念。

 每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。

[[scope]] : 指的就是我们所说的作用域,其中存储了执行期上下文的集合

作用域链 : [[scope]] 中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链接叫做作用域链。

运行期上下文  : 当函数执行时,会创建一个称为执行期上下文的内部对象(AO)。一个执行期上下文定义了一个函数执行的环境,函数每次执行时对应的执行环境都是的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。

查找变量  :从作用域链的顶端依次向下查找。

下面举一些例子:

[html] view plain copy
  1. function a(){  
  2.     function b(){  
  3.         function c(){  
  4.   
  5.         }  
  6.         c();  
  7.     }  
  8.     b();  
  9. }  
  10. a();  
  11.   
  12.   
  13. a defined a.[[scope]] ----> 0 : GO          //a定义的时候产生GO对象  
  14. a doing   a.[[scope]] ----> 0 : aAO           //a执行的时候新产生AO对象  
  15.                             1 : GO  
  16.   
  17. b defined  b.[[scope]] ----> 0 : aAO            //子级b定义会继承父级a运行时产生的对象  
  18.                              1 : GO   
  19. b doing    b.[[scope]] ---->  0 : bAO            //子级b新产生AO对象  
  20.                               1 : aAO   
  21.                               2 : GO   
  22.                                 
  23. c defined  c.[[scope]] ---->  0 : bAO            //c定义时会继承b运行时产生的属性  
  24.                               1 : aAO   
  25.                               2 : GO                          
  26. c doing     c.[[scope]] ----> 0 : cAO            //c执行时同时又产生新的AO  
  27.                               1 ;bAO   
  28.                               2 : aAO   
  29.                               3 : GO   

立即执行函数

之前学过函数的定义、函数表达式,还有一种函数叫做立即执行函数。

立即执行函数:函数执行过后立即被销毁。

立即执行函数的官方写法:

[html] view plain copy
  1. // 立即执行函数的官方写法  
  2. (function() {} ());  W3C建议此种  
  3. (function() {})();  

针对初始化功能的函数,可以有参数。

[html] view plain copy
  1. var num = function (a,b){  
  2.     return a + b;  
  3. }(1,2);  
  4.   
  5. (function abc(){  
  6.     var a = 123;  
  7.     var b = 234;  
  8.     console.log(a+b);  
  9. }())  

只有表达式才能被执行符号执行,能被执行符号执行的表达式,函数名字会被自动忽略。

[html] view plain copy
  1. function test(){  
  2.     console.log("a");  
  3. }()    会出现语法解析错误,因为括号前面是函数声明  
  4.   
  5. (+ function test( ){  
  6.     console.log('a');  
  7. }())                    -------->打印出a  

下面是一道曾阿里面试题

[html] view plain copy
  1. function test(a, b, c, d){  
  2.     console.log(a + b + c + d);  
  3. }(1, 2, 3, 4);  
  4.   
  5. // 不报错也没有执行        

下面是几道经典的例题,可以参考一下:

[html] view plain copy
  1.   
[html] view plain copy
  1. function test(){  
  2.     var arr = [];  
  3.     for(var i = 0; i < 10; i ++){  
  4.         arr[i] = function (){  
  5.             console.log(i);  
  6.         }  
  7.     }  
  8.     return arr;  
  9. }  
  10. var myArr = test();  
  11. for(var j = 0; j < 10; j++){  
  12.     myArr[j]();  
  13. }    
[html] view plain copy
  1.   
[html] view plain copy
  1. // 输出:10个10  

那么采用立即执行函数呢?会有怎样的结果呢?

[html] view plain copy
  1. function test(){  
  2.     var arr = [];  
  3.     for(var i = 0; i < 10; i ++){  
  4.         (function(j){  
  5.             arr[i] = function (){  
  6.             console.log(j + " ");  
  7.         }  
  8.         }(i))  
  9.     }  
  10.     return arr;  
  11. }  
  12. var myArr = test();  
  13. for(var j = 0; j < 10; j++){  
  14.     myArr[j]();  
  15. }   
[html] view plain copy
  1.   
[html] view plain copy
  1. // 输出结果  0 1 2 3 4 5 6 7 8 9   

大家可以自行思考一下。

闭包

闭包的现象:当内部函数保存到外部时会产生闭包。


闭包会导致原有的作用域链不释放,造成内存泄漏

(内存泄漏:内存占用(比如:手握沙子,握得越紧手里剩得就越少))


闭包触发的情况:

    两个或多个函数互相嵌套,把里面的函数保存到外部,这样的情况一定会产生闭包。从外面还可以调用里面的函数。


闭包的作用:

            实现公有变量

                    eg:函数累加器

            可以做缓存(存储结构)

                    eg:eater

               可以实现封装,属性私有化

                    eg:person()

                模块化开发,防止污染全局变量



[html] view plain copy
  1. // 函数累加器  
  2. function add(){  
  3.     var count = 0;  
  4.     function demo(){  
  5.         count ++;  
  6.         console.log(count);  
  7.     }  
  8.     return demo;  
  9. }  
  10. var counter = add();  
  11. counter();  
  12. counter();  
  13. counter();  
  14. counter();  
  15. counter();  
  16. counter();  
  17.   
  18.   
  19. // eater  
  20. function test(){  
  21.     var food = "apple";  
  22.     var obj = {  
  23.         eatFood : function (){  
  24.             if(food != ""){  
  25.                 console.log("I am eating  " + food);  
  26.                 food = "";  
  27.             }  
  28.             else{  
  29.                 console.log("There is nothing!");  
  30.             }  
  31.         },  
  32.         pushFood : function (myFood){  
  33.             food = myFood;  
  34.         }  
  35.     }  
  36.     return obj;  
  37. }  
  38. var person = test();  
  39. person.eatFood();  
  40. person.eatFood();  
  41. person.pushFood('banana');  
  42. person.eatFood();  

附加一个逗号操作符:

        先看前面的表达式,再看后面的表达式,把后面表达式的计算结构返回

例题:

[html] view plain copy
  1. var f =(  
  2.     function f(){  
  3.         return "1";  
  4.     },  
  5.     function g(){  
  6.         return 2;  
  7.     }  
  8. )();  
  9. console.log(typeof(f));   
  10.   
  11. // -------number  
  12.   
  13. var x = 1;  
  14. if(function f(){}){  
  15.     x += typeof f;  
  16. }  
  17. console.log(x);  
  18. // --------> 1undefined  
  19. 蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

HTML条件注释用法诠释

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

HTML条件注释用法诠释

注释内容以样式为例,如下:

1、支持所有IE浏览器

<!--[if IE]>
<link rel="stylesheet" href="all-ie-only.css" type="text/css"/>
<![endif]-->
    
  • 1
  • 2
  • 3

2、支持非IE浏览器

<!--[if !IE]>
<link rel="stylesheet" href="not-ie.css" type="text/css"/>
<![endif]-->
    
  • 1
  • 2
  • 3

上面是除了IE浏览器外所有浏览器都识别这个样式,另外CSS-TRICKS《How To Create an IE-Only Stylesheet》一文中提供了另一种写法:

<!--[if !IE]><!--> <link rel="stylesheet" type="text/css" href="not-ie.css" /> <!--<![endif]-->
    
  • 1
  • 2
  • 3

3、仅仅支持IE10

<!--[if IE 10]>
<link rel="stylesheet" type="text/css" href="ie10.css">
<![endif]-->
    
  • 1
  • 2
  • 3

4、支持IE10以下版本(IE9以及IE9以下版本)

这种方法是样式表使用在低于IE10的浏览器,换句话说除了IE10以外的所有IE版本都将被支持。

<!--[if lt IE 10]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]-->
    
  • 1
  • 2
  • 3

也可以写成

<!--[if lte IE 9]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]-->
    
  • 1
  • 2
  • 3

前面我们也说过了lt和lte的区别,lt表示小于版本号,不包括条件版本号本身;而lte是小于或等于版本号,包括了版本号自身

上面这几种方法,使用的是低于(lt)和低于或等于(lte)的方法来判断,我们也可以使用大于gt和大于或等于gte达到上面的效果:

5、高于IE9的版本(IE10以及IE10以上版本)

<!--[if gt IE 9]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]-->
    
  • 1
  • 2
  • 3

<!--[if gte IE 10]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]-->
    
  • 1
  • 2
  • 3

6、指定多种IE版本

<!--[if (IE 6)|(IE 7)|(IE 8)]>
<link rel="stylesheet" type="text/css" href="ie6-7-8.css">
<![endif]-->
    
  • 1
  • 2
  • 3

参考: 
https://www.cnblogs.com/hushufang/p/3708704.html

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

获取网页授权

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

在微信登录中,如何和获取网页授权。

一、登录微信测试公众品平台,修改网页授权基本信息,输入授权回调页面域名(自己的域名)。

然后重新建立一个tp框架 编写方法如图:

[php] view plain copy
  1. <?php  
  2. namespace Home\Controller;  
  3. use Think\Controller;  
  4. class IndexController extends Controller {  
  5.     public function index(){  
  6.        $appid='wx27f664ab15ecb71d';  
  7.        $redirect_uri=urlencode('http://www.crimson1.top/vote/index.php/home/index/getcode');  
  8.        $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appid&redirect_uri=$redirect_uri&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";  
  9.   
  10.              header("Location:".$url);  
  11.     }  
  12.   
  13.     public function getcode(){  
  14.         $code=$_GET["code"];  
  15.          $json=$this->access_token($code);  
  16.          echo $json;  
  17.     }  
  18.     public function access_token($code){  
  19.         $appid="wx27f664ab15ecb71d";  
  20.         $appsecret="015756334f2982ed1189c6d66dbc0353";  
  21.         $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$appsecret&code=$code&grant_type=authorization_code";  
  22.   
  23.         $ret=https_request($url);  
  24.         return $ret;  
  25.     }  
  26. }  

在公共模块中新建function.php

[php] view plain copy
  1. <?php  
  2. function https_request($url){  
  3.     $curl=curl_init();  
  4.     curl_setopt($curl, CURLOPT_URL, $url);  
  5.     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);  
  6.     curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);  
  7.     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  
  8.     $data=curl_exec($curl);  
  9.     if(curl_errno($curl)){  
  10.         return 'ERROR'.curl_error($curl);  
  11.     }  
  12.     curl_close($curl);  
  13.     return $data;  
  14. }  

在自己的手机端访问,就能获取access_token;

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档