资讯专栏INFORMATION COLUMN

深入了解js对象

cheukyin / 2457人阅读

摘要:通过创建的对象运算符创建并初始化一个新对象,关键字后跟随一个函数调用,这里的函数称作构造函数,构造函数用以初始化一个新创建的对象。

该文章以收录: 《JavaScript深入探索之路》 前言

对象是Javascript 的基本类型。对象是一种复合值,它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值。对象也可看做是属性的无序集合。每个属性都是一个名/值对。JavaScript对象还可以从一个称为原型的对象继承属性。

需要注意的是ES6中对对象也做了一些扩展,本文章并没有特别说明,如果你想了解,可以看看阮老师的ES6书籍。

我们可以把对象的属性分为三大类

内置对象:是有ECMAScript规范定义的对象或类。例如数组、函数、日期和正则表达式都是内置对象。

宿主对象: 是由JavaScript 解析器所嵌入的宿主环境,客户端JavaScript 中表示网页结构的HTMLElement对像均是宿主对象。宿主对象也可以当成内置对象。

自定义对象:是由运行中的JavaScript 代码创建的对象。

另外还有两类属性

自有属性: 是直接在队形中定义的属性

继承属性: 是在对象的原型对象中定义的属性

创建对象 1.对象字面量(也称为对象直接量)

创建对象最简单的方式就是在JavaScripot代码中使用对象直接量。

let obj = {
    name: "web",
    age: 23,
    sex: "man"
}

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

2.通过new创建的对象

new运算符创建并初始化一个新对象,关键字new 后跟随一个函数调用,这里的函数称作构造函数,构造函数用以初始化一个新创建的对象。JavaScript语言核心中的原始类型都包含内置构造函数。

let obj = new fun();
let ary = new Array();

另外我们需要知道使用new创建的构造函数时没有原型的,但是他们最终都会继承Object.prototype

let ary = new Array();
ary.prototype // undefind
3.Object.create()方法创建对象

Object.create() 该方法创建一个新对象,它有两个参数,第一个参数是这个对象的原型。第二个参数用以对对象的属性进行进一步描述。Object.create() 是一个静态函数,而不是提供给某个对象调用的方法。

let o = {
    name: "jhon",
    age: 23
}
let obj = Object.create(o);

obj.name // jhon
obj.__proto__ === o // true obj的原型链指向对象 o
obj.name === o.name // true

它的第二个参数是对属性的一些数值,下面我们会讲到,对对象属性特征的一些设置

对象的属性操作 1.查询

对象属性的查询我们有可以使用.运算符、[]运算符或者使用ES6提供的Reflect.get() 方法

let o = {
        name: "jhon",
        age: 23
    }

console.log(o.name) // "jhon"
console.log(o["name"])  // "jhon"
console.log(Reflect.get(o, "name"))  // "jhon"

对于[]来说,方括号内必须是一个计算结果为字符串的表达式(也可以直接是字符串),一般我们用来获取动态的属性。另外我这里不在讲解ES6的东西,想了解ES6,可以看看阮一峰老师关于es6基础的书籍。

2.删除

delete 操作符可以删除属性,它的操作数应当是一个属性访问表达式,delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。

let o = {
    name: "jhon",
    age: 23,
    other: {
        address: "HangHai",
    },
}

var obj = o.name;

delete o.name

console.log(o.name) // underfind
console.log(obj) // "jhon"

另外delete运算符只能删除自有属性,不能删除继承属性,它也不能删除某些属性配置为false的属性。还有全局函数和var声明的变量也是不能删除的。

3.继承

属性是可以继承的,JavaScript对象具有“自有属性”,也有一些是从原型对象上继承的属性。例如函数的toString()方法我们继承自Object的原型。

4.检测

检测属性的归属我们可以使用in运算符, hasOwnPreperty()protertyIsEnumerable() 方法。

let o = {
    name: "jhon",
    age: 23,
    other: {
        address: "HangHai",
    },
}

//使用 in 操作符来判读属性是否是该对象的自有属性
// 或继承的属性

console.log("name" in o) // true
console.log("toString" in o) // true

//hasOwnProperty()判读属性是否是该对象的自有属性

console.log(o.hasOwnProperty("name")) // true
console.log(o.hasOwnProperty("toString")) // false

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

// toString 是不可枚举的属性
console.log(o.propertyIsEnumerable("toString")) // false
5.枚举属性

我们可以使用for/in 遍历(枚举) 属性,我们可以使用以下方法来遍历对象的自有属性

 let o = {
    name: "jhon",
    age: 23,
    other: {
        address: "HangHai",
    },
}

let obj = {}

for (prop in o){
  if(o.hasOwnProperty[prop]) continue;
  obj[prop] = o[prop];
}
6.属性的set和get

