一、对象
- var obj = {};
- obj[true] = "foo";
- obj[3] = "bar";
- obj[obj] = "baz";
- obj["true"];
- obj["3"];
- obj["[object Object]"];
二、数组也是对象
- var ary = ["foo", 42, "bar"];
- ary.baz = "baz";
- ary.length; //3
- ary.baz;
- /* 如果试图想数组添加一个属性,但是属性名“看起来”像一个数字,那么它会变成一个数值下标 */
- ary["4"] = "baz";
- ary.length; //5
- ary[4];
三、对象属性
writable:可写(修改)enumerable:可枚举(for ... in)
configurable:可配置(配置、删除)
注意:delete只能删除对象(可删除)属性,即configurable为true的属性。
- var obj = {};
- Object.defineProperty(obj, "a", {enumerable:true, value:2});
- Object.defineProperty(obj, "b", {enumerable:false, value:3});
- /* 检查给定属性名是否直接存在于对象中(而不是在原型链上)并满足enumerable:true */
- obj.propertyIsEnumerable("a"); //true
- obj.propertyIsEnumerable("b"); //false
- /* 返回一个数组,包含所有(自身)可枚举属性 */
- Object.keys(obj); //["a"]
- /* 返回一个数组,包含所有(自身)属性 */
- Object.getOwnPropertyNames(obj); //["a", "b"]
四、对象原型
获取对象原型:Object.getPropertyOf(..)- function Foo(){}
- var foo = new Foo();
- Foo.prototype === Object.getPrototypeOf(foo); //true
类理论: 在构造完成后,通常只需要操作这些实例(而不是类),因为每个实例都有你需要完成任务的所有行为。
五、原型链[[prototype]]
[[prototype]]机制就是存在于对象中的一个内部链接,它会引用其他对象。- var foo = {
- something:function(){
- // ....
- }
- };
- var bar = Object.create(foo); // 创建新对象bar,并将其关联到对象foo上。
对象之间的关系不是复制而是委托!!!
谈及原型链不得不提及我们经常在JavaScript中的类型检查!即内省:检查实例的类型;主要目的是通过创建方式来判断对象的结构和功能。
方式一:a instanceof Foo
方式二: “鸭子类型” :如果看起来像鸭子,叫起来像鸭子,那就一定是鸭子。
- if(a.something) {
- a.something(); // something()并不一定在a自身上
- }
建议使用方式三!!!
六、函数
JavaScript中的函数无法(用标准、可靠的方法)真正地复制,所以只能共享函数对象的引用。这意味着,如果修改共享函数,比如增加一个属性,所有引用地方都会随之修改!七、构造函数
- function Foo(){}
- Foo.prototype = {};
- var a1 = new Foo();
- a1.constructor === Foo; //false
- a1.constructor === Object; //true
创建一个新对象并替换了函数默认的.prototype对象引用,那么新对象并不会自动获得.constructor属性。
a1并没有.constructor属性,所以它会委托[[Prototype]]链上的Foo.prototype。但是这个对象也没有.constructor属性,所以它会继续委托给链顶端的Object.protoype。
实际上,对象的.constructor会默认指向一个函数,这个函数可以通过对象的.prototype引用!
总之,constructor并不表示被构造!!!改变prototype并不能彻底改变继承关系!!!
- function Foo(name){
- this.name = "FenFei"
- }
- function Bar(){}
错误理解一:
- Bar.prototype = Foo.prototype;
- Bar.prototype.myTest = 123;
- new Foo().myTest; //123
错误理解二:
- Bar.prototype = new Foo();
- new Bar("Camile").name; //FenFei
正确处理方式一[ES6之前]:
- Bar.prototype = Object.create(Foo.prototype);
- Bar.prototype.myTest = 123;
- new Foo().myTest; //undefined
- new Bar("Camile").name; //undefined
正确处理方式二[ES6之后]:
- Object.setPrototypeOf(Bar.prototype, Foo.prototype);
- Bar.prototype.myTest = 123;
- new Foo().myTest; //undefined
- new Bar("Camile").name; //undefined
八、函数关系
(1)在a的整条[[prototype]]链中是否有指向Foo.prototype的对象?- a instanceof Foo;
- Foo.prototype.isPrototypeOf(a); // 不需要间接引用函数Foo,它的prototype属性会自动访问。
isPrototypeOf()方法可以判断对象间的关系。
b是否出现在c的[[prototype]]链中?
- b.isPrototypeOf(c);
- function Foo(){}
- var a = new Foo();
- console.log(a instanceof Foo); // true
- console.log(Foo.prototype.isPrototypeOf(a)); // true
- var b = {};
- var c = Object.create(b);
- console.log(b.isPrototypeOf(c)); // true
- console.log(b instanceof c); // TypeError
在传统面向类的语言中,类定义之后就不会进行修改,所以类的设计模式不支持修改。但是JavaScript最强大的特性之一就是它的动态性,任何对象的定义都可以修改(除非你把它设置成不可变)!