建立第一类的形式
(1)Object 缺省形式 Object 缺省将取值的值包装袋为两个新第一类。
假如取值的值是 null 或 undefined, 它会建立并回到两个空第一类。不然, 它将回到两个和给定的值相相关联的类别的第一类。假如取值值是两个早已存有的第一类, 则会回到那个早已存有的值( 完全相同门牌号)let o = new Object() o.foo = 42 console.log(o)(2)第一类字面量形式
var obj1 = { foo: bar, x: 42 };(3)Object.create() 方式用作建立两个新第一类,采用原有的第一类来做为新建立第一类的蓝本(prototype)。
假如该模块被选定且不为 undefined,则该传至第一类的Chhatarpur可隐式特性(即其另一方面表述的特性,而并非其蓝本链上的隐式特性)将为新建立的第一类加进选定的特性值和相关联的特性配置文件。那些特性相关联于 Object.defineProperties() 的第三个模块。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/createconst person = { isHuman: false, printIntroduction: function() { console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`); } }; const me = Object.create(person); console.log(me) me.name =Matthew; // “name” is a property set on “me”, but not on “person” me.isHuman = true; // inherited properties can be overwritten me.printIntroduction(); // expected output: “My name is Matthew. Am I human? true”第一类的静态方式
Object.assign() 通过复制两个或多个第一类来建立两个新的第一类。
Object.create() 采用选定的蓝本第一类和特性建立两个新第一类。
Object.defineProperty() 给第一类加进两个特性并选定该特性的配置。
Object.defineProperties() 给第一类加进多个特性并分别选定它们的配置。
Object.entries() 回到取值第一类另一方面可隐式特性的 [key, value] 数组。
Object.freeze() 冻结第一类:其他代码不能删除或更改任何特性。
Object.getOwnPropertyDescriptor() 回到第一类选定的特性配置。
Object.getOwnPropertyNames() 回到两个数组,它包含了选定第一类所有的可隐式或不可隐式的特性名。
Object.getOwnPropertySymbols() 回到两个数组,它包含了选定第一类另一方面所有的符号特性。 Object.getPrototypeOf() 回到选定第一类的蓝本第一类。
Object.is() 比较两个值是否完全相同。所有 NaN 值都相等(这与==和===不同)。
Object.isExtensible() 判断第一类是否可扩展。
Object.isFrozen() 判断第一类是否早已冻结。
Object.isSealed() 判断第一类是否早已密封。
Object.keys() 回到两个包含所有取值第一类另一方面可隐式特性名称的数组。
Object.preventExtensions() 防止第一类的任何扩展。
Object.seal() 防止其他代码删除第一类的特性。
Object.setPrototypeOf() 设置第一类的蓝本(即内部 [[Prototype]] 特性)。
Object.values() 回到取值第一类另一方面可隐式值的数组。
第一类的实例实例特性
Object.prototype.constructor两个引用值,指向 Object 缺省Object.prototype.__proto__指向两个第一类,当两个 object 实例化时,采用该第一类做为实例化第一类的蓝本方式表述
第一类特性也可以是两个函数、getter、setter方式。
var o = { property: function ([parameters]) {},//or property([parameters]) {} get property() {}, set property(value) {}, };特性
第一类拥有两种特性:数据特性和访问器特性
数据特性
数据特性是键值对,并且每个数据特性拥有下列特性:
configurable :当且仅当该特性的 configurable 键值为 true 时,该特性的配置文件才能够被改变,同时该特性也能从相关联的第一类上被删除。默认值为false
Value: 包含那个特性的数据值。
Writable:假如该值为 false,则该特性的Value 特性不能被修改。
Enumerable : 假如该值为 true,则该特性可以用 for…in 循环来隐式。
letobj = {foo: 123 }; console.log(Object.getOwnPropertyDescriptor(obj, foo))访问器特性
访问器特性有两个或两个访问器函数(get 和 set)来存取数值。 自表述 Setters和getter
function Archiver() { var temperature = null; var archive = []; Object.defineProperty(this, temperature, { get: function() { console.log(get!); return temperature; }, set: function(value) { temperature = value; archive.push({val: temperature }); } }); this.getArchive = function() { return archive; }; } var arc = new Archiver(); arc.temperature; // get! arc.temperature = 11; arc.temperature =13; arc.getArchive(); // [{ val: 11 }, { val: 13 }]可隐式性
第一类的每个特性都有两个描述第一类(Descriptor),用来控制该特性的行为。Object.getOwnPropertyDescriptor
可隐式特性是指那些内部 “可隐式” 标志设置为 true的特性,对于通过直接的赋值和特性初始化的特性,该标识值默认为即为true,对于通过 Object.defineProperty 等表述的特性,该标识值默认为 false。
var o = {}; Object.defineProperty(o, “a”, { value: 1, enumerable: true }); Object.defineProperty(o, “b”, { value: 2, enumerable: false }); Object.defineProperty(o, “c”, { value: 3 }); // enumerable 默认为 false console.log(o) for (var i in o) { console.log(i) }for …in
for…in语句以任意顺序迭代两个第一类的除Symbol以外的可隐式特性,包括继承的可隐式特性。
const user = {}; Object.prototype.authenticated =true; for (var i in user) { console.log(i) }示例2
var obj = {}; obj.name = xkx; obj.age =18; obj.run = function() { //建立两个 run()方式并回到值 return this.name + this.age + 运行中…; };// 给蓝本加进特性和方式 Object.prototype.gaga = function() { console.log(gaga) } Object.prototype.names = names // 给蓝本加进两个可隐式的特性 Object.defineProperty(Object.prototype, “ages”, { enumerable: false, configurable: false,writable: false, value: 20 }); var descriptor = Object.create(null); // 没有继承的特性 // descriptor.value = static; // // 默认没有 enumerable,没有 configurable,没有 writable // Object.defineProperty(obj, key, descriptor); // console.log(Object.getOwnPropertyDescriptor(obj, key)) //显式 Object.defineProperty(obj, “key”, { enumerable: false, configurable: false, writable: false, value: “static” }); console.log(Object.getOwnPropertyDescriptor(obj,key)) console.log(obj) console.log(Object.getPrototypeOf(obj)) for (var i in obj) { console.log(i) }蓝本上加进的不可隐式的ages特性,没有被隐式
假如将enumerable 改为true,蓝本上加进的ages 可隐式特性被遍历
Object.defineProperty(Object.prototype, “ages”, { enumerable: true, configurable: false, writable: false, value: 20 });建立特性
假如第一类中不存有选定的特性,Object.defineProperty() 会建立那个特性。当配置文件中省略某些字段时,那些字段将采用它们的默认值。
Object.defineProperty() 方式会直接在两个第一类上表述两个新特性,或者修改两个第一类的原有特性,并回到此第一类。
var o = {}; // 建立两个新第一类 // 在第一类中加进两个特性与数据配置文件的示例 Object.defineProperty(o, “a”, { value : 37, writable : true, enumerable : true, configurable : true });getPrototypeOf方式
getPrototypeOf()是JavaScript中的内置函数,用作检查用户创建的第一类的蓝本。大多数时候,它用作检查两个第一类是否具有完全相同的蓝本。这里的蓝本是指用户在JavaScript代码中表述的第一类的内部表述
const person = { isHuman: false, printIntroduction: function() { console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`); } };const me = Object.create(person); console.log(me) me.name = Matthew; // “name” is a property set on “me”, but not on “person” me.isHuman = true; // inherited properties can be overwrittenme.printIntroduction();// expected output: “My name is Matthew. Am I human? true” console.log(Object.getPrototypeOf(me))应用场景: (1)完整克隆两个第一类,还拷贝第一类蓝本的特性,可以采用下面的写法。
// 写法一 const clone1 = { __proto__: Object.getPrototypeOf(obj), …obj };// 写法二 const clone2 = Object.assign( Object.create(Object.getPrototypeOf(obj)), obj );// 写法三 const clone3 = Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) )getOwnPropertyDescriptor 方式
Object.getOwnPropertyDescriptor
let obj = { foo: 123 }; Object.getOwnPropertyDescriptor(obj, foo) // { // value: 123, // writable: true, // enumerable: true, // configurable: true // } console.log(Object.getOwnPropertyDescriptor(Object.prototype, toString).enumerable) console.log(Object.getOwnPropertyDescriptor(Object.prototype, ages).enumerable)defineProperty方式
Object.defineProperty()方式会直接在两个第一类上表述两个新特性,或者修改两个第一类的原有特性,并回到此第一类
Object.keys(obj)
Object.keys回到两个数组,包括第一类另一方面的(不含继承的)所有可隐式特性(不含 Symbol 特性)的键名。
var obj = {}; obj.name = xkx; obj.age = 18; obj.run = function() { //建立两个 run()方式并回到值 return this.name + this.age + 运行中…; }; // 给蓝本加进特性和方式 Object.prototype.gaga = function() { console.log(gaga) } Object.prototype.names = names // 给蓝本加进两个可隐式的特性 Object.defineProperty(Object.prototype, “ages”, { enumerable: true, configurable: false, writable: false, value: 20 }); var descriptor = Object.create(null); // 没有继承的特性 // descriptor.value = static; // // 默认没有 enumerable,没有 configurable,没有 writable // Object.defineProperty(obj, key, descriptor); // console.log(Object.getOwnPropertyDescriptor(obj, key)) //显式 Object.defineProperty(obj, “key”, { enumerable: true, configurable: false, writable: false, value: “static” }); // console.log(Object.getOwnPropertyDescriptor(obj, key)) // console.log(obj) // console.log(Object.getPrototypeOf(obj)) // console.log(Object.getOwnPropertyDescriptor(Object.prototype, toString).enumerable) // console.log(Object.getOwnPropertyDescriptor(Object.prototype, ages).enumerable) // 查看第一类蓝本上toString console.log(Object.getOwnPropertyDescriptor(Object.prototype, toString)) // 修改前 console.log(obj.toString()) // 蓝本链形式修改 Object.prototype.toString = function() { return 修改了toString方式 } // defineProperty形式修改 // Object.defineProperty(Object.prototype, toString, { // value: ……… // }) // 修改后 console.log(obj.toString()) // 修改 重写 第一类蓝本上的toString 方式 // console.log(Object.getOwnPropertyDescriptor(Object.prototype, toString).enumerable) for (var i in obj) { console.log(i) } console.log(Object.keys(obj))可以发现蓝本上的特性并没有被隐式出来
常用方式
(1) 怎样判断某个第一类是否为另两个第一类的蓝本第一类 采用
Object.prototype.constructor.prototype进行比较 varobj1 = {name:“李雷”}; var obj2 = {age: 23}; obj1.constructor.prototype === Object.prototype; // true(2)采用:
Object.prototype.isPrototypeOf()进行比较var obj1 = {name: “Lilei”}; var obj2 = Object.create(obj1); obj1.isPrototypeOf(obj2);// true(3)扩展特性 ECMAScript 提案(第 3 阶段)的剩余/扩展特性将扩展特性加进到第一类字面上量。它将自己提供的第一类的隐式特性复制到两个新的第一类上。
采用比Object.assign()更短的语法,可以轻松克隆(不包括蓝本)或合并第一类。
var obj1 = { foo: bar, x: 42 }; var obj2 = { foo: baz, y: 13 }; var clonedObj = { …obj1 }; // Object { foo: “bar”, x: 42 } var mergedObj = { …obj1, …obj2 }; // Object { foo: “baz”, x: 42, y: 13 }(4)hasOwnProperty 继承的特性不显示
var triangle = {a: 1, b: 2, c: 3}; function ColoredTriangle() { this.color = red; } ColoredTriangle.prototype = triangle;var obj = new ColoredTriangle(); for (var prop in obj) { if(obj.hasOwnProperty(prop)) {console.log(`obj.${prop} = ${obj[prop]}`); } } // Output: // “obj.color = red”(4)Object.create(null)生生的第一类里面没有任何特性,非常“空”,我们称它为字典,这种字典第一类适合存放数据,不必担心蓝本带来的副作用。
bject.prototype.isPrototypeOf({})// true Object.prototype.isPrototypeOf([]) // true Object.prototype.isPrototypeOf(/xyz/) // true Object.prototype.isPrototypeOf(Object.create(null)) // false关于 _proto和 prototype
而缺省的prototype是什么,它的蓝本链最终又指向了哪里呢?那个问题的答案是:函数的prototype是两个在函数声明阶段就会产生的第一类(prototype只有函数才会有),那个第一类只有两个特性constructor和__proto__,其中__proto__指向了我们蓝本链的顶点Object.prototype。constructor指向函数本身,里面包括了函数一些基本描述信息比如函数名称,模块个数等。
有意思的是constructor里面即有__proto__又有prototype,他们之间有什么关系和差别呢?首先prototype描述的是蓝本第一类,它是两个实实在在的第一类,__proto__是用来描述第一类间的关联关系的。最终会指向两个prototype蓝本。函数由Function衍生而来,所以函数的__proto__指向的是Function.prototype。Function是由Object衍生而来,有意思的事情又发生了,Function的__proto__却并不指向Object.prototype,而是指向Function.prototype那个标准的内置第一类。
Function.prototype.__proto__才是指向我们的蓝本链顶点Object.prototypeFunction.proto === Function.prototype // true