在ECMAScrit5中属性值是可以用一个或两个方法替代,这两个方法就是gettersetter,由getter和setter定义的属性称做“存取器属性”,它不同于“数据属性”。

当程序查询存取器属性的值时,JavaScript调用getter方法(无参数)。这个方法的返回值就是属性存去表达式的值,当程序设置一个存去器属性的值时,JavaScript调用setter方法,将赋值表达式右侧的值当做参数传入setter。

和数据属性不同的是,存取器属性不具有可写性。如果属性同时具有getter和setter方法,那它是一个读/写属性,如果它只有getter方法,那么他是一个只读属性,如果它只有setter方法,那么他是一个只写属性。

定义存取器属性的最简单方法是使用对象直接量的语法:

let o = {
    name: "jhon",
    age: 23,
    get g(){
        console.log("您已经拿到年龄")
        return this.age + 10;
    },
    set g(value){
        console.log("您设置的年龄为: "+ this.age)
    },

} 

console.log(o)
o.g  // 您已经拿到年龄
o.g = 10  // 您设置的年龄为: 23
属性的几个特征

属性除了名字和值之外,还包含一些表示他们可写、可枚举、可配置的特性。

数据属性特性包括:

value

可写性 writable 默认 true

可枚举性 enumerable 默认 true

可配置性 configurable 默认 true

存取器属性特性包括:

读取 get

写入 set

可没举性 enumerable

可配置性 configurable

为了实现属性特性的查询和设置操作,ECMAScript5 定义了一个名为 “属性描述符”的对象

defineProperty() 设置某个属性的特性

let obj = {
    name: "jhon",
    age: 23,
}
Object.defineProperty(obj,"name",{
    value: "King", // 改写默认值
    writable: false,  // 不可修改属性值
    enumerable: true, // 可枚举该属性
    configurable: true // 可配置该属性

})    

console.log(obj.name); // "King"
obj.name = "Tom"; // 改写不会成功
console.log( obj.name); // "King"

我们也可以设置器存取属性特性:

let obj = {
    name: "jhon",
    age: 23,
}
// 我们将name设置成存取属性器
Object.defineProperty(obj,"name",{
    get: function(){
    return "更改为存取属性器"
    },
    enumerable: true, // 可枚举该属性
    configurable: true // 可配置该属性

})    

console.log(obj.name);

definePeoperties() 设置多个属性的特性

我们可以使用 definePeoperties()来对多个属性的特性进行设置

let obj = {
         name: "jhon",
         age: 23,
}
Object.defineProperties(obj,{
    name:{
    get: function(){
    return "更改为存取属性器"
    },
    enumerable: true, // 可枚举该属性
    configurable: true // 可配置该属性
    },
    age:{
        writable: false, // 禁止改写age
    }

})    

console.log(obj.name); //更改为存取属性器

obj.age = 10;
console.log(obj.age) // 23

getOwnpropertyDescriptor() 获取某个对象自有属性的属性描述

let obj = {
    name:"jhon"
}

let descriptor = Object.getOwnPropertyDescriptor(obj,"name");

// Object {value: "jhon", writable: true, enumerable: true, configurable: true}
console.log(descriptor)
对象的三个属性 1.原型属性

对象的原型属性是用来继承属性的,原型属性实例创建之初就设置好了,通过对象直接量创建的对象使用对象 Object.prototype 作为他们的原型,通过new创建的对象,使用构造函数prototype属性作为它们的原型,通过Object.create() 创建的对象使用第一个参数(也可以是null)作为他们的原型

在ECMAScript5中,将对象作为参数传入Object.getPrototypeOf() 可以查看他的原型。

let obja = {
 name:"jhon"
}

let proto = Object.getPrototypeOf(obja);
console.log(proto) // 返回Objcet的原型

如果想要检测一个对象是否是另一个对象的原型(或处于原型链中),可以使用isPrototypeOf() 方法。

     
function fun(name){
    this.name = name
}

fun.prototype = function(){
    console.log("原型")
}

let newFun = new fun("jhon");

// true
console.log(fun.prototype.isPrototypeOf(newFun))

// 另外我们还可以通过 instanceof 来检测一个对象是否是另一个对象的实例

console.log( newFun instanceof  fun) // true
2.类属性

对象的雷属性是一个字符串,用以表示对象的类型信息,我们可以通过一种间接的方法查询它。
默认的 toString() 方法(继承自Object.prototype) 返回这种格式的字符串:[object class]

我们可以通过 Object.prototype.toString.call() 来检测对象的class

function fun (){

}

let className = Object.prototype.toString.call(fun);

console.log(className) // [object Function]
3.可扩展性

