文章目录

  • 对象
    • 什么是对象
      • 创建一个对象
      • 使用对象
    • 对象进阶
      • 被忽视的属性(特性)
        • 1. 数据属性:包含一个数据值的位置。在这个位置可以进行读取和写入
        • 尝试下修改这些值会发现什么变化?
        • 2. 访问器属性
    • Object原型上的方法
    • 设计一个对象
    • 参考链接

对象

每一个语言最重要与最基础的数据结构非对象莫属,因为可以通过它实现其他任何数据结构。

什么是对象

在JS语言中,对象的定义未:无序属性的集合,其属性可以包含基本值、对象或者函数,换句话说,就是对象里包含许多属性,这些属性通过映射可以指向任何类型的值。

创建一个对象

  1. 通过实例Object来创建一个对象
var o = new Object()
o.name = 'Rex'
o.age = 23
o.getName = function(){return this.name
}
  1. 通过对象字面量来创建一个对象
var rexDate = {name:'rex',age:23,getName:function(){return this.name}
}

使用对象

JS有2种方法来进行访问对象

  1. 第一种是通过.来进行访问

这个是具有声明变量的功能,如果访问的是对象不存在的属性的时候,返回的是undefined,但是它只是存在于你调用的时候,在你调用完之后,由于JS的垃圾回收机制就会将这个内存进行删除,所以不用担心内存泄漏。这里说一句只是为了区别与我们直接输出声明过的变量是会直接报错的。

var rexDate = {name:'rex',age:23,getName:function(){return this.name}
}
console.log(rexDate.age)// 23
console.log(rexDate.getName())// rex
  1. 第二种是通过[]来进行访问
var rexDate = {name:'rex',age:23,getName:function(){return this.name}
}
console.log(rexDate['age'])// 23
console.log(rexDate['getName']())// rex

当然不推荐这样访问对象,这样不仅写起来麻烦阅读性差,并且每一个属性名字都需要加''字符串进行访问,实在太不人性了。
熟悉数组的同学很快就会发现这就是array的访问的方法,所以也可以侧面看出来数组其实本质就是对象,只不过编译器进行封装,我们可以非常方便实用数组。


对象进阶

我们简单熟悉对象之后,也要认识下一些对象底层的一些方法。无论你通过什么方式进行声明对象,最终的实例都会继承Object的原型链上的属性和方法。这里我们就来认识下这些必然会存在的方法和属性(特性)吧!

被忽视的属性(特性)

1. 数据属性:包含一个数据值的位置。在这个位置可以进行读取和写入

  • Configurable属性能否被delete删除,能否被修改特性或者能否把属性修改为访问器的属性。
    稍微解释下,delete是人自行删除释放内存的方法之一,如果设置为false则无法被这个方法删除。而后者则是无法进行修改其他特性和访问器都不能进行设置。这里简单可以理解为属性的权限。
  • Enumerable属性,顾名思义可枚举的,就是设置是否能够被for-in进行枚举
  • Writable属性,就是能否被修改。
  • Value属性,保存的就是属性的值本身——数据值。如果我们只是声明没有进行赋值,则为undefined
    我们直接来测试下吧,文字始终是难记住的,通过例子来强化下记忆!
    我们在声明属性的时候如何同时设置这些属性值,我们不进行任何操作时候他们的默认值是多少?
    通过Object.getOwnPropertyDescriptor(obj, prop)来获取属性配置
var rexDate = {}
rexDate.name = 'rex'
console.log(Object.getOwnPropertyDescriptor(rexDate, 'name'))

输出情况

{ value: 'rex',writable: true,enumerable: true,configurable: true }

默认情况下,数据属性都是TRUEValue就是数值。
我们继续看下函数的Value是如何保存的?

var rexDate = {}rexDate.getName = function() {console.log('rex')
};
console.log(Object.getOwnPropertyDescriptor(rexDate, 'getName'))
Object.getOwnPropertyDescriptor(rexDate, 'getName').value()
{ value: [Function],writable: true,enumerable: true,configurable: true }
rex

我们通过访问value直接执行是可以正确返回的,所以value同样是保存数据值的。

尝试下修改这些值会发现什么变化?

通过Object.defineProperty(obj, prop, descriptor)来获取属性配置

  • Configurablefalse时。
