首页 > 技术文章 > JavaScript Object

lancgg 2019-02-19 21:39 原文

创建: 2019/02/19

迁入: 2019/02/19 从【JavaScript 基础】迁入 Object相关内容

完成: 2019/02/26 (并给迁入专门赋予新的标签: 迁入)

更新: 2019/02/26 已完全覆盖迁入内容, 故删除迁入内容, 移到删除

更新: 2019/03/03 补充class语法

更新: 2019/05/03 补充class内部定义属性

待完成事项: TODO 

 

 Object的生成
 注意
 new  生成实例并初始化
 this   表示生成的实例
 注意,嵌套的话代表最靠近的一级的外层实例
   作为构造函数的函数一般首字母大写(大驼峰记法)
 定义访问属性

 用 Object.defineProperty(obj, p, descriptor) 

function Sample(name) {
  Object.defineProperty(this, name.toString(), {
    get: function() {
      return this.name;
    },
    set: function(n) {
      this.name = n;
    },
    enumerable: true,
    configurable: true
  });
}

 

 注: 这种直接定义在this里, 要放prototype则用class或者函数外 

Object.defineProperty(B.prototype, 'name', {
  get: function() {
    return this.a;
  },
  set: function(v) {
    this.a = v;
  }
});

 

 构造函数的继承 

 例

function A() {
    this.a = 1;
}
A.prototype.show = function() {
    console.log(this.a);
}

function B() {
    this.b = 2;
}

 B继承A的方法一

Object.setPrototypeOf(B.prototype, A.prototype);
// 也就是B.prototype.__proto__ = A.prototype

 方法二(结果和方法一一样)

B.prototype = Object.create(A.prototype, {
    value: B,
    writable: true,
    enumerable: true,
    configurable: true
})

 方法三(这种保留继承的类定义的属性, 推荐)

B.prototype = new A();
B.prototype.constructor = B;

 保留继承类定义属性的另一种方法 

function B() {
    A.call(this);
    this.b = 2;
}
Object.setPrototypeOf(B.prototype, A.prototype);

 

 

 利用继承的函数

 

B.prototype.showA = function () {
    A.prototype.showA();
    ...
};

 

 class语法

 

class A {
  constructor() {
    this.a = 1;
  }
  show() {
    console.log(`this.a = ${this.a}`);
  }
}
let a = new A();

 注:

 · constructor是构造函数, 相当于 function A() {} 

   定义属性和方法都可以在 constructor() {...} 外

class Sample {
    a = 1; // 属性都在this里
    b = {a: 1, b: 2};
    show() { // 方法都在this.prototype里
        console.log(`a: ${this.a}, b: ${this.b}`);
    };
}

 · 除了constructor以外的属性, 如果是方法则自动放入prototype, 其他相当于constructor里设置

 · class声明不上卷, 遇到以后才能用

 · 同一个名称只能用一次, let a = class name {...} 除外(这种的name只在类定义内部有效)

 · 类的constructor不能当做函数来用

 · 定义访问属性: 

class C {
  show() {
    console.log(`name: ${this.name}`);
  }
  get name() {
    return this.a;
  }
  set name(v) {
    this.a = v.toString();
  }
}

 · 类方法用static

 · 继承用extends 

   子类的构造函数要先呼出 super() 

 对象字符(literal)生成

 {键: 值, 键: 值, ...}
 var sample = {sample1: 1, sample2: 2}
 注意: 符号部分不需要特地写成字符串(键可以用单纯的符号,也可以用字符串。获取时没有区别)
         可以嵌套

 var sample = { a: 1, b: 2, "c":3};
 var multi = {
       {a: 1, b: 2},
        c: 1,
        d: 2
 };

 获取: sample.a或sample["a"]

 构析函数

 构析函数来生成

 function Object-Name(args) {
    this.property-name = ?;
    this.property-name = ?;
    ...
 }

 var sample = new Object-Name(args);

 

 例: 

function ObjectTest(numA, numB) {
    this.numA = numA;
    this.numB = numB;
}
let objectTest = new ObjectTest(111, 222);

 

 生成带方法的Object: 

function Sum(a, b) {
    this.a = a;
    this.b = b;
    this.sum = function() {
        return a + b;
    }
}

var sample = new Sum(1, 2);
console.log(sample.sum()); // 3

 

 

 Object.create

 