对象的可扩展性用以表示是否可以给对象添加新属相,所有内置对象和自定义对象都是显式可扩展的。
这里我们可以通过 Object.esExtensible(),来判断该对象是否可扩展的。

let obj = {
    name: "jhon",
    age: 23,
}

// true  对象obj默认是可扩展的
console.log(Object.isExtensible(obj))

如果想将对象转换为不可扩展的,可以使用 Object.preventExtensions()

let obj = {
        name: "jhon",
        age: 23,
    }

Object.preventExtensions(obj);

obj.address = "BeiJing"

console.log(obj) // obj并没有多出一个address属性
console.log(Object.isExtensible(obj)) // false

注意一旦将对象转换为不可扩展的,就无法在将其转换回可扩展的了。

如果想将对象转换为不可扩展的,并且对象的所有自有属性都设置为不可配置(也就是封闭对象),可以使用 Object.seal()
判读封闭对象可以使用Object.isSealed()

如果想将对象转换为不可扩展的,对象的所有自有属性都设置为不可配置并且是只读(也就是冻结对象),可以使用 Object.frozen(), 如果对象的存取器属性具有setter方法,存取器属性将不受影响。 使用Object.isFrozen() 来检测对象是否冻结。

Object.preventExtensions()Object.seal()Object.frozen()都返回传入的对象。

对象的方法

所用的JavaScript对象都从Objcet.prototype继承属性(除了那些不通过原型显示创建的对象),以下这些方法我不在详细介绍,因为他们还是比较常用的。

1.toString() 方法

2.toLocaleString() 方法

它仅仅调用了 toString() 方法并返回对应值,DateNumber 类对该方法做了定制。

3.toJson() 方法

Objcet.prototype实际上没有定义toJson() 方法,但对于需要执行序列化的对象来说,JSON.stringify()方法会调用该方法。

4.valueOf 方法

当JavaScript需要将对象转换为某种原始值而非字符串的时候才会调用它。

结束

参考书籍:《JavaScript权威指南》

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89882.html

相关文章

  • 深入理解JavaScript

    摘要:深入之继承的多种方式和优缺点深入系列第十五篇,讲解各种继承方式和优缺点。对于解释型语言例如来说,通过词法分析语法分析语法树,就可以开始解释执行了。 JavaScript深入之继承的多种方式和优缺点 JavaScript深入系列第十五篇,讲解JavaScript各种继承方式和优缺点。 写在前面 本文讲解JavaScript各种继承方式和优缺点。 但是注意: 这篇文章更像是笔记,哎,再让我...

    myeveryheart 评论0 收藏0
  • JavaScript 异步

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。写一个符合规范并可配合使用的写一个符合规范并可配合使用的理解的工作原理采用回调函数来处理异步编程。 JavaScript怎么使用循环代替(异步)递归 问题描述 在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过...

    tuniutech 评论0 收藏0
  • 深入了解 Number 类型

    摘要:下面就让我们来一起深入了解下,为以后的策马奔腾做好铺垫。整数整数,可以通过十进制,八进制,十六进制的字面值来表示。对前面定义的八进制和十六进制数值进行运算浮点数浮点数其实就是我们通常所说的小数,所以一定有个小数点。 Number 类型作为 JS 的基本数据类型之一,被应用在程序中的各种场景,其重要性就如数字对于我们日常生活。下面就让我们来一起深入了解下,为以后的策马奔腾做好铺垫。 定义...

    scwang90 评论0 收藏0
  • 深入js隐式类型转换

    摘要:结合实际中的情况来看,有意或无意中涉及到隐式类型转换的情况还是很多的。此外当进行某些操作时,变量可以进行类型转换,我们主动进行的就是显式类型转换,另一种就是隐式类型转换了。 前言 相信刚开始了解js的时候,都会遇到 2 ==2,但 1+2 == 1+2为false的情况。这时候应该会是一脸懵逼的状态,不得不感慨js弱类型的灵活让人发指,隐式类型转换就是这么猝不及防。结合实际中的情况来看...

    tomato 评论0 收藏0
  • javascript知识点

    摘要:模块化是随着前端技术的发展,前端代码爆炸式增长后,工程化所采取的必然措施。目前模块化的思想分为和。特别指出,事件不等同于异步,回调也不等同于异步。将会讨论安全的类型检测惰性载入函数冻结对象定时器等话题。 Vue.js 前后端同构方案之准备篇——代码优化 目前 Vue.js 的火爆不亚于当初的 React,本人对写代码有洁癖,代码也是艺术。此篇是准备篇,工欲善其事,必先利其器。我们先在代...

    Karrdy 评论0 收藏0
  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0

发表评论

0条评论

cheukyin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<