箭头函数(=>)具备隐式返回的特性。若是某个函数体只有单个表达式,你就能够忽略return关键字:()=>foo是一个不须要参数,并且最后会返回字符串foo
的函数。
并且须要注意的是,当你想要返回一个对象字面量的时候,若是你使用了大括号,javascript会默认你想要建立一个函数体。像是{ broken:true}。若是你想要经过隐式返回来返回一个字面量对象,那你就须要在你的字面量对象外面包裹一层小括号来消除这种歧义。javascript
const noop = () => { foo: 'bar'}l console.log(noop());// undefined const createFoo = () => ({foo: 'bar'}); console.log(createFoo());// { foo: "bar"}
在第一个例子中,foo会被理解成一个标签,而bar会被理解成一个没有被赋值的表达式,这个函数会返回undefined.
而在createFoo()的例子中,圆括号强制让大括号里的内容被解释成为一个须要被计算的表达式,而不是一个函数体。java
先看一个函数的声明。es6
const createUser = ({ userName, avatar}) => {}
在这一行中,大括号({})表明了对象的解构。这个函数接受一个参数(一个对象)。可是从这个单一对象中又解构出了两个形参,userName和avatar。这些参数均可以被看成函数体做用域内的变量使用。你一样也能够解构一些数组:chrome
const swap = ([first, second]) => [second, first]; console.log( swap([1,2]) ); // [2,1]
你也可使用拓展运算符(...varName)来获取数组(或者参数列表)中的其余值,而后将这些数组元素回传成单个元素:express
const rotate = ([first, ...rest]) => [...rest, first]; console.log( rotate([1,2,3])); // [2,3,1]
先看一个示例json
const arrToObj = ([key, value]) => ({ [key]: value }); console.log( arrToObj([ 'foo', 'bar' ]) ); // { "foo": "bar" }
在这个例子里,arrToObj将一个包含键值对(也叫元组)的数组转换成了一个对象。由于咱们不知道键的名称,因此咱们须要经过计算属性名来在对象中设置键值对。
这里须要知道js中访问对象属性的二者方式js对象属性中.号和中括号的区别。咱们能够经过[]中括号去动态的设置对象属性属性名。数组
js中访问对象属性有二者方式,一个是经过点号,一个是中括号。
一、中括号的运算符能够用字符串变量的内容做为属性名。点运算符不能。好比obj['string'+variable];即前者属性名能够是动态的。然后者须要是静态的
二、中括号运算符能够用纯数字做为属性名。点运算符不能。
三、中括号运算符能够用js的关键字和保留字做为属性名。点运算符不能。浏览器
//example function aa(key,value){ console.log({[key]:value}) } console.log(aa("asd","123"));// {"asd","123"}
一、将json对象转化为json字符串,再判断该字符串是否为"{}"app
var data = {}; var b = (JSON.stringify(data) === "{}") console.log(b) //true
二、for in 循环判断函数
var obj = {}; var b = function(){ for( var key in obj) { return false; } return true; } console.log(b);// true
三、Object.getOwnPropertyNames()方法
此方法是使用Object对象的getOwnPropertyNames方法,获取到对象中的属性名,存到一个数组中,经过判断数组的length来判断对象是否为空。
var data = {}; var arr = Object.getOwnPropertyNames(data); alert(arr.length == 0);//true
四、使用ES6的Object.keys()方法
var data = {}; var arr = Object.keys(data); console.log(arr.length === 0);//true
isNaN() 函数用来肯定一个值是否为NaN。
当算术运算返回一个未定义的或没法表示的值时,NaN就产生了。可是,NaN并不必定用于表示某些值超出表示范围的状况。将某些不能强制转换为数值的非数值转换为数值的时候,也会获得NaN。
能够经过isNaN去判断一个值是否为数字
if(isNaN(str)){ console.log("不是数字") }else{ console.log("是数字") } // isNaN的polyfill var isNaN = function(value){ var n = parseInt(value) return n !== n }
扩展:es6扩展了一个Number.isNaN的方法,传递的值是否为 NaN和其类型是 Number。它是原始的全局isNaN()的更强大的版本。
isNaN的扩展。和全局函数 isNaN()相比,该方法不会强制将参数转换成数字,只有在参数是真正的数字类型,且值为 NaN 的时候才会返回 true。
Number.isNaN(NaN); // true Number.isNaN(Number.NaN); // true Number.isNaN(0 / 0) // true // 下面这几个若是使用全局的 isNaN() 时,会返回 true。 Number.isNaN("NaN"); // false,字符串 "NaN" 不会被隐式转换成数字 NaN。 Number.isNaN(undefined); // false Number.isNaN({}); // false Number.isNaN("blabla"); // false // 下面的都返回 false Number.isNaN(true); Number.isNaN(null); Number.isNaN(37); Number.isNaN("37"); Number.isNaN("37.37"); Number.isNaN(""); Number.isNaN(" "); // polyfill Number.isNaN = Number.isNaN || function(value) { return typeof value === "number" && isNaN(value); }
localeCompare()方法返回一个数字来指示一个参考字符串是否在排序顺序前面或以后或与给定字符串相同。
返回一个数字表示是否 引用字符串 在排序中位于 比较字符串 的前面,后面,或者两者相同。
//能够用该方法结合sort方法对字符串数组进行排序: var str="abbbbAAbcBCCccdaACBDDabcccddddaab"; str.join().sort(function(a,b){return a.localeCompare(b)})
Object.freeze()方法能够冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改已有的属性的值,不能删除已有属性,以及不能修改对象已有的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
//examples const object1 = { property1:42 }; const object2 = Object.freeze(object1); object2.property1 = 33; // Throws an error in strict mode console.log(object2.property1); // expected output:42
注意:
一、被冻结的对象自身的全部属性都不可能以任何方式被修改(浅冻结状况下,若是被冻结的对象含有对象属性,则该对象属性不会被冻结)。任何修改尝试都会失败,通常会静默或者抛出TypeError异常
二、数据属性的值不可更改,访问器属性(有getter和setter)也一样。若是一个属性的值是个对象,在这个对象中的属性是能够修改的,除非它也是个冻结对象。
三、这个方法返回传递的对象,而不是建立一个被冻结的副本。因此不须要将返回的结果从新赋给一个新的对象,由于指向的都是同一个对象。
defineProperty方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有的属性,并返回这个对象。
Object.defineProperty(obj, prop, descriptor)
obj 要在其上定义属性的对象。
prop 要定义或修改的属性的名称。
descriptor 将被定义或修改的属性描述符。
返回:被传递给函数的对象。
reduce(callback[, initialValue])方法对累加器和数组中的每一个元素(从左到右)应用一个函数,将其减小为单个值。
const array1 = [1,2,3,4]; const reducer = (accumulator, currentValue) => accumulator + currentValue; // 1 + 2 + 3 + 4 console.log(array1.reduce(reducer)); // expected output:10 // 5 + 1 + 2 + 3 + 4 console.log(array1.reduce(reducer, 5)); // expected output:15
参数:
callback:执行数组中每一个值的函数,包含四个参数:
一、accumulator
累加器累加回调的返回值;它是上一次调用回调时返回的累积值,或initialValue
二、currentValue
数组中正则处理的元素
三、currentIndex(可选)
数组中正在处理的当前元素的索引。若是提供了initialValue,则索引号为0,不然索引为1。
四、array(可选)
调用reduce的数组
initialValue(可选)
用做第一个调用callback的第一个参数的值。若是没有提供初始值,则将使用数组中的第一个元素。在没有初始值的空数组上调用reduce将报错。
返回值:
函数累计处理的结果。
concat()方法用于合并两个或多个数组,此方法不会更改现有数组,而是返回一个新数组。
with语句 扩展一个语句的做用域链。
with (expression) { statement }
expression 将给定的表达式添加到在评估语句时做用的做用域链上。表达式周围的括号是必需的。
statement
任何语句。要执行多个语句,请使用一个块语句对这些语句进行分组
描述:javascript 查找某个未使用变量时,会经过做用域链来查找,做用域链是跟执行代码的context或者包含这个变量的函数有关。'with'语句将某个对象添加的做用域链的顶部,若是在statement中又某个未使用命名空间的变量,跟做用域链中的某个属性同名,则这个变量将指向这个属性值。若是没有同名的属性,则将抛出RefrenceError异常
另外:with 在严格模式下被禁用,替代方式是声明一个临时变量来承载你所须要的属性。
简单来讲,with 能够减小变量的长度。好比this。使用with不须要在一个函数块中大量的使用this+"."的方式去访问对象属性,能够直接使用属性名就能够访问到属性的值。
Object.assign()方法用于将全部可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
描述:若是目标对象中的属性具备相同的键,则属性将被源中的属性覆盖。后来的源的属性将相似地覆盖早先的属性。
apply(thisArg, [argsArray]) 方法调用一个函数,其具备一个指定的this值,以及做为一个数组提供的参数。
注意:call()方法的做用和apply()方法相似,只有一个区别,就是call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。
参数:
thisArg。可选参数
在func函数运行时使用的this值。须要注意的是,使用的this值不必定是该函数执行时真正的this值,若是这个函数处于非严格模式下,则制定为null或undefined时会自动替换为指向全局对象(浏览器中就是window对象),同时值为原始值(数字、字符串、布尔值)的this会指向该原始值的包装对象。
argsArray 可选参数
一个数组或者类数组对象,其中的数组元素做为单独的参数传给func函数。若是该参数的值为null或undefined。
返回值:
调用有指定this值和参数的函数的结果。
示例:使用apply来连接构造器(函数的constructor属性指向函数自己)
// examples Function.prototype.construct = function (aArgs) { var oNew = Object.create(this.prototype);// 定义一个对象,该对象的原型指向函数的原型属性(prototype) this.apply(oNew,aArgs); //使用该对象继承函数的对象属性,这样就能够实现constructor指向函数自己 return oNew; } function MyConstructor () { for (var nProp = 0; nProp < arguments.length; nProp++) { this["property" + nProp] = arguments[nProp]; } } var myArray = [4, "Hello world!", false]; var myInstance = MyConstructor.construct(myArray); console.log(myInstance.property1); // logs "Hello world!" console.log(myInstance instanceof MyConstructor); // logs "true" console.log(myInstance.constructor); // logs "MyConstructor"
target.addEventListener(type, listener, options);
参数:
capture:Boolean,表示listener会在该类型的事件捕获阶段传播到该EventTarget时触发
once:Boolean,表示listener在添加以后最多只调用一次。若是是true,listenter会在其被调用以后自动移除。
passive:Boolean。表示listener永远不会调用preventDefault().若是 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。关于该属性具体介绍,可移步下个关于passive属性的介绍。
mozSystemGroup: 只能在 XBL 或者是 Firefox' chrome 使用,这是个 Boolean,表示 listener 被添加到 system group。
Boolean,是指在DOM树中,注册了该listener的元素,是否会先于它下方的任何事件目标,接收到该事件。沿着DOM树向上冒泡的事件不会触发被指定为usecapture的listener。当一个元素嵌套了另外一个元素,两个元素都对同一个事件注册一个处理函数是,所发生的事件冒泡和事件捕获是两种不一样的事件传播方式。事件传播模式决定了元素以那个顺序接收事件。
注意:那些不支持参数options的浏览器,会把第三个参数默认为useCapture,即设置useCapture为true
document.addEventListener("touchstart", function(e){ ... // 浏览器不知道这里会不会有 e.preventDefault() },passive:true)
因为浏览器不知道当咱们在移动端监听touch事件,如touchstart时。是否有作 e.preventDefault,即阻止默认行为。因此浏览器必需要执行完整个监听函数才知道是否有阻止默认行为的代码(好比页面滚动),从而让页面进行滚动。这无疑会对浏览器的滚动性能形成卡顿。
而passive属性,就是为了告诉浏览器,个人监听事件里面没有调用e.preventDefault,这样浏览器就能够不用管监听事件里面的内容,而直接滚动。固然若是监听器里面依然调用了e.preventDefault,那么客户端也会忽略他,而且抛出一个警告。
对于浏览器是否支持passive属性检测实例。
var passiveSupported = false; try { var options = Object.defineProperty({},'passive',{ get: function() { passiveSubpported = true; } }) window.addEventLisener("test",null,options); } catch(err){}
这段代码为passive属性建立一个带有getter函数的options对象;getter设定了一个标识,passiveSupported,被调用后就会把其设为true。那意味着若是浏览器检查options对象上的passive指时,passiveSupported就会被设置为true;不然它将保持false.而后咱们调用addEventListener()去设置一个指定这些选项的空事件处理器,这样若是浏览器将第三个参数认定为对象的话,这些选项指就会被检查。
而后,当你想实际建立一个是否支持options的事件侦听器时,你能够这样作:
someElement.addEventListener("mouseup",handleMouseUp,passiveSupported ? {passive:true} : false)
一、target:触发事件的某个对象,通常出现的事件流的目标阶段。
二、currentTarget:绑定事件的对象,可能会出如今事件流的任意一个阶段中。
三、一般状况下target和currentTarget是一致的。咱们只要使用target便可,但有一种状况下,必需要区分这两者之间的关系,那就是在父子嵌套的关系中,父元素绑定了事件,点击子元素(根据事件流,在不阻止事件流的前提下他会传递至父元素,致使父元素的事件处理函数执行)。这种状况下,currentTarget指向的是父元素,由于他是绑定事件的对象,而target指向了子元素,由于他是触发事件的那个具体对象。
示例:
<div id="one"> <div id="three"></div> </div> one.addEventlistener('click',function(e){ console.log(e.target); //three console.log(e.currentTarget) })
一、事件捕获:事件从window顶层向事件触发的元素传播的过程。
二、事件冒泡:事件从触发事件的元素向window顶层传播的过程。
三、ie最开始提出的事件冒泡,而w3c提出的是事件捕获,因此如今才会有这两种事件的传播方式。
四、现代浏览器的通常解析这两种事件流的顺序:事件捕获--》目标阶段-》事件冒泡。
经过一个示例看下两个不一样的事件流的顺序关系。
<div id="one"> <div id="two"> <div id="three"></div> </div> </div> one.addEventLister('click',function(e){ console.log('one'); },false) two.addEventLister('click',function(e) { console.log('two'); },false) three.addEventListener('click',function(e){ console.log('three'); },true); //three //two //one one.addEventLister('click',function(e){ console.log('one'); },true) two.addEventLister('click',function(e) { console.log('two'); },true) three.addEventListener('click',function(e){ console.log('three'); },true); //当三个均为捕获时。结果正好相反 //one //two //three //一个是自上而下触发事件,一个是自下而上触发事件。因此致使了两种绑定方式结果的不一样
addEventListener方法能够容许传第二个位置一个参数,告诉浏览器这里你添加的事件是在事件捕获阶段执行,仍是在事件冒泡阶段执行。默认参数为false,为冒泡。为true,为捕获