[js] Object
Object.create()
Object.create(proto, [ propertiesObject ])
Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象。
#似乎是更纯净的object
console.log({}.__proto__);//有 let a = Object.create(null); console.log(a.__proto__);//undefined
#使用Object.create实现类式继承
//Shape - superclass function Shape() { this.x = 0; this.y = 0; } Shape.prototype.move = function(x, y) { this.x += x; this.y += y; console.info("Shape moved."); }; // Rectangle - subclass function Rectangle() { Shape.call(this); //call super constructor. } Rectangle.prototype = Object.create(Shape.prototype); var rect = new Rectangle(); console.log(rect instanceof Rectangle); //true. console.log(rect instanceof Shape); //true. rect.move(1, 1); //Outputs, "Shape moved."
#
var o; // 创建一个原型为null的空对象 o = Object.create(null); o = {}; // 以字面量方式创建的空对象就相当于: o = Object.create(Object.prototype); o = Object.create(Object.prototype, { // foo会成为所创建对象的数据属性 foo: { writable: true, configurable: true, value: "hello" }, // bar会成为所创建对象的访问器属性 bar: { configurable: false, get: function() { return 10 }, set: function(value) { console.log("Setting `o.bar` to", value) } } }) function Constructor() {} o = new Constructor(); // 上面的一句就相当于: o = Object.create(Constructor.prototype); // 当然,如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码 // 创建一个以另一个空对象为原型,且拥有一个属性p的对象 o = Object.create({}, { p: { value: 42 } }) // 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的: o.p = 24 o.p;//42 o.q = 12 for (var prop in o) { console.log(prop) } //"q" delete o.p//false //创建一个可写的,可枚举的,可配置的属性p o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });
Object.prototype.toString()
object.toString()
toString() 方法返回一个代表该对象的字符串。
可以通过Object.prototype.toString.call() 来获取每个对象的类型。
把需要检测的对象作为第一个参数传入。
var toString = Object.prototype.toString; toString.call(new Date); // [object Date] toString.call(new String); // [object String] toString.call(Math); // [object Math] //Since JavaScript 1.8.5 toString.call(undefined); // [object Undefined] toString.call(null); // [object Null] function judge(data) { console.log(data,toString.call(data)); } judge([]); judge({}); judge(Array); judge(null);
#
function isArray(value) { return Object.prototype.toString.call(value) == '[object Array]'; } function isFunction(value) { return Object.prototype.toString.call(value) == '[object Function]'; } function isRegExp(value) { return Object.prototype.toString.call(value) == '[object RegExp]'; } console.log(isRegExp(/abc/));
#Number.prototype.toString()
numObj.toString([radix])
toString() 方法返回指定 Number 对象的字符串表示形式。
var count = 10; print( count.toString() ); // 输出 "10" print( (17).toString() ); // 输出 "17" var x = 6; print( x.toString(2) ); // 输出 "110" print( (254).toString(16) ); // 输出 "fe" print( (-10).toString(2) ); // 输出 "-1010" print( (-0xff).toString() ); // 输出 "-11111111"
#ECMAscript5
Object.create()
//创建一个拥有指定原型和若干个指定属性的对象。
//Shape - superclass function Shape() { this.x = 0; this.y = 0; } Shape.prototype.move = function(x, y) { this.x += x; this.y += y; console.info("Shape moved."); }; // Rectangle - subclass function Rectangle() { Shape.call(this); //call super constructor. } Rectangle.prototype = Object.create(Shape.prototype); console.log(Rectangle.prototype.constructor); //Shape var rect = new Rectangle(); rect instanceof Rectangle //true.; rect instanceof Shape //true. rect.move(1, 1); //Outputs, "Shape moved."
Object.getPrototypeOf(object)
//返回指定对象的原型(也就是该对象内部属性[[Prototype]]的值)。
var proto = {}; var obj = Object.create(proto); Object.getPrototypeOf(obj) === proto; // true
#在 ES5 中,如果参数不是一个对象类型,将抛出一个 TypeError 异常。在 ES6 中,参数被强制转换为Object。
console.log(Object.getPrototypeOf("foo")); // ES5 code //TypeError: "foo"is not an object console.log(Object.getPrototypeOf("foo")); // ES6 code //String.prototype
Object.prototype.isPrototypeOf()
prototype.isPrototypeOf(object)
//Object.prototype.isPrototypeOf(XX),可以判定XX是不是对象
//测试一个对象是否存在于另一个对象的原型链上。
function Fee() { // . . . } function Fi() { // . . . } Fi.prototype = new Fee(); function Fo() { // . . . } Fo.prototype = new Fi(); function Fum() { // . . . } Fum.prototype = new Fo(); var fum = new Fum(); var fo = new Fo(); console.log(Fi.prototype.isPrototypeOf(fo)); //true console.log(Fi.prototype.isPrototypeOf(fum)); //true
Object.keys()
Object.keys(obj)
#ES5
Object.keys() 方法会返回一个由给定对象的所有可枚举自身属性的属性名组成的数组,数组中属性名的排列顺序和使用for-in循环遍历该对象时返回的顺序一致
,两者的主要区别是 for-in 还会遍历出一个对象从其原型链上继承到的可枚举属性。
打印的是键值。
var arr = ["a", "b", "c"]; console.log(Object.keys(arr)); // "0,1,2" // 类数组对象 var obj = { 0 : "a", 1 : "b", 2 : "c"}; console.log(Object.keys(obj)); // "0,1,2" // getFoo是个不可枚举的属性 var my_obj = Object.create({}, { getFoo : { value : function () { return this.foo } } }); my_obj.foo = 1; console.log(Object.keys(my_obj)); // 只打印出foo
Object.getOwnPropertyNames()
Object.getOwnPropertyNames(obj)
返回一个数组,该数组对元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。
数组中枚举属性的顺序与通过 for...in (或 Object.keys))迭代该对象属性时一致。
数组中不可枚举属性的顺序未定义。
#与object.key的区别在于能够获取不可枚举的属性名(键值)
var arr = ["a", "b", "c"]; console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"] // 类数组对象 var obj = { 0: "a", 1: "b", 2: "c"}; console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"] // 使用Array.forEach输出属性名和属性值 Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) { console.log(val + " -> " + obj[val]); }); // 输出 // 0 -> a // 1 -> b // 2 -> c //不可枚举属性 var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; }, enumerable: false } }); my_obj.foo = 1; console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]
#不获取到原型链上的属性
function ParentClass() {} ParentClass.prototype.inheritedMethod = function() {}; function ChildClass() { this.prop = 5; this.method = function() {}; } ChildClass.prototype = new ParentClass; ChildClass.prototype.prototypeMethod = function() {}; console.log(Object.getOwnPropertyNames(new ChildClass())); // ["prop", "method"]
#仅获取不可枚举的属性
var target = myObject; var enum_and_nonenum = Object.getOwnPropertyNames(target); var enum_only = Object.keys(target); var nonenum_only = enum_and_nonenum.filter(function(key) { var indexInEnum = enum_only.indexOf(key); if (indexInEnum == -1) { // not found in enum_only keys mean the key is non-enumerable, // so return true so we keep this in the filter return true; } else { return false; } }); console.log(nonenum_only);
#在 ES6 中, non-object 参数被强制转换为 object 。
Object.getOwnPropertyNames('foo'); // TypeError: "foo" is not an object (ES5 code) Object.getOwnPropertyNames('foo'); // ['length', '0', '1', '2'] (ES6 code)
Object.prototype.hasOwnProperty()
obj.hasOwnProperty(prop)
hasOwnProperty() 方法用来判断某个对象是否含有指定的自身属性。
判断某对象是否含有特定的自身属性
o = new Object(); o.prop = 'exists'; function changeO() { o.newprop = o.prop; delete o.prop; } o.hasOwnProperty('prop'); // 返回 true changeO(); o.hasOwnProperty('prop'); // 返回 false
hasOwnProperty && in 同时为true,实例。
in 为 true ,hasOwnProperty 为 false,原型。
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ console.log(this.name); }; var person1 = new Person(); var person2 = new Person(); console.log(person1.hasOwnProperty("name")); //false console.log("name" in person1); //true person1.name = "Greg"; console.log(person1.name); //"Greg" from instance console.log(person1.hasOwnProperty("name")); //true console.log("name" in person1); //true console.log(person2.name); //"Nicholas" from prototype console.log(person2.hasOwnProperty("name")); //false console.log("name" in person2); //true delete person1.name; console.log(person1.name); //"Nicholas" - from the prototype console.log(person1.hasOwnProperty("name")); //false console.log("name" in person1); //true
自身属性和继承属性的区别
o = new Object(); o.prop = 'exists'; o.hasOwnProperty('prop'); // 返回 true o.hasOwnProperty('toString'); // 返回 false o.hasOwnProperty('hasOwnProperty'); // 返回 false
遍历一个对象的所有自身属性
var buz = { fog: 'stack' }; for (var name in buz) { if (buz.hasOwnProperty(name)) { console.log("this is fog (" + name + ") for sure. Value: " + buz[name]); } else { console.log(name); // toString or something else } }
#ES5
Object.defineProperty()
Object.defineProperty(obj, prop, descriptor)
Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。
// 使用 __proto__ Object.defineProperty(obj, "key", { __proto__: null, // 没有继承的属性 value: "static" // 没有 enumerable // 没有 configurable // 没有 writable // 作为默认值 }); // 显式 Object.defineProperty(obj, "key", { enumerable: false, configurable: false, writable: false, value: "static" }); // 循环使用同一对象 function withValue(value) { var d = withValue.d || ( withValue.d = { enumerable: false, writable: false, configurable: false, value: null } ); d.value = value; return d; } // ... 并且 ... Object.defineProperty(obj, "key", withValue("static")); // 如果 freeze 可用, 防止代码添加或删除对象原型的属性 // (value, get, set, enumerable, writable, configurable) (Object.freeze||Object)(Object.prototype);
#
var o = {}; o.a = 1; // 等同于 : Object.defineProperty(o, "a", { value : 1, writable : true, configurable : true, enumerable : true }); // 另一方面, Object.defineProperty(o, "a", { value : 1 }); // 等同于 : Object.defineProperty(o, "a", { value : 1, writable : false, configurable : false, enumerable : false });
#set、get
var o = {}; // 创建一个新对象 // Example of an object property added with defineProperty with a data property descriptor Object.defineProperty(o, "a", {value : 37, writable : true, enumerable : true, configurable : true}); // 对象o拥有了属性a,值为37 // Example of an object property added with defineProperty with an accessor property descriptor var bValue; Object.defineProperty(o, "b", {get : function(){ return bValue; }, set : function(newValue){ bValue = newValue; }, enumerable : true, configurable : true}); o.b = 38; // 对象o拥有了属性b,值为38 // The value of o.b is now always identical to bValue, unless o.b is redefined // 数据描述符和存取描述符不能混合使用 Object.defineProperty(o, "conflict", { value: 0x9f91102, get: function() { return 0xdeadbeef; } }); // throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors
#
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 }]
#
var pattern = { get: function () { return 'I alway return this string,whatever you have assigned'; }, set: function () { this.myname = 'this is my name string'; } }; function TestDefineSetAndGet() { Object.defineProperty(this, 'myproperty', pattern); } var instance = new TestDefineSetAndGet(); instance.myproperty = 'test'; console.log(instance.myproperty);//I alway return this string,whatever you have assigned console.log(instance.myname);//this is my name string
#writable
var o = {}; // 创建一个新对象 Object.defineProperty(o, "a", { value : 37, writable : false }); console.log(o.a); // 打印 37 o.a = 25; // 没有错误抛出(在严格模式下会抛出,即使之前已经有相同的值) console.log(o.a); // 打印 37, 赋值不起作用。
#enumerable
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 defaults to false o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则这个属性的enumerable为true for (var i in o) { console.log(i); } // 打印 'a' 和 'd' (in undefined order) Object.keys(o); // ["a", "d"] o.propertyIsEnumerable('a'); // true o.propertyIsEnumerable('b'); // false o.propertyIsEnumerable('c'); // false
#configurable 特性表示对象的属性是否可以被删除,以及除 writable 特性外的其他特性是否可以被修改。
var o = {}; Object.defineProperty(o, "a", { get : function(){return 1;}, configurable : false } ); Object.defineProperty(o, "a", {configurable : true}); // throws a TypeError Object.defineProperty(o, "a", {enumerable : true}); // throws a TypeError Object.defineProperty(o, "a", {set : function(){}}); // throws a TypeError (set was undefined previously) Object.defineProperty(o, "a", {get : function(){return 1;}}); // throws a TypeError (even though the new get does exactly the same thing) Object.defineProperty(o, "a", {value : 12}); // throws a TypeError console.log(o.a); // logs 1 delete o.a; // Nothing happens console.log(o.a); // logs 1
Object.defineProperties()
Object.defineProperties(obj, props)
在一个对象上添加或修改一个或者多个自有属性,并返回该对象。
#
var obj = {}; Object.defineProperties(obj, { "property1": { value: true, writable: true }, "property2": { value: "Hello", writable: false } // etc. etc. });
Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor(obj, prop)
obj
在该对象上查看属性
prop
一个属性名称,该属性的属性描述符将被返回
返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
如果指定的属性存在于对象上,则返回其属性描述符(property descriptor),否则返回 undefined。
在 Javascript 中, 属性 由一个字符串类型的“名字”(name)和一个“属性描述符”(property descriptor)对象构成。
一个属性描述符是一个记录,由下面属性当中的某些组成的:
value
该属性的值(仅针对数据属性描述符有效)
writable
当且仅当属性的值可以被改变时为true。(仅针对数据属性描述有效)
get
获取该属性的访问器函数(getter)。如果没有访问器, 该值为undefined。(仅针对包含访问器或设置器的属性描述有效)
set
获取该属性的设置器函数(setter)。 如果没有设置器, 该值为undefined。(仅针对包含访问器或设置器的属性描述有效)
configurable
当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为true。
enumerable
当且仅当指定对象的属性可以被枚举出时,为 true。
#
var o, d; o = {get foo() { return 17; } }; d = Object.getOwnPropertyDescriptor(o, "foo"); // d is { configurable: true, enumerable: true, get: /*访问器函数foo*/, set: undefined } console.log(d); o = { bar: 42 }; d = Object.getOwnPropertyDescriptor(o, "bar"); // d is { configurable: true, enumerable: true, value: 42, writable: true } console.log(d); o = {}; Object.defineProperty(o, "baz", { value: 8675309, writable: false, enumerable: false }); d = Object.getOwnPropertyDescriptor(o, "baz"); // d is { value: 8675309, writable: false, enumerable: false, configurable: false } console.log(d);
#在 ES6 中, non-object 参数被强制转换为 object 。
Object.getOwnPropertyDescriptor("foo", 0); // TypeError: "foo" is not an object // ES5 code Object.getOwnPropertyDescriptor("foo", 0); // {configurable:false, enumerable:true, value:"f", writable:false} // ES6 code