var rexDate = {}
Object.defineProperty(rexDate, 'name',{enumerable: true,configurable: false,writable: true,value: "rex"
})
delete rexDate.name
console.log(rexDate.name)
rexDate.name ='Rex'
delete rexDate.name
console.log(rexDate.name)

输出

rex
Rex

无法成功删除,可以修改value,除了configurable之外都是可以重新设置的。
如果我们设置了configurablefalse,如果重新设置为true会报错。

var rexDate = {}Object.defineProperty(rexDate, 'name',{enumerable: true,configurable: false,writable: true,value: "rex"
})
Object.defineProperty(rexDate, 'name',{enumerable: true,configurable: true,writable: true,value: "rex"
})

  • enumerablefalse
var rexDate = {}Object.defineProperty(rexDate, 'name',{enumerable: true,configurable: true,writable: true,value: "rex"
})for(let i in rexDate) {console.log(i,rexDate[i])
}
Object.defineProperty(rexDate, 'name',{enumerable: false,configurable: true,writable: true,value: "rex"
})
for(let i in rexDate) {console.log(i,rexDate[i])
}
console.log('测试完成')

输出

name rex
测试完成

只输出了一行,所以设置了enumerable就无法被for-in遍历了。

  • writablefalse
var rexDate = {}Object.defineProperty(rexDate, 'name',{enumerable: true,configurable: true,writable: true,value: "rex"
})rexDate.name = "Rex"
console.log(rexDate.name)
Object.defineProperty(rexDate, 'name',{enumerable: true,configurable: true,writable: false,value: "rex"
})
rexDate.name = "Rex"
console.log(rexDate.name)
console.log('测试完成')

输出

Rex
rex
测试完成

设置了false之后,即使修改了也不会保存,但是修改无效。

2. 访问器属性

访问器属性熟悉的同学都知道这是VUE2实现双向绑定的方法,我们就用实现双向绑定来认识访问器属性吧

  • Configurable同上
  • Enumerable同上
  • Get这里设置当访问值时调用的函数。访问方法通过.或者[]
  • Set这里设置是当属性的value数据值发生变化的时候执行的函数。
    直接看例子
<!DOCTYPE HTML>
<html>
<head></head>
<body><input ></input><p id='data'></p>
</body>
<script>data ={}Object.defineProperty(data,'innerHtml',{get:function(v){return v},set:function (params) {var pNode = document.querySelector('#data')pNode.innerHTML=paramsinputNoed.value=params}})window.onload=function(){var inputNoed = document.querySelector('input')var pNode = document.querySelector('#data')data.innerHtml= '初始化数据'}// 添加input事件inputNoed.addEventListener('change',function(e){data.innerHtml = e.target.value})</script>
</html>

输出情况

这是一个非常简单的demo,vue会复杂很多,不过理解起来也不难。有了这个属性我们就可以通过给属性设置一些函数,让他们具有特殊的限制,比如我们抽奖的时候,累积抽奖可以提高中奖率,但是避免中奖率又不能超过一个数,在开发的时候,我们设置set让它赋值超过20的时候限制只返回20,这样可以防止后续开发者误操作让中奖率设置太高导致损失。

Object原型上的方法

我们这里列举一些比较通用和常见的。

  • Object.assign()通过复制一个或多个对象来创建一个新的对象。
    可以将多个对象进行合并为一个对象,不过这里是浅复制,如果出现相同名字的属性,则以最后一个对象中的重复属性的值为主。

只会拷贝源对象自身的并且可枚举的属性到目标对象,如果设置了enumerablefalse的话是无法复制的。

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };const returnedTarget = Object.assign(target, source);console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

我们通过绕下路,将属性中的对象变成字符串,在进行合并,合并之后将字符串变为对象,这样就可以实现深复制

面试的时候用这个回答会很加分。

// Deep Clone
obj1 = { a: 0 , b: { c: 0}};
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
  • Object.create()使用指定的原型对象和属性创建一个新对象。
var obj1 = {name :'rex'
}
var obj2 = Object.create(obj1)
console.log(obj2, obj2.name)
var obj3 = new Object(obj1)
console.log(obj3, obj3.name)

输出

{} 'rex'
{ name: 'rex' } 'rex'

create进行创建的方法并不是直接保存到返回的对象上的,而是保存到对象的prototype原型上,所以可以访问到name
等价于