var o3 = Object.create(Object.prototype, {
  a: {
    value: 1, // 必须有
    writable: true, // 必须有
    enumerable: true, // 必须有
    configurable: true // 必须有
  },
  b: {
    value: 1,
    writable: true,
    enumerable: true,
    configurable: true
  }
}); 

 注:  每一个属性都要设定  value, writable, enumerable, configurable 

 

   
   
 用构析函数定义函数的问题

 每一个实例都生成共有的元素函数,占用内存空间
 解决方法: 放到prototype
 var sample = function() {
    ...
 }
 sample.prototype.test = function() {
    ...
 }

 注: prototype默认为{}, 啥都没有

  从instance处只可读

 

 

   
访问与添加属性
 获取属性

 var sample = {a: 1, b: 2}
 两种方法
 注意: 用[]时候里面要放字符串

         不存在时返回undefined

   sample.a
   sample["a"]
 增加与删除元素
 增加  直接往新键带值
 var sample = {}
 sample.test1 = 1
 删除  delete ...
 例子: delete sample.test1
 内置Object  传送门:http://www.cnblogs.com/lancgg/p/8281719.html 
   
   
 protype的继承
 __proto__
 __proto__含义  

指向父object(当前object继承父object) 

var o6 = {
  name: 'a',
  show: function() {
    console.log('name: ' + this.name);
    return 'ok';
  }
};
console.log(o6.show());
var o7 = {
  name: 'b'
};
o7.__proto__ = o6;
console.log(o7.show());
var o8 = {};
o8.__proto__ = o7;
console.log(o8.show());

 

  

 呼出属性时的搜索链

  例:  obj.sample(); 

 先搜索 obj自身 有没有 sample 属性
 没有的话搜索 obj.__proto__ 
 还没有就继续往上搜索 obj.__proto__.__proto__ 
 如果搜到顶也没有则报错
 指定__proto__的方法

 ● 在构造函数的prototype里添加属性

 ● 使用Object.create方法

 获取prototype

 Object.getPrototypeOf()

 和直接呼出.__proto__一个效果

 设定prototype

 Object.setPrototypeOf()

 小结: __proto__是从头到目前object的所有继承内容, prototype是此object添加的。

         继承此object的__proto__ = 上一个.prototype

 new的作用

 例

// new的作用
function Sample(a, b) {
  this.a = a;
  this.b = b;
}
Sample.prototype.show = function () {
  console.log(this.a + this.b);
}
var o9 = new Sample(10, 30);

  内部处理

    
var newObj = {};

 

 

 

newObj.__proto__ = Sample.prototype

 如果 Sample.prototype 不是object, 则直接带入 Object.prototype 

 

 

Sample.apply(newObj, a, b); // 就是new的对象和参数

 

   
 return newObj;

 但构造函数的return值是object的话, 返回return的那个

 

 

 prototype的属性

 构造函数(所有函数都是)的prototype自带属性

 

 constructor  参照到自身
 __proto__  参照到 Object.prototype  (为空)

 

function F() {};
console.log(F.prototype.constructor); // ƒ F() {}
console.log(F.prototype.__proto__); // Object.prototype

 

 确认proto

 instanceof

a instanceof A // 对象 instanceof 构造函数
function F() {};
var obj = new F();
console.log(obj instanceof F); // true
console.log(obj instanceof Object); // true
console.log(obj instanceof Date); // false

 

 isPrototypeOf

prototype.isPrototypeOf(对象);
function F() {};
var obj = new F();
console.log(F.prototype.isPrototypeOf(obj)); // true
console.log(Object.prototype.isPrototypeOf(obj)); // true
console.log(Date.prototype.isPrototypeOf(obj)); // false

 

 Object的constructor

 

// 三个完全等价
var obj = {};
var obj = Object();
var obj = new Object();

 若指定参数, 则转换为对应的对象

 

 属性

 

 prototype  容纳prototype
   

 

 方法

 例: Object.assin(target, ...)

 # TODO: 补充这里

 assign(target, ...)

 把第二参数以后所有对象的可枚举自定义属性复制到target

 注: 不兼容访问属性

 解决方法: Object.getOwnPropertyDescriptor(obj, key), Object.defineProperty

function mixin(to, from) {
  for (var p in from) {
    if (from.hasOwnProperty(p)) {
      Object.defineProperty(to, p, Object.getOwnPropertyDescriptor(from, p));
    }
  }
  return to;
}

 

 

 create(proto [, propertiesObject])

 指定__proto__(继承对象)和属性生成object

 注: 要生成 {}的话用 

Object.create(Object.prototype);

 注: 第二参数和defineProperties的一样

 defineProperty(obj, prop, descriptor)

  设定属性(可以是新添加)

 注: 省略的属性描述部分: 若不存在该属性则设为 false/undefined

               存在则不做修改

 defineProperties(obj, props)

 

  var c = Object.defineProperties({}, {
    _t: {
      value: "t",
      writable: true,
      enumerable: true,
      configurable: true
    },
    name: {
      get () {
        return this._t;
      },
      set (v) {
        this._t += v;
      },
      enumerable: true,
      configurable: true
    }
  })

 

 

 getOwnPropertyDescriptor(obj, prop)

 获取指定的prop的descriptor

 例: 

