JavaScript 深入对象方法之 静态方法

245 阅读8分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情

对象是我们在使用 JavaScript 中最常用的数据类型之一了,JavaScript 中 有一个万物皆对象的概念,就是我们使用各种类型的时候,都可以使用 点语法访问其原型属性和原型方法,而了解对象的静态方法 和 实例属性及方法 有助于我们更好的在业务中去处理各种场景,今天我们主要来了解一下静态方法~

  • 首先我们要知道对象的构造函数是 Object ,什么是静态方法? 我们用一个小 demo 来看一下
// 我们可以使用 class 来构造函数, 也叫生成一个类, 这个类拥有 实例方法,实例属性,静态方法
class Demo{
  constructor(){
    // 实例属性
    this.a = 100
  }
  show(res){
    console.log('实例方法执行',res);
  }
  static olny(res){
    console.log('静态方法执行',res);
  }
}
const app = new Demo()
// 实例属性
console.log(app.a);
// 实例方法
app.show(123)
// 静态方法
Demo.olny(31)
// 用过原型访问 实例方法
Demo.prototype.show("执行")

就像上面的, 我们使用构造函数的 static 来设置静态方法,静态方法无法使用实例来访问,只能使用 类来访问这一种方式~, 下面我们来看 Object 的静态方法.

Object.keys()

返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。

  • 这个方法我们经常用来遍历对象,用来得到对象的 key 组成的一个数组,然后遍历这个 key,就相当于遍历一个对象的所有可枚举属性~

Object.values()

返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for...in 循环的顺序相同(区别在于 for-in 循环枚举原型链中的属性)。

  • 这个方法我们用来获取一个对象上所有的 值组成的一个数组,也可以获取数组的

Snipaste_2022-12-06_19-24-50.png

Object.assign()

Object.assign()  方法将所有可枚举Object.propertyIsEnumerable() 返回 true)的自有Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。

  • 上面的概念我们可能不是很理解,但是我们只需要知道, 这个方法是将一个对象 赋值或者叫克隆到另一个对象上而已,但不是深拷贝,也就是说对象中的对象是拷贝的地址,需要注意的一点就是,我们参数后面出现了和参数前面对象中重合的key,则后面会覆盖前面的,让我们来演示一下:
let obj1 = {a:1,c:1}
let obj2 = {b:2,d:{s:5}}
let obj3 = {c:3}
let obj = Object.assign({},obj1,obj2,obj3)
obj.a = 10
obj.d.s = 50
console.log(obj1);
console.log(obj2);
console.log(obj3);
console.log(obj);

上面的案例中,我们分别浅克隆了 obj1,2,3 我们修改浅克隆以后的值,不影响之前的,但如果修改的是浅克隆中的对象,就会影响对象引用中的值,打印如下:

Snipaste_2022-12-06_17-09-29.png
一般在业务中应用到需要浅克隆或者覆盖原对象的场景

Object.create()

用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。

  • 我们在创建对象的时候,都是使用 字面量的方式 直接新建一个对象,基本都不会使用这种方式来创建对象,那么这种方式和我们使用字面量方式有什么区别的? 这种方式新建的对象,我们传入的 参数对象,会作为新对象的原型,也就是 prototype.
let obj = {a:1,fn(res){console.log('执行',res);}}
let obj1 = Object.create(obj)
obj1.a // 1
obj1.fn(123) // fn执行
// 这里我们的 obj1 还是 一个空对象

那么我们可以用这个方法干嘛呢? 可以继承原型,也就是我们类的 prototype , 我们第一个示例中有一个 Demo 那我们就可以使用 obj = Object.create(Demo.prototype) 这时候我们得到的 obj 就拥有了这个 Demo 类的原型属性和方法,在我们实际开发中很少使用。

Object.defineProperty()

Object.defineProperty()  方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

  • 这个方法可就有意思了,可能大家看到这个方法都会眼熟,甚至熟悉,没错,这个就是 vue2 中使用的响应式,那么咱们先来了解一下他的三个参数,(obj, prop, descriptor),第一个参数是我们要定义属性的对象,第二个参数是要定义或者修改属性的名称,第三个参数是这个属性的描述,这个第三个参数就是响应式的关键了,他有两种描述方式,一种是带 gettersetter 的 一种是不带 gettersetter 的。
var obj={};
Object.defineProperty(obj,"a",{
    enumerable:true, // 是否可枚举
    configurable:true, // 是否可删除
    writable:true,  // 是否可更改
    value:1, // 值
})

// 如果使用了 set 和 get 则不能使用 value 和 writable
Object.defineProperty(obj,"b",{
    enumerable:true,
    configurable:true,
    set:function(v){
    
    },
    get:function(){

    }
})

这里我们就不详尽的去讨论他的内部了, 因为这个方法扩展开来,要说的东西实在是太多了,大家想了解可以直接去 developer.mozilla.org/zh-CN/docs/… 官方 去看一下即可, 还有一个方法是 Object.defineProperties() , 只是批量向对象中添加而已。

Object.getOwnPropertyDescriptor()

返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

  • 这个放个和我们上面的 设置描述对象是一对,一个是设置 一个是获取,包含两个参数,第一个是目标对象,第二个是需要获取的值

Object.getOwnPropertyDescriptors()

获取一个对象的所有自身属性的描述符,只能获取到所有字符串属性的描述对象。

Object.getOwnPropertyNames()

返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。

Object.getOwnPropertySymbols()

返回一个给定对象自身的所有 Symbol 属性的数组。

  • 使用上面这两个获取的方法组合,可以用来获取全部的对象自身属性
// obj 就是我们的源对象
var arr=Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj));

Object.entries()

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。

  • 这个方法就是返回一个 对象的 keyvalue 成对的一个数组, 平时在业务当中应用的场景不多,但我在使用 map 结构的时候,进行结构的转换会经常用到~ 因为我们使用entries 得到的是 一个迭代器对象,下面食用代码:
var obj={a:1,b:2};
//将对象转换为迭代对象
console.log(Object.entries(obj))
// 以对象产生一个map对象
var m=new Map(Object.entries(obj));
console.log(m)

那么为什么得到的是一个迭代对象呢?我们可以看一下打印,在其原型上我们能找到迭代器接口,因为是数组啦,所以有迭代器接口哈哈~ Snipaste_2022-12-06_18-31-42.png

Object.freeze() Object.isFrozen()

Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze()返回和传入的参数相同的对象。

// 冻结(不能删除,不能修改属性,并且不能扩展属性)
var obj={a:1,b:2};
Object.freeze(obj);
// 判断对象是否被冻结
console.log(Object.isFrozen(obj))
var arr=[1,2,3,4];
Object.freeze(arr);
obj.a=10;
arr[0]=10;
console.log(arr)
// 枚举类型
const COLOR={RED:"red",GREEN:"green",BLUE:"blue"};
Object.freeze(COLOR);
COLOR.RED=1;

我们一般也不会使用这个方法,但要是使用,只能是不被修改的场景,如枚举类型这种

Object.getPrototypeOf()

返回指定对象的原型(内部[[Prototype]]属性的值)。

  • 一个参数,返回的就是这个对象的原型,我们可以看一下用来获取 数组原型是啥样的

Snipaste_2022-12-06_18-59-46.png

Object.is()

判断两个值是否为同一个值

Snipaste_2022-12-06_19-01-20.png

Object.preventExtensions()

让一个对象变的不可扩展,也就是永远不能再添加新的属性, 但是可以删除,修改。

Object.isExtensible()

判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。

  • 这个方法和 上面的方法显然是一对的, 也很好理解,让我看简单看一下代码~
// 可以删除,可以修改属性,但是不能扩展
var obj={a:1,b:2};
Object.preventExtensions(obj);
Object.isExtensible(obj);//是否可以扩展
obj.a=10;
delete obj.a;
obj.c=10;
console.log(obj)

Object.seal()

封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。他和 freeze 冻结的区别是,冻结的对象不可改变, 而 封闭的对象是可以改变的。

Object.isSealed()

判断一个对象是否被密封。

  • 这个方法和上面的方法是一对,我们来看看代码~
// 不删删除,不能扩展,但是可以修改属性的值
var obj={a:1,b:2};
Object.seal(obj);
// 判断是否通过seal设置过
console.log(Object.isSealed(obj))
obj.c=3;
delete obj.a;
obj.a=10;
console.log(obj)