var obj = function () {}
var test = {name:'rex'}
obj.prototype = test
var o = new obj()
console.log(o, o.name)
console.log(o.__proto__  === obj.prototype)
console.log(o instanceof obj)

输出情况

{} 'rex'
true
true

new Object()等价于

var obj = function () {this.name = 'rex'}
obj2 = new obj()
/*var o = new Object()var bindObj = obj.bind(o)bindObj()return o
*/
// 可以看看下面的代码输出什么var test = function () {this.name = 'rex'
}
var o = new Object()
var bindO = test.bind(o)
bindO()
console.log(o) // {name : 'rex'}

我们用一张图来解释下这里的区别

我们在寻找属性的时候,如果实例没有对应的属性,会通过访问prototype来继续访问,如果没有则继续访问prototypeprototype直到Object的原型上,如果没有则返回undefined
我们看下Object.create是如何进行创建的?

我们继续看new的过程

我们这里来证明下这个图

let obj = function (params) {this.name = 'rex'
}let o = new obj()
console.log(o.prototype == obj)
console.log(o.__proto__ == obj.prototype)
console.log(o.__proto__.constructor == obj)
console.log(o.constructor == obj)

输出

false
true
true

实例的__proto__的确指向这构造函数的原型,构造函数constructor这个属性保存的是构造函数本身,new过程中绑定的函数就是它,通过输出o.__proto__.constructor == obj可以清楚地看到,obj并不是原型本身,而是原型上构造函数constructor指向的函数,而构造函数本身存在一个prototype属性指向这原型。有点难理清楚,我们画张图表示下就明白了。

  • Object.defineProperty()设置属性和属性的配置,Object.defineProperties()是同时设置多个属性的配置

  • Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,这里可以阅读阮一峰的ES6教程里的遍历器

  • Object.fromEntries(iterable);参数有键值对的列表参数。

    map转对象

    const map = new Map([ ['foo', 'bar'], ['baz', 42] ]);
    console.log(map)// Map { 'foo' => 'bar', 'baz' => 42 }
    const obj = Object.fromEntries(map);
    console.log(obj); // { foo: "bar", baz: 42 }
    

    数组转对象

    const arr = [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ];
    console.log(arr) // [ [ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ]
    const obj = Object.fromEntries(arr);
    console.log(obj); // { 0: "a", 1: "b", 2: "c" }
    
  • Object.getPrototypeOf()在实例中,我们需要通过__proto__来访问实例的prototype,也可以使用这个方法获取实例的prototype

const prototype1 = {};
const object1 = Object.create(prototype1);
console.log(object1.__proto__ === prototype1);// true
console.log(Object.getPrototypeOf(object1) === prototype1);
// expected output: true
  • Object.freeze()方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。
    下面是ES6拓展的方法
  • Object.getOwnPropertyNames(obj)
    返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
  • Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身的所有 Symbol 属性的键名。
let obj = {name:'a',age:'b',[Symbol('123')]:123
}
console.log(Object.getOwnPropertyNames(obj))
console.log(Object.getOwnPropertySymbols(obj))

输出

[ 'name', 'age' ]
[ Symbol(123) ]
  • Object.setPrototypeOf设置prototype
Object.setPrototypeOf = function (obj, proto) {obj.__proto__ = proto;return obj;
}

设计一个对象

我们从上面可以了解到,通过构造函数可以给每一个实例添加属性和方法,实例也可以继承构造函数的原型对象,这2个唯一的区别就是前者每一个实例都是独立的,而后者每一个实例都是共享的。

function Person(name,age){this.name = namethis.age = age
}
Person.prototype.sayname= function(){console.log(this.name)
}
Person.prototype.sex = 'mela'
var p1 = new Person('rex',12)
var p2 = new Person('jone',23)
console.log(p1.sayname())// rex
console.log(p2.sayname())// rex
console.log(p2.sex,p1.sex )// mela mela
p1.sex = 'femela'
console.log(p2.sex,p1.sex )// femela femela

构造函数保存每个实例需要单独保存的方法。
原型保存所有实例的共享方法和属性。

参考链接

更多Object方法和详细内容请浏览MDN
《Javascript高级程序设计》

JavaScript 对象的创建与继承——创建篇相关推荐

  1. javascript小技巧amp;amp;JavaScript[对象.属性]集锦 [转载了多篇]

    因为这两篇太安逸了,东西很多,很实用,所以转到我格子里! 总的来说,如果你要找js 的东西,而不看这两篇的话,肯定要多花好多时间!!哈哈!! 如果你找的javascript的东西的话,建议你 ctrl ...

  2. javascript小技巧JavaScript[对象.属性]集锦 [转载了多篇]

    因为这两篇太安逸了,东西很多,很实用,所以转到我格子里! 总的来说,如果你要找js 的东西,而不看这两篇的话,肯定要多花好多时间!!哈哈!! 如果你找的javascript的东西的话,建议你 ctrl ...

  3. javascript 对象属性

    function Person(name, age) {this.name = first;this.age = age; } var father = new Person("wang&q ...

  4. Java程序员从笨鸟到菜鸟之(二十九)javascript对象的创建和继承实现

    JavaScript对象的创建 JavaScript中定义对象的几种方式(JavaScript中没有类的概念,只有对象): 1) 基于已有对象扩充其属性和方法:  [html] view plainc ...

  5. JavaScript对象的创建

    原文 简书原文:https://www.jianshu.com/p/6cb1e7b7e379 大纲 前言 1.简单方式创建对象的方法 2.工厂模式创建对象 3.构造函数模式创建对象 4.原型模式创建对 ...

  6. 【Infragistics教程】在javascript构造函数中创建基本继承

    2019独角兽企业重金招聘Python工程师标准>>> [下载Infragistics Ultimate最新版本] 用javascript创建对象有四种方法.具体如下: 对象作为文本 ...

  7. JavaScript对象的几种创建方式?

    **` JavaScript对象的几种创建方式? `**

  8. 创建JAVASCRIPT对象3种方法

    创建JAVASCRIPT对象3种方法 方法一:直接定义并创建对象实例 var obj = new Object();    //创建对象实例 //添加属性obj.num = 5;   //添加属性 o ...

  9. js 对象创建及其继承的方法

    重新看红皮书,觉得很多知识多看几遍确实是能看的更明白些.今天重温了一下对象创建和继承,就稍微记下来,巩固一下. js是面向对象的编程语言,ECMA-262吧对象定义为:"无序属性的集合,其属 ...

  10. 27、Python 面向对象(创建类、创建实例对象、访问属性、内置类属性、对象销毁、类的继承、方法重写、基础重载方法、运算符重载、类属性与方法、下划线双下划线)

    27Python面向对象(Python2) Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. ...

最新文章

  1. HTML表格颜色按条件填充,Excel单元格能否根据条件填充颜色?
  2. 反射 -- 业务需求:执行某个类中全部的以test为开头的无参数无返回值的非静态方法。...
  3. CentOS7下pptp ***一键安装脚本
  4. 绿色计算在数据中心的应用及节能效果浅析
  5. hdu 2049 考新郎
  6. boost::scoped_ptr与std::unique_ptr
  7. 全网最细之接口的定义与实现
  8. 洛谷P2015 二叉苹果树【树形dp】
  9. hibernate CascadeType属性说明
  10. 第7集 驱动与电气原理图绘制
  11. Qt视频直播软件--项目实战(Day3)
  12. 联想硬盘保护系统 计算机名 后缀,联想硬盘保护系统,教您联想硬盘保护系统怎么安装...
  13. pandas-task08-文本数据.md
  14. request、response
  15. uniapp 苹果安全区配置
  16. iOS 初中级工程师简历指南
  17. easypoi导出EXCEL表格,WPS能打开,OFFICE打不开问题
  18. Unity之数据持久化——Json
  19. LocalDB 声称以后对于中文乱码的问题
  20. GIS篇—搭建本地地图服务器(geoserver )和 leaflet 绘制多边形,点击事件等

热门文章

  1. 一台电脑两个macOS系统,怎么装
  2. rd640 linux raid,联想服务器rd640如何设置raid 1
  3. 古时候有个【百僧问题】,一百馒头一百僧,大僧三个更无争,小僧三人分一个,大小和尚各几丁? *...
  4. CH32V103C8T6入门指导
  5. 关于微信号为“绘本学堂”的一篇文章《中国孩子已经变了,老师和家长还没跟上!》的思考
  6. Python学习手册之函数和模块
  7. 批量下载网页链接---数据集批量下载
  8. QT中更改主窗体背景色和背景图片
  9. 2017年全国大学生电子设计竞赛 参赛回忆
  10. SpringBoot项目使用RestTemplate发送请求踩坑记录