Object.getOwnPropertyDescriptor({a:1}, 'a'); 
// => {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor({a:1}, 'n'); // => undefined

 注: 只用于当前实例自身的属性, __proto__继承的无效

 

 

 getOwnPropertyNames(obj) 

 获取指定obj所有prop的名称(字符串的数组)

 注: 返回此类定义的所有属性/方法(无视enumerable是否为true)

 keys(obj)

 注: 只返回此类定义且可枚举的

 getOwnPropertySymbols(obj)

 获取指定obj所有Symbol属性的名称(Symbol的数组)

 is(value1, value2)  判断value1和value2是否相同
 isExtensible(obj)  判断是否可以扩展
 isFrozen(obj)  判断是否被冻结
 isSealed(obj)  判断是否受保护
 preventExtensions(obj)

 禁止扩展(是object无法添加新属性)

 注: strict模式下阻止后再添加属性会报错

  // "use strict";
  var a = {a: 1};
  Object.preventExtensions(a);
  a.b = 1;
  console.log(a); // => {a:1}

 

 

 seal(obj)

 保护obj(阻止添加新prop且所有现有的configurable都设为false)

 注: 可以对已有的prop进行修改

 

 freeze(obj)

 固定指定obj(生成无法改动的新obj)

 注: 有setter的可以调用setter来改变属性值

 

 getPrototypeOf(obj)  获取指定Object的prototype
 setPrototypeOf(obj, prototype)  设定__proto__
   
   

 

 

  Object.prototype

 所有自带Object都继承,instance上都可用

 hasOwnProperty(key)

 in

 是否拥有指定key

 注: 只判断自身的值, 继承的无效(继承的也判断则用in)

 

  var a = { a: 1 };
  var b = Object.create(a, {
    b: {
      value: 1,
      writbale: true,
      enumerable: true,
      configurable: true
    }
  });
  console.log(b);
  console.log('------------------in--------------------');
  console.log('b' in b); // true
  console.log('a' in b); // true
  console.log('--------------hasOwnProperty---------------');
  console.log(b.hasOwnProperty('b')); // true
  console.log(b.hasOwnProperty('a')); // false

 

 

 isPrototypeOf(obj)  是否是指定obj的prototype
 propertyIsEnumerable(key)

 指定key的值是否可枚举(值存在且可枚举)

 注: 只对自身的值有效, 继承的(prototype里的)无效

 

 toString()

 toLocaleString()

 转换成字符串
 valueOf()   返回primitive
   
   
   
   
   

 

   
   
 访问属性
 属性种类  数据属性, 访问属性
 访问属性

 ● 用get, set替代 function 

 ● get, set中间要逗号

 ● get没参数, set一个参数

 ● 呼出不存在的setter不会有反应, strict模式下报错

 注: 内置属性(Object.prototype等)的都是 writable: true, enumerable: false, configurable: true 

get 函数名() {
    ...
}

 

set 函数名(一个参数名) {
    ...
}

  

var a = {
    _t: 't',
    get t() {
      return this._t;
    }, // 要逗号
    set t(v) {
      this._t = this._t + '|' + v;
    }
  }
  console.log(a.t); // t
  a.t = 100;
  console.log(a.t); // t|100

 

 对外部隐藏数据属性

  用闭包

  var b = (function () {
    var a = "a";
    return {
      show: function () {
        console.log('name: ' + a);
      },
      get name() {
        return a;
      },
      set name(v) {
        a = v;
      }
    };
  })();
  b.show(); // => name: a
  b.name = "haha";
  b.show(); // => name: haha

 

 

   
 property的属性
 两种

 

 

 

get: Function // getter
set: Function // setter
enumerable: Bool // for/in是否可以枚举
configurable: Bool // 是否可以改变设定 

 

 

 

value: 值的类型随意
writable: Bool // 是否可以改变value
enumerable: Bool // for/in 是否可以枚举
configurable: Bool //是否可以改变属性的属性(false则只能改writable到false)

 

 

 

 属性的属性

 [getter/setter]和[value+write]不可共存

 可写

 writable

 是否可以改变值

 可枚举

 enumerable

 用for/in, Object.keys来遍历是是否能获取该值

 注: __proto__里的都是false

 

