You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
a('sdf');// a is not definedif(true){functiona(){console.log('a');}a('sdf');// successful;}a('sdf');// a is not defined
神奇的是,函数只在块级作用域内部发生提升
typeofa;// a is not defined// a('sdf'); // a is not definedif(true){a('sdf');// afunctiona(){console.log('a');}a('sdf');// atypeofa;// a is not defined}// a('sdf'); // a is not definedtypeofa;// a is not defined
第一章 块级作用域绑定
var 会有一个作用域提升的问题
等同于
等同于
变量a被提升到顶部,因为这种bug,let,const等块级作用域诞生了。
let/const 的声明周期和var不一样。
块级声明
块级作用域(同时被称为词法作用域)存在于
{}
和[]
var的变量提升,原本是为了方便防止报错,结果到现在反而成了一种bug😭。
let禁止重复声明,而var不存在这种xian'z限制。
const
他必须经过初始化才行
临时死区(Temporal Dead Zone)
非常有意思
对比
因此,a的值如果处于ley的块级作用域,并且在打印后才赋值,那么是引用错误,但是如果放到块级作用域外面,它是默认从window下面拿值的,因此let之前的块级作用域称之为 Temporal Dead Zone.换句话说,块级作用域内。
第二章 模板字符串
众所周知,``代表es6的模板字符串,默认支持换行,但据说,他真正厉害的是模板标签
第三章 函数
函数参数默认值
由于a默认值等于b,而b命名在a之后,
函数参数中的默认参数的 Temporal Dead Zone
非常有趣的函数默认参数命名
上面例子,函数参数命名过程
一切正如第一章所说,当a引用b的时候,b在临死区,所有的绑定行为都会报错。
所有函数参数都有自己的作用域和临死区,与其他函数体的作用域各自独立,,也就是说,函数体内部参数默认值同样不能访问函数内部声明的变量。
函数的name,
同样非常有意思,函数默认有一条属性,那就是name
打印函数,输出的是函数体,但(函数).name输出的确实他的函数名,或者函数声明。这同样涉及到函数背后所做的事情。
构造函数
一般来说,new让函数内部this指向新的对象,并且返回这个新的对象。
js函数有两个不同的内部方法,[[Call]]和[[Constructor]],这两个方法很有意思,当new关键字被调用的时候,执行的是[[Construct]]函数,,他会创作一个通常被称为实例的新对象,然后执行函数体,将this绑定到实例上,如果不通过new关键字调用的话,,就会执行[[Call]],从而直接执行代码中的函数体,,而具有[[Constructor]]方法的函数,被统称为构造函数,
切记,不是所有函数都有[[Construct]]方法,因此不是所有的函数都可以通过new来调用,例如后面本章所说的箭头函数就没有[[Construct]]方法,
如何判断 是否被当作构造函数来调用,
看上面例子,首先this会被指向新的对象,如果新的对象被指向的新对象,他的原型中又Person,那么说明你有通过构造函数构造拥有Person原型的对象;如果this的 原型是Person,即this是Person的实例,那么继续执行,如果不是,就抛出错误。由于[[Construct]]方法会创建一个Person的实例 ,并将this绑定到新的实例上面,通常,通过call也可以实现绑定。
上面这种方法同样将this绑定到Person上面。Person.call()时将变量person作为第一个参数传入,相当于在Person函数里面将this设为了person实例。对于函数本身,无法通过区分是否是通过new调用的还是通过Person.call()来调用的。
通过 鉴别new.target可以判断是否是通过new来调用的
块级作用域 中的函数
所有的函数都会发生提升,但是问题来了,一旦if语句不执行这部分呢??
神奇的是,函数只在块级作用域内部发生提升
但是在非严格模式下,块级函数会被提升到外围函数顶部。
箭头函数 (重点)
在ECMAScript6中,箭头函数是最有趣的的新特性。与传统函数的不同主要有以下
以上差异产生原因。内部this指向不明确,因而出现箭头函数。
箭头函数同样拥有name属性,
箭头函数的IIFE版本(立即执行函数)需要包一层小括号,而正常函数包不包小括号都可以执行。
箭头函数没有this绑定
箭头函数内的this绑定是JavaScript中最常出现错误的因素,函数体内的this值可以根据函数调用上下文而改变。
上面代码来看,对象PageHandler涉及初衷就是用来处理页面上面的交互,通过init来配置交互,然而实际上普通函数,this指向谁引用的它。this绑定的是目标对象的引用,上面代码中init被调用的引用是document,自然无法执行下去,想要通过bind绑定this的值,是不可能的,箭头函数this指向其外部非箭头函数。
通常在过去,通过bind方法可以显示绑定到对象中,修正这个问题。
但是仔细一看,上面的做法很奇怪,为什么呢?
(function(){}).bind(this)
创建了一个新的函数。他的this指向当前对象。为了避免创建额外的函数,下面使用箭头函数。这个时候,this已经成功指向PageHandling本身了,再改一下,外部函数改成箭头函数
是不是很神奇,箭头函数永远指向其外部最近的普通的function的this。如果外部没有普通function,那么this指向window,或者undefined。箭头函数缺少基本的prototype,也就是说箭头函数没有原型链,箭头函数的原则就是即用即弃。,
箭头函数不能使用new来构造,因为他没有[[Construct]]方法,同时也是因为如此,JavaScript引擎可以进一步优化其特定行为。
同时,箭头函数不能通过call(),apply(),bind(),来改变this值。
箭头函数和数组
不多解释,非常强大,
箭头函数没有arguments绑定。这样,无论写在哪,都能通过this访问父函数的arguments。
尾递归优化
同样也是灰常强大的功能, 为什么这么说呢,这可以有效防止栈溢出。
在es5引擎中,尾调用的栈同样清晰,创建一个新的栈帧(stack frame),将未完成的函数调用推入栈。但是尾递归的问题就是,当调用栈太多的时候会造成程序性能问题,
在es6引擎中,尾调用被优化,换句话说,es6引擎较少了调用栈的最大长度,如果超出长度,调用栈会先停止,转而去处理栈帧。如果满足以下三个条件,可以被js引擎自动优化调用栈。
(尼马,这一段阮一峰说的不清不楚的。)
如何优化一个函数
事实上尾递归优化发生在引擎后面,递归函数优化最明显,
然而在浏览器中打印,依然是zhan'yi'chu栈溢出。目前尚处于审查阶段。,日后再安利一波。
第四章 扩展对象的新功能
几乎每一种类型的值都是对象,随着js的发展,对象使用率越来越高,因此提升对象使用效率就变得非常重要。
es6也对对象进行了优化。通过许多方式加强对象的使用,通过简单的语法扩展,提供更多操作对象交互的方法,本章详细讲解这些改进。
对象类别
es6对对象进行了分类,以下4个类别
下面,我们将用这些属于来解释es6定义的各种对象。
对象新增方法
通过
Object.is()
,我们可以检测两个值是否全等。除了NaN 或者-0这种情况,其他情况Object.is()和===基本一样。
####Object.assign()方法
今天终于见到了Mixin这个单词,原来这就是混合,真鸡毛坑啊,中文翻译真的好坑。
混合(Mixin)是JavaScript中实现函数混合对象组合的最流行的一种方式,
上面函数会将两个对象混合在一起。因此es6出现了Object.assign这种方法。它可以改变第一个参数那个对象的属性并混入第二个对象的属性。
Object.assign可以接受任意个数的参数,并且越靠后的权重越高,同时,由于对象是指针关系,为了避免改变第一个参数,造成混乱,我们可以将第一个参数传入{},这样Object.assign()返回的新对象,将不会影响任何对象。注意,get属性不能被复制。
Object.getOwnPropertyDescriptor
非常有意思的属性,它可以获取对象的某个属性全部的值,
简化原型访问的Super引用
正如之前说的,原型对于js非常重要,es许多改进,最终是为了让他更好用,es6引入了super,使用它可以更便捷的访问对象原型。举个例子,
super则相当于对象的原型指针,上面例子即使super = Object.getPrototypeOf(this);
当然他必须在简写方式中使用,负责会抛出语法错误。
第五章 解构:使数据解构访问更加方便
没啥好说的。
第六章 Symbol 和 Symbol属性
私有属性,外界无法访问。所有的原始值,除了symbol以外,都有各自的字面形式,例如布尔值类型的ture或者类型值42,可以通过Symbol来创建全局一个Symbol,
第七章 set和map集合
map 和 set的区别
首先安利一波mdn用法如下:第二个参数是可选参数,this,
下面这个对象,forEach的this,作为第二个参数传入,输出结果 1,2
下面这个例子,箭头函数从外围的process()函数读取this,其实直接把this当作变量来看待,他就是一个默认存在不需要声明就默认存在的变量,箭头函数内部没有this,所以你在箭头函数里面拿this会直接拿到外部的this。这个解释可以啊,
set和真数组array之间互相转换
谁都知道,对象是引用类型,那么当你
new Set(arr)
的时候,set被添加arr数组,当arr=null
的时候,引用对象呗销毁,而new Set()这个值依然保留。换句话说,这是强行引用,weakSet 弱引用
什么是弱引用,就是原来引用的对象被删除了,那么weakSet对象会同步到删除操作,然并卵。。
Map 集合
Map类型是一种储存许多键值对的有序列表,其中键名和对应的值支持所有类型
Weak Map 集合
Weak Set 是若引用Set集合,相对的,Weak Map 是弱引用的Map集合,也是用于储存对象的弱引用,weakMap集合的键名必须是一个对象,如果使用非对象键名回报错,,如果在弱引用之外,不存在其他强引用,,引擎的辣鸡回收机制,会自动回收这个对象,同时移除weak Map集合种的键值对。
weak map是一种储存许多键值对的无序列表,列表的键名必须是非null的对象,键名对应的值应该是可以是任意类型,weak map 接口与map非常相似,,通过set方法设置,通过get方法得到。
第七章小结
set 集合是一种包含多个非重复性的无序列表,值与值之间的等价性是通过
Object.is()
的方法来判断,,若果相同,就过滤,5和’5‘不同,同时,set不是数组的子类,所以你不能通过随机访问集合中的值,只能通过has()方法,检测指定的值是否存在于Set集合中,或者通过size属性查看数量,weak set集合是一个特殊的set集合,只支持存放弱引用,当其对象的其他强引用被清除的时候,弱引用自然会被清除,
map是多个无序键值对组成的集合,键名支持任意数据类型,与set集合类似,map也是通过Object.is()判断是否重复,他与set的区别是可以通过迭代器循环,
weak map是弱引用,造轮子应该非常适用这种东西。
我已经深刻相信,再自学下去也搞不出个什么鬼了。还是看书吧。系统性学习真的很重要。
The text was updated successfully, but these errors were encountered: