技术码头

JS关于对象的属性和方法整理

2020-01-02  本文已影响0人  石菖蒲_xl

对象简介

三类js对象
两类属性

创建对象

1、对象直接量

// 没有任何属性的对象
var empty = {};

// 复杂对象
var book = {
  x:0,                        // 正常属性
  "main title":"Js",          // 属性名字有空格,必须用字符串表示
  "sub-title":"js js",        // 属性名字有连字符,必须用字符串表示
  "for":"all"                 // for 是关键字,必须用引号,不建议使用关键字作为属性名
}

如上:对象直接量是一个表达式,这个表达式每次运算都创建并且初始化一个新的对象,每次计算对象直接量的时候,也都会计算它的每个属性的值,所以,如果在一个重复调用的函数中的循环体内使用了对象直接量,它将创建很多新对象,并且每次创建的对象的属性值也有可能不同。

2、new一个对象
new运算符创建并初始化一个新对象,关键字new后跟随一个函数调用,这里的函数称做构造函数(constructor),构造函数用以初始化一个新创建的对象。

var o = new Object(); // 创建一个空对象,和{}一样
var a = new Array(); //  创建一个空数组,和 []一样
var d = new Date(); // 创建一个表示当前时间的Date对象
var r = new RegExp('js'); // 创建一个可以进行模式匹配的RegExp对象

3、Object.create()
Object.create()是一个静态函数,而不是提供给某个对象调用的方法,使用它的方法只需传入所需原型对象即可。*·what·? ? ? *

var o1 = Object.create({x:1}); // o1继承了属性x

如上代码所示:o1继承了属性x,注意是继承,此时我们打印o1,输出{},但是打印o1.x却能输出1,再看o1.__proto__输出{x:1}o1的原型对象是{x:1}{x:1}的原型对象是Object,这一系列链接的原型对象就是所谓的“原型链”。

原型链
var o2 = Object.create(null); // o2不继承任何属性和方法。
o2
var o3 = Object.create(Object.prototype); // o3和{}和 new Object() 一样
o3

继承

js对象具有“自有属性”,也有一些属性是从原型对象继承而来的。

function inherit(p) {
  if(p == null){
    throw TypeError();            // p 是一个对象,但是不能是null
  }
  if(Object.create) {
    return Object.create(p);     // 如果Object.create()存在就直接使用
  }
  var t = typeof p;
  if(t !== "Object" && t !== "function") {
    throw TypeError();
  }
  function f(){};           // 定义一个空构造函数
  f.prototype = p;         // 将其原型属性设置为p
  return new f();         // 使用f()创建p的继承对象
}

var o = {};                 // o 从 Object.prototype 继承对象的方法
o.x = 1;                   // 给o定义一个属性x
var p = inherit(o);       // p 继承 o 和 Object.prototype
p.y = 2;                 // 给p定义一个属性y
var q = inherit(p);      //  q 继承 p、o、Object.prototype
q.z = 3;                // 给 q 定义一个属性 z
var s = q.toString();  // toString 继承自Object.prototype
q.x + q.y;             // => 3     x 和 y 分别继承自 o 和 p

假设要查询对象 o 的属性 x,如果 o 中不存在 x,那么将会继续在 o 原型对重查询属性 x,如果原型对象中也没有 x,但这个原型对象也有原型,那么继续在这个原型对象的原型上执行查询,直到找到x或者查找到一个原型是null的对象为止,可以看到,对象的原型属性构成一个“链”,通过这个“链”可以实现属性的继承。

现在假设给对象o的属性x赋值,如果o中已经有属性x(这个属性不是继承而来的),那么这个赋值操作只改变这个已有属性x的值,如果o中不存在属性x,那么赋值操作给o添加一个新属性x,如果之前o继承自属性x,那么这个继承的属性就被新创建的同名的属性覆盖了。

var unitcircle = {r:1};
var c = inherit(unitcircle);
c.x = 1;
c.y = 1;
c.r = 2;
unitcircle.r;         // => 1 原型对象没有修改

原型
每一个js对象(除了null)都和另一个对象相关联,“另一个”对象就是我们熟知的原型,每一个对象都是从原型继承属性。


属性访问错误

var o = {y:1};
o.x; // => undefined
var o = null;
o.x; // => Uncaught TypeError: Cannot read property 'x' of null

var p = {y:1};
o.x.z; // =>  Uncaught TypeError: Cannot read property 'z' of undefined

删除属性


检测属性

js对象可以看做属性的集合,我们经常会检测集合中成员的所属关系,判定某个属性是否存在某个对象中。
js提供四种个方式:

var o = {x:1};
"x" in o;            // => true 自有属性
"y" in o;            // => false 不存在属性
"toString" in o;     //=> true 继承属性

2、 hasOwnProperty()
hasOwnProperty()用来检测给定的名字是否是对象的自有属性,对于继承的属性它将返回false

var o  = {x:1};
o.hasOwnProperty("x");            // => true 自有属性
o.hasOwnProperty("y");            // => false 不存在属性
o.hasOwnProperty("toString");    // => false ,继承属性

3、propertyIsEnumerable()
propertyIsEnumerable()hasOwnProperty()的增强版,只有检测到是自有属性且这个属性可枚举为true时它才返回true

var o = inherit({y:2});
o.x = 1;
o.propertyIsEnumerable("x");   // => true 自有可枚举属性
o.propertyIsEnumerable("y");  // => false 继承属性
Object.prototype.propertyIsEnumerable("toString"); // => false 不可枚举属性

4、使用!==判定一个属性是否是undefined

