JS中的对象(Object)是一个基本数据类型,是一种复合值,它将不少值(原始值或者其余对象)聚合在一块儿,可经过名字访问这些值(属性)的无序集合。每一个对象都有一个原型,原型能够为空。git
Object每一个属性既能够是一个命名的数据属性,也能够是一个命名的访问器属性,或者是一个内部属性:github
上面两个列表中属性的默认值为(以下表3)函数
每个对象数据属性都具备表1的特性,每个对象里面的方法属性都具备表3里面的特性,这些特性能够经过ECMAScript内置对象Object构造器方法Object.defineProperty来修改。如a.x属性的Enumerable被修改成false时,对象在for-in循环里将迭代不出该属性。其余的属性这里不详细讲解ui
全部的Object对象都必须具备下表的属性(表4)this
[[prototype]]用于实现继承,[[Class]]用于区分对象的种类,也就是对象的名字。如String对象的[[Class]]值为"String"。建立对象时,对象的内部属性的[[Classs]]是除了"Arguments","Date","Array"....等内部对象名以外的值。因此咱们在定义对象的时候不能重名和用内置对象的名字。es5
ECMAScript不一样的对象的行为不一样,对应实现上表这些属性的方式也是略有不一样。可是必须都具有上述属性。不一样的内置对象具备不一样的属性,下表是只有在某些对象里面才具备属性(表5)spa
相对于Object内置对象Number,Date对象多实现[[primitiveValue]],Function对象多实现[[Code]]等属性,而经过Function.prototype.bind方法建立的Function对象还多实现[[TargetFunction]]方法,RegExp对象比Object多实现了[[Match]]属性等。而若是是可用于构造的对象则必须实现[[construct]]属性。prototype
一、对象字面量建立3d
var obj = {
name: 'lyq',
age: 18
}
console.log(obj.name) //lyq复制代码
直接复制操做。不详细讲解,由于涉及到JS中的“=、{}”操做符的运行过程,详细讲解的话又是一个话题。code
var obj = new Object();
obj.name = 'lyq';
console.log(obj.name); //lyq复制代码
function Obj (name) {
this.name = name;
this.age = 18;
}
var obj = new Obj('lyq');
console.log(obj.name); //lyq
console.log(obj.age); //18复制代码
- 若是提供了value则
- 若是Type(value)是Object,则
- value是原声ECMAScript对象(Array,Date这些),不建立新对象,简单返回value
- 若是value是宿主对象,则采起动做和放回依赖实现的结果的方式可使依赖于宿主对象(不纠结字面意思,简单的说就是返回宿主对象)
- 若是Type(value)是String类型,返回ToObject(value).
- 若是Type(value)是Boolean类型,返回ToObject(value).
- 若是Type(value)是Number类型,返回ToObject(value).
- 未提供参数value或者类型是Null或者Undefined
- 令obj为一个新建立的原声ECMAScript对象
- 设定obj的[[prototype]]内部属性为标准内置的Object的prototype。
- 设定obj的[[Class]]内部属性为"Object“
- 设定obj的[[Extensible]]内部属性为true
- 设定obj的表1指定的全部内部方法
- 返回obj。
根据表5建立Function对象,必须实现多些属性,其中包括Function对象需拥有 FormalParameterList 为可选参数列表,FunctionBody 为函数体,词法环境 Scope ,严格模式标记Strict。经过Function构造器建立Function对象的步骤以下:
- 令argCount为传给这个函数调用的参数总数
- 令P为空字符串
- 若是argCount=0,令body为空字符串
- 不然若是argCount=1,令body为那个参数
- 不然argCount>1
- 令firstArg为第一个参数
- 令P为ToString(firstArg)
- 令k为2
- 只要k<argCount就重复
- 令nextArg为第k个参数
- 令P为以前的P值。字符串“,”(逗号),ToString(nextArg)串联结构
- k递增
- 令body为第k个参数
- 令body为ToString(body)
- 若是P不可解析为一个FormalParameterListopt,则抛出一个SyntaxError异常
- 若是body不可解析为FunctionBody,则抛出一个SyntaxError异常
- 建立一个新的 ECMAScript 原生对象,令 F 为此对象。
- 依照 表1 描述设定 F 的除 [[Get]] 之外的全部内部方法
- 设定 F 的 [[Class]] 内部属性为 "Function"。
- 设定 F 的 [[Prototype]] 内部属性为指定的标准内置 Function 对象的 prototype 属性。
- 设定 F 的 [[Get]] 内部属性。
- 设定 F 的 [[Call]] 内部属性。
- 设定 F 的 [[Construct]] 内部属性。
- 设定 F 的 [[HasInstance]] 内部属性。
- 设定 F 的 [[Scope]] 全局环境。
- 设定 F 的 [[FormalParameters]] 内部属性为 P。
- 设定 F 的 [[Code]] 内部属性为 body 解析后的 FunctionBody。
- 设定 F 的 [[Extensible]] 内部属性为 true。
- 令 argCount为 FormalParameterList 指定的形式参数的个数。
- 以参数 "length",属性描述符 {[[Value]]: len, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false},false 调用 F 的 [[DefineOwnProperty]] 内部方法。
- 令 proto 为仿佛使用 new Object() 表达式建立新对象的结果,其中 Object 是标准内置构造器名。
- 以参数 "constructor", 属性描述符 {[[Value]]: F, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}, false 调用 proto 的 [[DefineOwnProperty]] 内部方法。
- 以参数 "prototype", 属性描述符 {[[Value]]: proto, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}, false 调用 F 的 [[DefineOwnProperty]] 内部方法。
- 若是body是严格模式代码。则令strict为true,不然令strict为false
- 若是strict是true,按照严格模式下的代码解析判断是否抛出异常
- 返回 F。
上述建立内部方法的步骤都没有详细标出,可是不碍理解对象的建立过程。对象建立中的内存分配是由构造函数的内部方法[[Construct]]负责的。该内部方法的行为是ECMAScript定义好的,全部的构造函数都是使用该方法来为新对象分配内存的。而若是被new的对象没有实现[[contruct]]这个属性将会抛出异常。接下来补充上面Function对象的建立过程当中省略的建立[[construct]]属性的过程。
当以一个可能的空的参数列表调用函数对象 F 的 [[Construct]] 内部方法,采用如下步骤:
- 令 obj 为新建立的 ECMAScript 原生对象。
- 依照 8.12 设定 obj 的全部内部方法。
- 设定 obj 的 [[Class]] 内部方法为 "Object"。
- 设定 obj 的 [[Extensible]] 内部方法为 true。
- 令 proto 为以参数 "prototype" 调用 F 的 [[Get]] 内部属性的值。
- 若是 Type(proto) 是 Object,设定 obj 的 [[Prototype]] 内部属性为 proto。
- 若是 Type(proto) 不是 Object,设定 obj 的 [[Prototype]] 内部属性为 标准的内置对象
- 以 obj 为 this 值,调用 [[Construct]] 的参数列表为 args,调用 F 的 [[Call]] 内部属性,令 result 为调用结果。
- 若是 Type(result) 是 Object,则返回 result。
- 返回 obj
回到前面实例2,Obj 是一个Function对象,实现了[[contruct]]属性,能够经过 new Obj()来建立一个新的对象。而此时new Obj() 的过程就能new Object()原理同样。
var obj = {};
console.log(obj.name); //undefined
obj.name = 'lyq';
console.log(obj.name); // lyq复制代码
var obj = {
name : 'lyl'
};
console.log(obj.name); //lyl
delete obj.name;
console.log(obj.name); //undefined复制代码
var obj = {
name: 'lyq'
};
// 第一种方法
console.log(obj['name']); //lyq
// 第二种方法
console.log(obj.name); // lyq
console.log(obj.age); // undefined复制代码
var obj = {
name: 'lyq'
};
console.log(obj.name); // lyq
obj.name = 'lee';
console.log(obj.name); // lee复制代码
var person = function Person(){};
Person.prototype.x = 1;
var person = new Person();复制代码
根据上述建立对象的过程,当我经过new建立一个实例对象的时候,会先判断构造函数的prototype是否存在,同时是一个对象,若是是则将这个prototype对象赋值给新建立的对象的prototype。若是不存在和不是一个对象,则赋给新建立出来的对象一个标准内置的prototype。上述Person.prototype就是实例对象的原型。(经过上述函数对象的建立过程当中可以看出,每一个函数都会自动建立一个prototype对象,默认为标准的内置对象,用于知足函数会被当作构造函数的可能性。)
构造函数建立出来的实例对象共有一个prototype对象,而不是每一个实例都复制一份prototype出来,每一个实例对象都有一个指向原型的对象为proto
构造函数的prototype里面有一个指向构造函数自己的属性为constructor,标识每一个实例是经过哪一个构造函数建立出来的,如:
Person === person.__proto__.constructor //true;复制代码
prototype也是一个对象,也具备prototype属性,上例中Person.prototype的prototype属性是Object对象的内置prototype属性。而Object对象的内置prototype的prototype为null。对象的原型图以下
当要获取person对象的属性时,就会照图中蓝色的链来查找属性,这条蓝色的链便可理解为原型链(这逼其实就是js中的原型链)。
js在查找值的时候就是经过表1中的[[get]]方法来获取的,设置值是经过[[put]]方法来设置。这里不深刻讲解这两个方法,有兴趣能够继续深刻了解。ECMAScript中[[get]]会照着原型链获取属性,而[[put]]是直接将属性设置在person对象上,因此即便对象原型上存在的属性,在设置的时候若是对象自己不存在该属性,则直接建立新属性,而不会影响原型,以下图
因此当对对象进行增删改操做时不会影响到对象的原型和构造函数,当对对象进行查操做时,若是在自身获取不到,则会继续在原型链上查找,直到获取到该对象或到根原型为null为止
- Object.prototype —— 对象原型
- Object.getPrototypeOf(o) —— 返回o的内部属性值
- Object.getOwnPropertyDescriptor ( O, P ) —— 返回对象O上面P属性的描述符
- Object.create ( O [, Properties] ) —— 建立一个拥有指定原型和若干属性的对象
- Object.defineProperty ( O, P, Attributes ) —— 在对象上添加或者修改一个属性,并返回这个对象,其中obj为要修改的对象,p为要修改或者添加的属性,Attributes将被定义或者修改的属性的描述符
- Object.defineProperties ( O, Properties ) —— 添加或者修改多个属性,操做多个属性不能更改描述符
- Object.seal ( O ) —— 密封对象
- Object.freeze ( O ) —— 冻结对象中的某个属性,使该属性没法进行增删改查
- Object.preventExtensions ( O ) ——禁止对象不能扩展,这样对象就永远不能添加更改属性
- Object.isSealed ( O ) —— 判断一个对象是否被密封
- Object.isFrozen ( O ) —— 判断一个对象是否被冻结
- Object.isExtensible ( O ) —— 判断对象是否能够扩展
- Object.prototype.constructor —— 标准内置的Object构造器
- Object.prototype.toString ( ) —— 返回对象的字符串表示
- Object.prototype.toLocaleString ( ) —— 返回对象的本地字符串表示
- Object.prototype.valueOf ( ) —— 返回指定对象的原始值
- Object.prototype.hasOwnProperty (V) —— 返回一个布尔值,表示对象是否包含有V这个属性,该属性为对象自己属性,不包括原型链上的属性
- Object.prototype.isPrototypeOf (V) —— 返回一个布尔值,表示对象是否包含V这个属性,包含自身和原型链上的
- Object.prototype.propertyIsEnumerable (V) —— 返回一个布尔值,表示V属性是否能够枚举