对象(Object)

... 2022-12-19 About 6 min

# 对象(Object)

# 对象方法

# 本身的方法

Object.print = function (o) { console.log(o); }; 这种直接加在对象上的就是对象本身的方法,不可以被实例的对象调用

# 实例方法

所谓实例方法就是定义在对象Object.prototype上的方法,它可以被Object实例直接使用

Object.print1 = function () {
  console.log(00)
}
Object.print = function () {
  console.log(11)
}
Object.prototype.print = function () {
  console.log(22)
}
let obj = new Object()
obj.print() // 22
obj.print1() // Error
1
2
3
4
5
6
7
8
9
10
11
12

# Object对象的相关方法

# 1. Object.getPrototypeOf()

返回参数对象的原型

let F = function () {};
let f = new F();
Object.getPrototypeOf(f) === F.prototype // true

// 有一些特殊的情况
// 空对象的原型是 Object.prototype
Object.getPrototypeOf({}) === Object.prototype // true

// Object.prototype 的原型是 null
Object.getPrototypeOf(Object.prototype) === null // true

// 函数的原型是 Function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2. Object.setPrototypeOf()

该方法可以为参数对象设置原型,返回该参数对象,第一个参数是已有的对象,第二个参数是原型对象

let a = {};
let b = {x: 1};
Object.setPrototypeOf(a, b);

Object.getPrototypeOf(a) === b // true
a.x // 1
// new命名除了之前的那种写法,也可使用这个属性
let F = function() {}
let f = Object.setPrototypeOf({}, F.prototype)
f.call(F)
1
2
3
4
5
6
7
8
9
10

# 3. Object.create()

生成实例对象的方法是,使用new命令让构造函数返回一个实例。但是很多时候,只能拿到一个实例对象,他可能根本不是有构造函数生成,那么能不能从一个实例对象生成另一个实例对象呢?答案肯定是有的,没有的话,我也不会说了

JavaScript提供了Object.create方法,用来满足这种需求,该方法接收一个对象作为参数,然后以他为原型,返回一个实例对象,该实例完全继承原型对象的属性

let A = {
  console:function(){
    console.log('hahahh')
  }
}

let B = Object.create(A)

Object.getPrototypeOf(B) === A // true

B.console() // hahhahh
B.console === A.console // true

1
2
3
4
5
6
7
8
9
10
11
12
13

可以看出Object.create()是以A对象为原型,生成了B对象,B继承了A所有的属性和方法

可以看一下Object.create()方法的实现

if (typeof Object.create !== 'function'){
  Object.create = function (obj){
    function F () {}
    F.prototype = obj
    return new F()
  }
}
1
2
3
4
5
6
7

从上面可以看出实质是利用构造函数返回了一个实例

ps:如果想要生成一个不继承任何属性(比如没有toString和valueOf方法)的对象,可以将Object.create的参数设为null。

下面的三种方法是一样的

let obj = Object.create()
let obj = Object.create({})
let obj = Object.create(Object.prototype)
1
2
3

# 4.Object.prototype.isPrototypeOf()

看名字就知道这个方法是用来检测某个对象是不是另一个对象的原型 两种情况

  1. ----->
let o1 = {}
let o2 = Object.create(o1)
let o3 = Object.create(o2)

o1.isPrototypeOF(o3) // true
o2.isPrototypeOF(o3) // true
1
2
3
4
5
6

可以看出可以传递的,o1和o2都是o3的原型。这表明只要实例对象处在参数对象的原型链上,isPrototypeOf方法都返回true 2. ----->

Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false
1
2
3
4

由于Object.prototype处于原型链的最顶端,所以对各种实例都返回true,只有直接继承自null的对象除外。

# 5.Object.prototype.proto (私有属性)

这个地方吧,我个人觉得搞清楚__proto__和prototype是针对谁而言就好了,__proto__是对象上面操作,而prototype是构造函数上面操作,虽然这样说会有漏洞

根据语言标准,__proto__属性只有浏览器才需要部署,其他环境可以没有这个属性。它前后的两根下划线,表明它本质是一个内部属性,不应该对使用者暴露。因此,应该尽量少用这个属性,而是用Object.getPrototypeOf()和Object.setPrototypeOf(),进行原型对象的读写操作。

# 6.Object.getOwnPropertyNames()

Object.getOwnPropertyNames方法返回一个数组,成员是参数对象本身的所有属性的键名,不包含继承的属性键名。

Object.getOwnPropertyNames(Date)
// ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"] 
// 是本上的所有属性的键名
1
2
3

# 7.Object.prototype.hasOwnProperty()

对象实例的hasOwnProperty方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。

Date.hasOwnProperty('length') // true
Date.hasOwnProperty('toString') // false
1
2

上面代码表明,Date.length(构造函数Date可以接受多少个参数)是Date自身的属性,Date.toString是继承的属性。

另外,hasOwnProperty方法是 JavaScript 之中唯一一个处理对象属性时,不会遍历原型链的方法。

# 8.对象的拷贝