var o = {x:1,y:undefined};
o.x !== undefined;              // => true 自有属性
o.y !== undefined;              // => false 不存在属性
o.toString !== undefined;      // => true 继承属性
o.y !== undefined;            // => false 属性存在但是值为undefined

如上代码:当属性存在,但是值是undefined!==不能返回希望的结果。


枚举属性

除了检测对象的属性是否存在,我们还会经常的遍历对象的属性。

1、for/in
for/in循环可以在循环体重遍历对象中所有可枚举的属性(自有和继承),把属性名称赋值给循环遍历。

var o = {x:1};
var p = inherit(o);
p.y = 2;
for (var key in p){
  console.log(key);
}
// => y 自有属性
// => x 继承属性
// 没有输出 toString ?
"toString" in p;                     // => true 继承属性
p.propertyIsEnumerable("toString"); // => false 不可枚举属性

如何过滤继承属性?

for (var key in p){
  if(!p.hasOwnProperty(key)) continue; // 跳过继承属性
   console.log(key)
}
// => x 只输出自有属性

2、Object.keys()
Object.keys() 枚举属性名称的函数,它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。

var o = {x:1};
var p = inherit(o);
p.y = 2;
p.z = 3;
Object.keys(p); // => ["y","z"] 未返回继承属性x

3、Objcet.getOwnPropertyNames()
只返回对象的自有属性名称,而不仅仅是可枚举属性,不可枚举属性也会返回。

var o = {x:1};
var p = inherit(o);
p.y = 2;
p.z = 3;
Object.defineProperty(p,"h",{value:4,enumerable:true}); // 添加可枚举属性
Object.defineProperty(p,"w",{value:5,enumerable:false}); // 添加不可枚举属性
Object.keys(p); // => ["y","z","h"]  未返回不可枚举属性w 和继承 属性 x
Object.getOwnPropertyNames(p); // => ["y","z","h","w"] 只是未返回继承属性 x

属性getter和setter

ES5中属性值可以用一个或两个方法代替,这俩方法就是gettersetter。由gettersetter定义的属性称做“存取器属性”

var o = {
  x:1,
  y:2,
  h:undefined,
  get product(){
    return this.x * this.y;
  },
  set product(value){
    this.x = value;
    this.y = value * 2;
  },
  get sum(){
    return this.x + this.y;
  },
  set z(value){
    this.h = value;
  }
}
// product 是一个读/写属性
o.product;     // => 2 
o.product = 2;
o.product;     // => 8

// sum 是一个只读属性
o.sum;       // => 3
o.sum = 5;
o.sum;       // => 3

// z 是一个只写属性
o.z;      // => undefined
o.z = 4;
this.h; // => 4

属性的特性

除了包含名字和值之外,属性还包含一些标识它们可写、可枚举、可配置的特性。ES3无法设置这些特性。

{
  value:数据属性,表示属性的值,默认: undefined
  writable: 可写性,表示能否修改属性。默认值:true
  enumerable:可枚举性,表示能否通过 for/in 遍历得到属性,默认true
  configurable:可配置性,如果属性为false则不可在对属性描述符进行修改,默认值为true。
}

通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述对象

var o = {x:1};
Object.getOwnPropertyDescriptor(o,"x");
// => {"value":1,"writable":true,"enumerable":true,"configurable":true}
Object.getOwnPropertyDescriptors(o);
// => {"x":{"value":1,"writable":true,"enumerable":true,"configurable":true}}

由上边代码可见,这个方法只能得到自有属性的描述符。
那么如何设置属性的特性呢? Object.defineProperty()

这个方法要么修改已有属性要么新建自有属性,但是不能修改继承属性。

var o = {x:1};
// 设置一个不可枚举的属性,其他属性默认true
Object.defineProperty(o,"x",{value:1,enumerable:false});
Object.keys(o); // => []

Object.defineProperties()
如果要同时修改或者创建多个属性:

var o = {};
// 给对象o添加俩个属性,x 和 y 其中 y 不可枚举不可配置
Object.defineProperties(o,{
  x:{"value":1,"writable":true,"enumerable":true,"configurable":true},
  y:{"value":2,"writable":true,"enumerable":false,"configurable":false}
});
// y不可配置,如果这个时候我们想要修改y的属性描述符,会报出错误异常
Object.defineProperties(o,{
  y:{"value":2,"writable":true,"enumerable":true,"configurable":false}
});
// => Uncaught TypeError: Cannot redefine property: y

对象的三个属性

原型属性
var o = {x:1};
var p = Object.create(o);
o.isPrototypeOf(p);        // => true p继承自o
Object.prototype.isPrototypeOf(o); // true  o 继承自Object.prototype
可扩展性

对象的可扩展性用以表示是否可以给对象添加新属性。


序列化对象

对象序列化是指将对象的状态转换为字符串,也可以将字符串还原为对象。
ES5提供了内置函数JSON.stringify()JSON.parse()用来序列化和还原js对象。

JSON.stringify(NaN); // => "null"
JSON.stringify(Infinity); // => "nulll"
JSON.stringify(undefined); // => undefined

instanceof 运算符

instanceof运算符希望左操作数是一个对象,右操作数标识对象的类,如果左侧对象是右侧类的示例,则表达式返回true,否则返回false
js对象的类是通过初始化它们的构造函数来定义的,这样的话instanceof的右操作数应当是一个函数

var d = new Date(); // 通过Date()构造函数来创建一个新对象
d instanceof Date; // => true d是由Date创建的
d instanceof Object ; // => true 所有的对象都是Object的实例
d instanceof Number; // => false 

上一篇 下一篇

猜你喜欢

热点阅读