是否改变内部属性

 configurable

 注: 包括 writable, enumerable, configurable

      一旦设定为false, 除了把writalbe变为false ,不可以改变其他

 

 

  属性描述符

 属性描述符

{
    value: 属性值,
    writable: true/false,
    enumerable: true/false,
    configurable: true/ false,
}

 

 

 获取

 Object.getOwnPropertyDescriptor(obj, prop)

 注: 只用于当前实例自身的属性, __proto__继承的无效

 设定  Object.defineProperty(obj, prop, descriptor)

 

   
   
 属性的枚举
 for/in

 语言自带的内置属性(Object.prototype等内部的)的 enumerable都是false 

 · 有些库对Object.prototype添加方法时enumerable没设为false, 避免误操作的方法

for (var p in obj) {
    if (!obj.hasOwnProperty(p)) { continue; }
    ...
}

// 或者
for (var p in obj) {
    if (typeof(p) === "function") { continue; }
    ...
}

 

 

 Object.keys 

 只返回此类定义且可枚举的

 Object.getOwnPropertyNames 

 只返回此类定义的所有属性/方法(无视enumerable是否为true)

 

   
 Object的锁
 extensible

 是否可以新添加属性

 内置object和所有自定义object的默认都是true

 阻止扩展

 

Object.preventExtensions(obj)

 

 strict模式下阻止后再添加会报错

 保护

 

Object.seal(obj)

 

 禁止 添加/删除 新 属性/方法, 且所有的configurable设为false

 即只可以改变属性的值

 冻结

 

Object.freeze(obj)

 

 禁止一切操作, 除了读取(有setter的可以调用setter来改变属性)

   
 Mixin
    不继承, 把属性复制到其他object
 Object.assign(target [, ...])

 把第二参数及以后的所有自定义变量都写入target

 注: 只是增加一个参照, 直接呼出值. 不兼容访问属性

 解决方法: Object.getOwnPropertyDescriptor(obj, key), Object.defineProperty

function mixin(to, from) {
  for (var p in from) {
    if (from.hasOwnProperty(p)) {
      Object.defineProperty(to, p, Object.getOwnPropertyDescriptor(from, p));
    }
  }
  return to;
}

 

   
 JSON
 写法

 

'{ "a": 1 }' // 最外边有单引号, 所有字符串和属性名都要加双引号

 

 

  数值

 

1
1.1

 

 十进制整数, 浮点数。

 浮点数也可以用指数来表示

 字符串

 添加双引号。可以带转意字符 "\" 

 Bool  true/false
 null  null
 数组  
[] // 用[]围着, 元素数据类型任意,且不用相同

 

[
    {
        "a": 1,
        "b": 2
    },
    1.1,
    "sample",
    null
]

 

 

 object

 

{ "a": 1 }

 

 属性名用双引号包围

   
   

 

 object与json的转换

 

转换为Json

 

JSON.stringify(value[, replacer [, space]])

 参数 

 value  要转换的object
 replacer

 函数/数组

 默认null

 函数

 两个参数, 第一个是属性名, 第二个属性值

 返回属性值

 数组

 只有数组里的字符串才能作为属性输出

 (无视不在数组里的属性名)

 

 space

 指定空白字符

 默认null

 

 注:

 · NaN, Infinity, -Infinity转换为null

 · Date转换为ISO形式的字符串

 · Function, RegExp, Error, undefined, Symbol直接无视(属性名和值都忽略)

 · 只转换enumerable为true的属性(其他忽略)

 · 属性名是Symbol类的也忽视

 JSON转换为object

 

JSON.parse(text[, reviver])

 

 参数

 text  需要转换的JSON(字符串)
 reviver

 参数: 属性名, 属性值

 返回: 转换后的属性值

 

 

   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
 ES6的相关扩张
   
 动态生成属性名

 

{ [式子]: value }

 

 若式子是Symbol则直接用, 否则转换为字符串

 例:

let o3 = {
  [100+1*23+23/18]: 1
}
console.log(o3); // => {124.27777777777777: 1}

 

 属性定义的简写  
{ prop } // 属性名是变量名, 属性值是变量值

 例:

let kkk = o3;
let o4 = {
  a: 1,
  o3,
  kkk,
  b: 2
};
console.log(o4); // => {a: 1, o3: {…}, kkk: {…}, b: 2}

  

 方法定义的简写

 

{ method() {} }

 例:

let o5 = {
  show(name) { console.log(`the name is: ${name}`); }
}

 

 和 函数名: function () {} 的区别

 · 不能作为构造函数来用(没有prototype属性, 无法用new生成实例)

 · 内部可以用 super 

 generator的简写

 

{ * generator() {} }

 

# TODO: 完成这里

   

推荐阅读