如果要拷贝一个对象,需要做到下面的两件事情

  1. 确保拷贝后的对象,与原对象具有相同的原型
  2. 确保拷贝后的对象,与原对象具有相同的属性

基于这两点造就完了

function copyObj(oriObj){
var copy = Object.create(Object.getPrototypeOf(oriObj))
  copyOwnPro(copy, oriObj)
  return copy
}
function copyOwnPro (target,source){
  Object.getOwnPropertyNames(source).forEach(function(item){
   var desc = Object.getOwnPropertyDescriptor(source, propKey);
      Object.defineProperty(target, item, desc);
  })
  return target
}
1
2
3
4
5
6
7
8
9
10
11
12

# 构造函数

值得注意的是,通过let obj = new Object()的写法生成新对象,与字面量的写法let obj = {}是等价的。或者说,后者只是前者的一种简便写法。

let o1 = {a: 1};
let o2 = new Object(o1);
o1 === o2 // true
let obj = new Object(123);
obj instanceof Number // true
// Object(value)与new Object(value)两者的语义是不同的,Object(value)表示将value转成一个对象,new Object(value)则表示新生成一个对象,它的值是value。
1
2
3
4
5
6

# 静态方法

  • Object.keys() (在平常开发中用的还是比较多的)
  • Object.getOwnPropertyNames()----这哥们通常来讲会比Object.keys()多一个length,我一般都是用Object.keys()遍历对象属性
// 需求打开一个地址参数是
let obj = {
name: 'salvatore',
id: 'adfhlw452345lahfa1234lha0per8f7',
type: 'new',
area: 'ss'
}
// 这种也可以,但是对于维护起来不是很好,如果加一个字段还要改两个地方,这个时候用Object.keys()
window.open(`/?name=${obj.name}&id=${obj.id}&type=${obj.type}&area=${obj.area}`)
let path = ''
Object.keys(obj).forEach(item => {
path += (path ? `&` : `/?`) + `${item}=${obj[item]}`
})
console.log(path) //---> /?name=salvatore&id=adfhlw452345lahfa1234lha0per8f7&type=new&area=ss
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 其他方法

# 1. 对象属性模型的相关方法

  • Object.getOwnPropertyDescriptor():获取某个属性的描述对象。
  • Object.defineProperty():通过描述对象,定义某个属性。
  • Object.defineProperties():通过描述对象,定义多个属性。

# 2. 控制对象状态的方法

  • Object.preventExtensions():防止对象扩展。
  • Object.isExtensible():判断对象是否可扩展。
  • Object.seal():禁止对象配置。
  • Object.isSealed():判断一个对象是否可配置。
  • Object.freeze():冻结一个对象。
  • Object.isFrozen():判断一个对象是否被冻结。

# 3. 原型链相关方法

  • Object.create():该方法可以指定原型对象和属性,返回一个新的对象。
  • Object.getPrototypeOf():获取对象的Prototype对象。
// 以上这些方法我就用过Object.defineProperty(),其他的我都还没有用过,但Object.freeze()这样的还是用听过的看过的,没有过用过的
// Object.defineProperty()这哥们是做数据双向绑定的基本原理上,上代码
let input = document.getElementById('input')
let span = document.getElementById('span')
let obj = {}
Object.defineProperty(obj, 'text', {
  set(val){
    input.value = val
    span.innerHTML = val
  }
})
input.addEventListener('keyup',(event) => {
  obj.text = event.target.value
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<input id="input">
<span id="span"></span>
1
2

# Object的实例方法

  • Object.prototype.valueOf():返回当前对象对应的值。
  • Object.prototype.toString():返回当前对象对应的字符串形式。
  • Object.prototype.toLocaleString():返回当前对象对应的本地字符串形式。
  • Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。
  • Object.prototype.isPrototypeOf():判断当前对象是否为另一个对象的原型。
  • Object.prototype.propertyIsEnumerable():判断某个属性是否可枚举。
  • 说两个我用的比较多的属性直接上代码
function getType (type) {
  return Object.prototype.toString.call(type).match(/\[object, (.*?)\]/)[1].toLowerCase()
}
type({}); // "object"
type([]); // "array"
type(5); // "number"
type(null); // "null"
type(); // "undefined"
type(/abcd/); // "regex"
type(new Date()); // "date"

let typeFixed = {}
const arr = ['Null', 'Undefined', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'RegExp']
arr.forEach(item => {
  typeFixed[`is${item}`] = function (type) {
    return getType(type) === item.toLowerCase()
  }
})

typeFixed.isObject({}) // true
type.isNumber(NaN) // true
type.isRegExp(/abc/) // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let obj = {
  p: 123
};
obj.hasOwnProperty('p') // true
obj.hasOwnProperty('toString') // false
// Object.prototype.hasOwnProperty方法接受一个字符串作为参数,返回一个布尔值,表示该实例对象自身是否具有该属性。
1
2
3
4
5
6
Last update: December 19, 2022 11:58
Contributors: salvatoreliaoxuan , liaoxuan