如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
例2很明显,这个过程非常的‘黑’,如果你想知道object包含什么数据的话,可以:
被上述步骤折磨完之后,终于能真正的写点代码了,但是依旧得非常小心,因为这里还有另一个函数:fn2
在修改代码的时候,得保证result这个结果没有被影响,那么如何保证呢?
很简单,重复上面的步骤,搞清楚result包含的数据,在测试的时候确保其数据跟原先的相同。
动态类型一时爽,代码重构火葬场
是时候彻底优化这个烦人的问题了
其实问题的根源就是因为javascript太灵活了,在代码运行期间几乎可以做任何的修改,
没有东西可以在代码层面保证 某个变量,某个函数 跟预期的一致。
所以要加入类型系统来确保代码的可靠性,在后期维护的时候同样能够传达出有效的信息
Flow是个JavaScript的静态类型检查工具,由Facebook出品的开源码项目,问世只有两三年,是个相当年轻的项目。简单来说,它是对比TypeScript语言的解决方式。
会有这类解决方案,起因是JavaScript是一种弱(动态)数据类型的语言,弱(动态)数据类型代表在代码中,变量或常量会自动依照赋值变更数据类型,而且类型种类也很少,这是直译式脚本语言的常见特性,但有可能是优点也是很大的缺点。优点是容易学习与使用,缺点是像开发者经常会因为赋值或传值的类型错误,造成不如预期的结果。有些时候在使用框架或函数库时,如果没有仔细看文件,亦或是文件写得不清不楚,也容易造成误用的情况。
这个缺点在应用规模化时,会显得更加严重。我们在团队开发协同时,一般都是通过统一的代码规范,来降低这个问题的发生,但
TypeScript自然有它的市场,但它有一些明显的问题:
*所以许多现行的开源码函数库或框架,并不会直接使用TypeScript作为代码的语言,另一方面因为TypeScript并非是普及到一定程度的语言。
现在,Flow提供了另一个新的选项,它是一种强(静态)类型的辅助
相较于TypeScript是另外重新制定一套语言,最后再经过编译为JavaScript代码来运行。Flow走的则是非强制与非侵入性的路线。
选择flow.js工具而不选择TypeScript强类型语言的原因显而易见?
这种类型不符的情况在代码中非常容易发生,例如上面的例1:
x这个传参,我们在函数声明时希望它是个数字类型,但最后使用调用函数时则用了字符串类型。最后的结果会是什么吗? “Hello!10”,这是因为加号(+)在JavaScript语言中,除了作为数字的加运算外,也可以当作字符串的连接运算。想当然这并不是我们想要的结果。
聪明如你应该会想要用类型来当传参的识别名,容易一眼看出传参要的是什么类型,像下面这样:
利用Flow类型的定义方式,来解决这个小案例的问题,可以改写为像下面的代码:
当使用非数字类型的值作为传入值时,就会出现由Flow工具发出的警告消息,像下面这样:
[flow] Cannot call
如果是要允许多种类型也是很容易可以加标记的,假使这个函数可以使用布尔与数字类型,但返回可以是数字或字符串,就像下面这样修改过:
在多人协同开发某个有规模的JavaScript应用时,这种类型的输出输入问题就会很常遇见。如果利用Flow工具的检查,可以避免掉许多不必要的类型问题。
可能你会认为Flow工具只能运用在小型代码中,其实不然,Vue源码中大量使用flowjs中类型检测:
“javascript.validate.enable”: false
4 . babel插件在编译时就会一并转换Flow标记
Flow支持原始数据类型,如下面的列表:
如果你在React class里面使用了React.PropTypes规范,你可以对JSX上的attributes做静态类型检查:
更多关于支持React的细节 请移步 https://flow.org/en/docs/react/components/
看一段常见代码:
//例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
}
…
知乎传送门:为什么说“动态类型一时爽,代码重构火葬场”
引入类型系统
Flow & TypeScript
JS语言本身
无法有效阻止这些问题。TypeScript这样的强(静态)类型的JavaScript超集语言就开始流行,用严格的角度,以JavaScript语言为基底,来重新打造另一套具有强(静态)类型特性的语言,就如同Java或C#这些语言一样,这也是为什么TypeScript称自己是企业级的开发JavaScript解决方案。
TypeScript存在的问题
当然TypeScript也是个活跃的开源码项目,发展到现在也有一段时间,它的背后有微软公司的支持,全新打造过的Angular2框架中(由Google主导),也采用了TypeScript作为基础的开发语言*。
Flow你的新选择
检查工具
。Flow的功能是让现有的JavaScript语法可以事先作类型的声明(定义),在开发过程中进行自动检查
,当然在最后编译时,一样可以用babel工具来移除这些标记。
Flow的优点
轻
且易学易用
它的学习曲线没有TypeScript来得高,虽然内容也很多,但半天学个大概,就可以渐进式地开始使用
检查工具
不是新的程序语言或超集语言,所以它可以与各种现有的JavaScript代码兼容,如果你哪天不想用了,就去除掉标记就是回到原来的代码,没什么负担
so
flow.js对工程的侵入性很小,无需大量的额外工作就能使用起来
从一个小例子演示
function foo(x) { return x + 10 }
foo('Hello!')
function foo(number) { return number + 10 }
// @flow function foo(x: number): number { return x + 10 }
foo('hi')
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) // 这一行有类型错误消息
真实案例
Flow使用
1. flow init
2. // @flow 或 /* @flow */
3. IDE插件 或 flow check
在Visual Studio Code中因为它内建TypeScript与JavaScript的检查功能,如果要使用Flow工具来作类型检查,需要在用户设置中,加上下面这行设置值以免冲突:
{
"plugins": [ "transform-flow-strip-types" ] }
Flow支持的数据类型
类型别名&常见语法
// @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) { /* ... */ } }
React中的应用
var Hello = React.createClass ({
propTypes: {
name: React.PropTypes.string.isRequired
} ... });
//<Hello/> //Flow就会发现 缺少属性的错误
//<Hello name={42}/>//属性类型的错误
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} />
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
BEM的意识就是块(block)、元素(element)、修饰符(modifier),是由yandex团队提出的一种CSS Class命名方法。
任何一个东西的存在都有其存在的道理,如果他毫无价值,那么肯定会被淘汰,后人可能都不了解,甚至都不会出现在后人的世界里。
关于BEM命名其最大的争议就是其命名风格,它鼓励一级一级的写的非常具体,但是会很长。如此常的命名会影响书写效率,名称过长代码量就会增多,文件体积就会变大(在gzip下这个不算是个问题),从而会影响传输速度,用户体验度就低,但是作为一个职业人我们都不能单纯把个人喜好和习惯作为借口来拒绝或否定其用途。
风格对于使用者来说并不是很重要,关键的是看其效果。正所谓人们常说的“不看疗程,看疗效”。
从扩展性上来看,嵌套过多阅读性差,超过3层就很难阅读了;嵌套越多,选择器的层级也会随之增多,那么性能不知不觉就会变差;如此长的名字,书写上想冲突都难。
从编程原则上来说,这种命名方式不会暴露抽象类。假如样式变了需要继承另一个抽象类,不需要改HTML,只需要改css即可。
团队开发中,风格无非是一种形式,可以约束人们达到一定程度上的统一。内部沟通会极大降低沟通成本。
BEM命名的方法虽然有自身的不足之处,但至少他可以使我们命名的时候达到一定的统一,我们可以学习其优秀的方面将其纳为己用。在实际项目开发中将其巧妙而又灵活的运用起来也未尝不是一件坏事。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
首先先介绍一下作用域等一些基础概念。
每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
[[scope]] : 指的就是我们所说的作用域,其中存储了执行期上下文的集合
作用域链 : [[scope]] 中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链接叫做作用域链。
运行期上下文 : 当函数执行时,会创建一个称为执行期上下文的内部对象(AO)。一个执行期上下文定义了一个函数执行的环境,函数每次执行时对应的执行环境都是的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
查找变量 :从作用域链的顶端依次向下查找。
下面举一些例子:
之前学过函数的定义、函数表达式,还有一种函数叫做立即执行函数。
立即执行函数:函数执行过后立即被销毁。
立即执行函数的官方写法:
针对初始化功能的函数,可以有参数。
只有表达式才能被执行符号执行,能被执行符号执行的表达式,函数名字会被自动忽略。
下面是一道曾阿里面试题
下面是几道经典的例题,可以参考一下:
那么采用立即执行函数呢?会有怎样的结果呢?
闭包的现象:当内部函数保存到外部时会产生闭包。
闭包会导致原有的作用域链不释放,造成内存泄漏
(内存泄漏:内存占用(比如:手握沙子,握得越紧手里剩得就越少))
闭包触发的情况:
两个或多个函数互相嵌套,把里面的函数保存到外部,这样的情况一定会产生闭包。从外面还可以调用里面的函数。
闭包的作用:
实现公有变量
eg:函数累加器
可以做缓存(存储结构)
eg:eater
可以实现封装,属性私有化
eg:person()
模块化开发,防止污染全局变量
附加一个逗号操作符:
先看前面的表达式,再看后面的表达式,把后面表达式的计算结构返回
例题:
作用域
立即执行函数
大家可以自行思考一下。
闭包
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
注释内容以样式为例,如下:
上面是除了IE浏览器外所有浏览器都识别这个样式,另外CSS-TRICKS的《How To Create an IE-Only Stylesheet》一文中提供了另一种写法:
这种方法是样式表使用在低于IE10的浏览器,换句话说除了IE10以外的所有IE版本都将被支持。
也可以写成
前面我们也说过了lt和lte的区别,
上面这几种方法,使用的是低于(lt)和低于或等于(lte)的方法来判断,我们也可以使用大于
或
参考:
HTML条件注释用法诠释
1、支持所有IE浏览器
<!--[if IE]>
<link rel="stylesheet" href="all-ie-only.css" type="text/css"/>
<![endif]-->
2、支持非IE浏览器
<!--[if !IE]>
<link rel="stylesheet" href="not-ie.css" type="text/css"/>
<![endif]-->
<!--[if !IE]><!--> <link rel="stylesheet" type="text/css" href="not-ie.css" /> <!--<![endif]-->
3、仅仅支持IE10
<!--[if IE 10]>
<link rel="stylesheet" type="text/css" href="ie10.css">
<![endif]-->
4、支持IE10以下版本(IE9以及IE9以下版本)
<!--[if lt IE 10]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]-->
<!--[if lte IE 9]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]-->
lt表示小于版本号,不包括条件版本号本身;而lte是小于或等于版本号,包括了版本号自身
。
gt
和大于或等于gte
达到上面的效果:
5、高于IE9的版本(IE10以及IE10以上版本)
<!--[if gt IE 9]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]-->
<!--[if gte IE 10]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]-->
6、指定多种IE版本
<!--[if (IE 6)|(IE 7)|(IE 8)]>
<link rel="stylesheet" type="text/css" href="ie6-7-8.css">
<![endif]-->
https://www.cnblogs.com/hushufang/p/3708704.html
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
在微信登录中,如何和获取网页授权。
一、登录微信测试公众品平台,修改网页授权基本信息,输入授权回调页面域名(自己的域名)。
然后重新建立一个tp框架 编写方法如图:
在公共模块中新建function.php
在自己的手机端访问,就能获取access_token;
设计不是简单的迎合消费者的需求,而是引导他们消费,不光是美化生活,更重要的是创造一种生活方式,与其说是设计一件产品,不如说是设计了一种生活方式。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
在 JavaScript 中
如果我们有一个对象
二者的作用完全一样,知识接受 参数 的方式不太一样。
在 Javascript 中,多次
三种方法的作用
call
、apply
和 bind
是 Function 对象自带的三个方法,都是为了改变函数体内部 this
的指向。
call
、apply
和 bind
三者第一个参数都是 this
要指向的对象,也就是想指定的上下文。
call
、apply
和 bind
三者都可以利用后续参数传参。
bind
是返回对应 函数,便于稍后调用;apply
、call
则是立即调用 。
举个栗子
function fruits() {}
fruits.prototype = {
color: 'red',
say: function() { console.log('My color is ' + this.color);
}
} var apple = new fruits;
apple.say(); // 此时方法里面的this 指的是fruits // 结果: My color is red
banana= {color : 'yellow'}
,我们不想重新定义 say 方法,那么我们可以通过 call
或 apply
用 apple 的 say 方法:
var banana = { color: 'yellow' };
apple.say.call(banana); // 此时的this的指向已经同过call()方法改变了,指向的是banana,this.color就是banana.color='yellow'; // 结果是My color is yellow
apple.say.apply(banana); // 同理,此时的this的指向已经同过apply()方法改变了,指向的是banana,this.color就是banana.color ='yellow'; // 结果是My color is yellow
apple.say.apply(null); // null是window下的,此时,this 就指向了window ,但是window下并没有clolr这个属性,因此this.clolr就是window.color=undefined; // 结果是My color is undefined
call
和 apply
的区别
call
是把参数按顺序传递进去,而 apply
则是把参数放在 数组 里面。
var array1 = [12,'foo',{name:'Joe'},-2458]; var array2 = ['Doe' , 555 , 100]; Array.prototype.push.call(array1, array2); // 这里用 call 第二个参数不会把 array2 当成一个数组,而是一个元素 // 等价于 array1.push("'Doe' , 555 , 100"); // array1.length=5; Array.prototype.push.apply(array1, array2); // 这里用 apply 第二个参数是一个数组 // 等价于: array1.push('Doe' , 555 , 100); // array1.length=7;
类(伪)数组使用数组方法
var divElements = document.getElementsByTagName('div'); // 虽然 divElements 有 length 属性,但是他是一个伪数组,不能使用数组里面的方法 Array.isArray(divElements);// false var domNodes = Array.prototype.slice.call(document.getElementsByTagName('div')); // 将数组对象 Array 里的 this 指向伪数组 document.getElementsByTagName('div'), // slice() 方法可从已有的数组中返回选定的元素,不传参数是,返回整个数组 Array.isArray(domNodes);// true
验证一个对象的类型可以用
Object.prototype.toString.call(obj)
bind()
方法
bind()
方法会创建一个 新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()
方法的第一个参数 作为 this,传入 bind()
方法的 第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
注意
:bind()
方法创建的函数不会立即调用,在下面的例子中,最后 func()
才调用了函数,这是它与 call
和apply
的区别。
var bar = function(){ console.log(this.x);
} var foo = {
x:3 }
bar(); // undefined var func = bar.bind(foo); //此时this已经指向了foo,但是用bind()方法并不会立即执行,而是创建一个新函数,如果要直接调用的话 可以bar.bind(foo)() func(); // 3
bind()
是无效的。更深层次的原因, bind()
的实现,相当于使用函数在内部包了一个 call / apply
,第二次 bind()
相当于再包住第一次 bind()
,故第二次以后的 bind
是无法生效的。
var bar = function(){ console.log(this.x);
} var foo = {
x:3 } var sed = {
x:4 } var func = bar.bind(foo).bind(sed);
func(); //3 var fiv = {
x:5 } var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //3
蓝蓝设计的小编 http://www.lanlanwork.com