关于this
匿名函数无法从函数内部引用自身
this既不指向函数自身也不指向函数的词法作用域。this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用
this全面解析
调用位置:调用位置就是函数在代码中被调用的位置(而不是声明的位置)。
this词法
箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。
箭头函数最常用于回调函数中,例如事件处理器或者定时器
对象
语法
对象可以通过两种形式定义:声明(文字)形式和构造形式
构造形式和文字形式生成的对象是是一样的。唯一的区别是,在文字声明中你可以添加多个键/值对,但是在构造形式中你必须逐个添加属性
存储在对象容器内部的是这些属性的民称,他们就像指针(引用),指向这些真正的存储位置。使用.
操作符(属性访问)或者[]
操作符(键访问).
操作符要求属性名满足标识符的命名规范,而[]
语法可以接受任意字符串作为属性名。
在对象中属性名永远都是字符串,会自动转换为字符串
可计算属性名
可计算属性名:可以再文字形式中使用[]
包裹一个表达式来当做属性名
属性和方法
无论返回值是什么类型,每次访问对象的属性就是属性访问。如果属性访问返回的是一个函数,那它也并不是一个方法。
数组
数组也是对象,每个下标都为整数,可以为数组添加不同的属性
注意:如皋港在数组中添加一个属性,属性名是一个数字,那它会变成一个数值下标
属性描述符
使用Object.defineProperty(...)
来添加一个新属性或者修改一个已有属性
- Writable:决定是否可以修改属性的值
- Configurable:只要属性是可配置的,就可以使用
defineProperty(...)
方法来修改属性描述符
注意:即使属性是configurable:false
,我们还是可以把writable
的状态由true
修改为false
,但是无法由false
改为true
- 不变性
- 对象常量
结合writable:false
和configurable:false
就可以创建一个真正的常量属性(不可修改、重定义或者删除)
- 禁止扩展
如果想要禁止一个对象添加新属性并且保留已有属性,可以使用Object.preventExtensions(...)
- 密封
Object.seal(...)
会创建一个”密封”的对象,这个方法实际上会在一个现有对象上调用Object.preventExtensions(...)
并把所有现有属性标记为configurable:false
密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(可以修改属性的值)
- 冻结
Object.freeze(...)
会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal(...)
并把所有”数据访问”属性标记为writable:false
,这样就无法修改它们的值。
它会禁止对于对象本身及其任意直接属性的修改
注意:这个对象引用的其他对象是不受影响的
存在性
in
操作符会检查属性是否在对象及其[[Prototype]]
原型链中in
操作符可以检查容器内是否有某个值,实际上检查的是某个属性名是否存在hasOwnProperty(...)
只会检查属性是否在对象中,不会检查[[Prototype]]
链枚举
for...in
可以用来遍历对象的可枚举性列表(包括[[Prototype]]链)forEach(...)
会遍历数组中的所有值并忽略回调函数的返回值every(...)
会一直运行知道回调函数返回false
(或者”假”值)some(...)
会一直运行直到回调函数返回true(或者”真”值)for...of
首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的next()
方法遍历所有返回值
注意:遍历数组下标时采用的是数字顺序(for循环或其他迭代器),但是遍历对象属性时的顺序是不确定的,在不同的JavaScript引擎中可能不一样
混合对象-类
构造函数
类实例是由一个特殊的类方法构造的,这个方法名通常和类名相同,被称为构造函数。这个方法的任务就是初始化实例需要的所有信息(状态)
多态
原型
所有普通的[[Prototype]]链最终都会指向内置的Object.prototype
关于名称
在JavaScript中,我们并不会将一个对象(“类”)复制到另一个对象(“实例”),只是将它们关联起来。从视觉角度来说,[[Prototype]]机制如下图所示,箭头从右到左,从下到上:
类
继承意味着复制操作,JavaScript(默认)并不会复制对象属性。相关,JavaScript会在两个对象之间创建一个关联,这样一个对象就可以通过委托访问另一个对象的属性和函数。
还有个偶尔会用到的JavaScript术语”差异继承”,基本原则就是在描述对象行为时,使用其不同于普遍描述的特质。举例来说,描述汽车时你会说汽车是有四个轮子的一种交通工具,但是你不会重复描述交通工具具备的通用特性(比如引擎)
构造函数
按照JavaScript世界的惯例,”类”名首字母要大写,所以名字协作Foo
而非foo
在一个普通函数调用前面加上new关键字之后,就会把这个函数调用变成一个”构造函数调用”。实际上,new会劫持所有普通函数并用构造对象的形式来调用它,换句话说,在JavaScript中对于”构造函数”最准确的解释是,所有带new的函数调用。函数不是构造函数,但是当且仅当使用new时,函数调用会变成”构造函数调用”
对象的.constructor
会默认指向一个函数,这个函数可以通过对象的.prototype
引用
对象关联
[[Prototype]]机制就是存在于对象中的一个内部链接,它会引用其他对象。通常来说,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就会继续在[[Prototype]]关联的对象上进行查找。同理,如果在后者也没有找到需要的引用就会继续查找它的[[Prototype]],以此类推。这一系列对象的链接被称为”原型链”
创建关联
Object.create(...)
会创建一个新对象,并把它关联到我们指定的对象(foo),这样我们就可以充分发挥[[Prototype]]机制的威力(委托),并且避免不必要的麻烦(比如使用new的构造函数调用会生成.prototype
和.constructor
引用)