加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

[S3-E435]深度挖掘 Object 对象的使用

发布时间:2020-12-14 04:59:16 所属栏目:大数据 来源:网络整理
导读:介绍 在javascript中,数据类型主要分为原始类型和引用类型两种。而一切引用类型都来自于Object的拷贝。所有引用类型的原型链都可以追溯到 Object Object 构造函数属性 JavaScript 内置的一些构造函数有 Object,Function,Number,String,Boolean,Array,RegExp

介绍

在javascript中,数据类型主要分为原始类型和引用类型两种。而一切引用类型都来自于Object的拷贝。所有引用类型的原型链都可以追溯到 Object

Object 构造函数属性

JavaScript 内置的一些构造函数有 Object,Function,Number,String,Boolean,Array,RegExp 等等,它们主要有两个共有的属性。


  • length 构造函数参数个数

  • prototype 构造函数原型对象


Object原型链

  • Object.getPrototypeOf

  • Object.isPrototypeOf

  • Object.hasOwnProperty

一切引用对象的原型都来自 Object.prototype

测试各个数据类型的引用情况


var a = {},

? ? b = [],

? ? c = function () {},

? ? d = Function,

? ? e = String;

[a,b,c,d,e].forEach(function (val) {

? ? // all return true

? ? console.log(val instanceof Object);

});

每一个引用类型对象,都含有一个原型属性__proto__,它负责控制对象的原型属性和方法的查询使用


创建无Object.prototype的原型链对象

// method 1

var obj1 = Object.create(null);


// method 2

var obj2 = {};

Object.setPrototypeOf(obj2,null);


// method 3

var obj3 = {};

obj3.__proto__ = null;


[obj1,obj2,obj3].forEach(function (item) {

? console.log(item instanceof Object); // false

});

__proto__ 与 prototype

__proto__ 隐式原型, prototype 显示原型.?

实例对象通过隐式原型__proto__ 匹配找到对应的函数和属性. 而prototype是每一个构造函数都存在的一个属性。其中prototype 包含 constructor属性


var o = {};

'__proto__' in o; // return true,说明 字面量对象存在一个隐式属性


// 指定隐式属性

function Foo () {}

o.__proto__ = Foo.prototype;


o instanceof Foo; // return true

o instanceof Object; // return true


设置隐藏原型属性

var o = {};

'__proto__' in o;


function Foo () {}

function Bar () {}

Bar.prototype = new Foo();

Bar.prototype.constructor = Bar;


// 方法一,直接设置 __proto__值

o.__proto__ = Foo.prototype;

console.log(o instanceof Foo); // return true;


// 方法二,使用 setPrototypeOf

Object.setPrototypeOf(o,Bar.prototype); // 设置新原型

console.log(o instanceof Bar); // return true;


// 获取对象隐式属性

Object.getPrototypeOf(o) === Bar.prototype; // return true


// 检查原型 是否存在于对象属性的链中

Bar.prototype.isPrototypeOf(o); // true

Foo.prototype.isPrototypeOf(o); // true

Object.prototype.isPrototypeOf(o); // true


获取对象的实例属性

  • Object.keys

  • Object.getOwnPropertyNames

// return []

Object.keys(Object.prototype)


// return ["constructor","__defineGetter__","__defineSetter__","hasOwnProperty","__lookupGetter__","__lookupSetter__","isPrototypeOf","propertyIsEnumerable","toString","valueOf","__proto__","toLocaleString"]

Object.getOwnPropertyNames(Object.prototype)

Object.keys 返回一个对象的实例可枚举属性,如果使用了Object.defineProperty改变了对象的某个属性,则无法通过Object.keys返回属性进行遍历属性,也无法使用 for-in循环。


var obj = {

? ? foo: function () {}

};


// return ['foo']

Object.keys(obj);


Object.defineProperty(obj,'foo',{

? ?enumerable: false

});


// return []

Object.keys(obj);


// empty loop

for (var name in obj) {

? console.log(name);

}


// return false

obj.hasOwnProperty('foo');

Object.getOwnPropertyNames() 返回自身实例属性名称,无视enumerable: false


var obj = {

? ? foo: function () {},

? ? bar: 'hello world'

};


Object.defineProperty(obj,{

? ? // foo 已被定义,所以需要显示设置 false

? ? enumerable: false

});


Object.defineProperty(obj,'foo2',{

? ? value: function () {},

? ? // foo2 未被定义,默认enumerable为false

? ? enumerable: true

});


// 'bar','foo2'

Object.keys(obj);


// 'foo','bar','foo2'

Object.getOwnPropertyNames(obj);


'foo' in obj // return true

in 操作符,检查属性是否在能够获取,无视属性


对象定义属性

  • Object.defineProperty

  • Object.getOwnPropertyDescriptor

属性描述一般是由enumrable,value,get,set,configurable,writeable,value 组成, 其中 get,set 与 value 为互斥关系


定义一个对象的描述

var obj = Object.create(null);


Object.defineProperty(obj,{

? ? value: 'foo',

? ? configurable: false,

? ? writeable: false,

? ? enumerable: false

});


obj.foo = 'change foo';

console.log(obj.foo); // still foo


Object.defineProperty(obj,{

? ? writeable: true,

? ? configurable: true

});


obj.foo = 'change foo 2';

console.log(obj.foo); // still foo

'foo' in obj; // return true

  • 一旦被定义了configureable: false,那么后续再次 defineProperty时不会生效。

  • writeable: false 的情况下,无法修改属性的 value 值


属性描述中的 value 与 get,set

var obj = Object.create(null);


// throw Error?

// Uncaught TypeError: Invalid property descriptor.?

// Cannot both specify accessors and a value or writable attribute

Object.defineProperty(obj,

? ? set: function (val) {

? ? ? ? // this 指向 obj

? ? ? ? this._foo = val;

? ? },

? ? get: function () {

? ? ? ? return this._foo;

? ? }

});

因为 value 与 get,set 为互斥关系,所以无法同时进行定义。


writeable 与 get,set

var obj = Object.create(null);


Object.defineProperty(obj,{

? ? // 失效

? ? writeable: false,

? ? get: function () {

? ? ? ? return this._foo;

? ? }

});


obj.foo = 'abc'; // set()

obj._foo === obj.foo ?// return true

console.log(obj.foo); // return 'abc'

'foo' in obj // return true

writeable 失效,无法对属性做任何限制


重复定义对象的属性

var obj = Object.create(null);


Object.defineProperty(obj,{

? ? configurable: false,

? ? value: 'foo'

});


// Uncaught TypeError: Cannot redefine property: foo

Object.defineProperty(obj,{

? ? value: 'foo2'

});

一旦定义了configurable: false以后,不允许再次定义 descriptor


获取对象的属性描述

var obj = Object.create(null);


Object.defineProperty(obj,{

? ? configurable: true,

? ? value: 'foo'

});

var descriptor = Object.getOwnPropertyDescriptor(obj,'foo');


console.log(descrptor); // {value: "foo",writable: false,enumerable: false,configurable: false}


// {foo: {value: "foo",configurable: false}}

Object.getOwnPropertyDescriptors(obj);


对象拷贝

浅拷贝

  • Object.assign

将候选的对象里的可枚举属性进行引用赋值,支持多个候选的对象传递


var o = {

? foo: 'foo',

? bar: 'bar'

};


Object.defineProperty(o,{

? enumerable: false

});


var obj = Object.assign(Object.create(null),o,{

? o: o

});


/*

obj = {

? bar: 'bar',

? o: {

? ? 'foo': 'foo',

? ? 'bar': 'bar'

? }

}

*/

obj.o === o; // return true;

由于Object.assign 处于浅拷贝的关系,所以返回的key 都为简单的引用方式.


深度拷贝

使用 对象系列化方式copy数据格式


// 该方法只能拷贝基本数据类型

var obj = {a: 1,b: 2,c: function () { console.log('hello world');},d: {e: 3,f: 4}};


JSON.parse(JSON.stringify(obj));

自行实现深度拷贝


function deepClone (obj) {

? var newObj;

? var isPlainObject = function (o) {

? ? return Object.prototype.toString.call(o) === '[object Object]';

? };

? var isArray = function (o) {

? ? return Object.prototype.toString.call(o) === '[object Array]';

? };

? if (isArray(obj)) {

? ? newObj = [];

? ? for (var i = 0,len = obj.length; i < len; i++) {

? ? ? newObj.push(deepClone(obj[i]));

? ? }

? } else if (isPlainObject(obj)) {

? ? newObj = {};

? ? for (var key in obj) {

? ? ? newObj[key] = deepClone(obj[key]);

? ? }

? } else {

? ? newObj = obj;

? }

? return newObj;

}


var o = {a: 1,b: [{c: 2,d: 3}]};

var o2 = deepClone(o);

o.b[0] !== o2.b[0]; // return true

深度拷贝对象函数,内置的对象和数组都被完整的拷贝出来。


循环引用拷贝问题



var o = {a: 1,b: 2};


// 循环引用问题

o.foo = o;


// Uncaught TypeError: Converting circular structure to JSON

JSON.stringify(o);


// Uncaught RangeError: Maximum call stack size exceeded

deepClone(o);


// 将循环引用的key设置为不可枚举型

Object.defineProperty(o,{enumerable: false});

// OK {"a":1,"b":2}

JSON.stringify(o);

避免重复循环引用的深度clone


function deepClone (obj) {


? var objStack = [];


? var isPlainObject = function (o) {

? ? return Object.prototype.toString.call(o) === '[object Object]';

? };


? var isArray = function (o) {

? ? return Object.prototype.toString.call(o) === '[object Array]';

? };

??

? var isError = function (o) {

? ? return o instanceof Error;

? };


? function _deepClone (obj) {

? ? var newObj,cloneObj;

? ? if (isArray(obj) || isPlainObject(obj)) {

? ? ? // 对象重复引用

? ? ? if (objStack.indexOf(obj) === -1) {

? ? ? ? objStack.push(obj);

? ? ? } else {

? ? ? ? return new Error('parameter Error. it is exits loop reference');

? ? ? }

? ? }

? ? if (isArray(obj)) {

? ? ? newObj = [];

? ? ? for (var i = 0,len = obj.length; i < len; i++) {

? ? ? ? cloneObj = _deepClone(obj[i]);

? ? ? ? if (!isError(cloneObj)) {

? ? ? ? ? newObj.push(cloneObj);

? ? ? ? }

? ? ? }

? ? } else if (isPlainObject(obj)) {

? ? ? newObj = {};

? ? ? for (var key in obj) {

? ? ? ? cloneObj = _deepClone(obj[key]);

? ? ? ? if (!isError(cloneObj)) {

? ? ? ? ? newObj[key] = cloneObj;

? ? ? ? }

? ? ? }

? ? } else {

? ? ? newObj = obj;

? ? }

? ? return newObj;

? }

? return _deepClone(obj);

}


Object.create 创建对象实例

一般创建对象有三种方式


  • 字面量方式 var o = {};

  • 构造函数方式 var o = new Object();

  • Object.create();

Object.create 与 字面量创建的区别


Object.create 可以指定创建的对象的隐式原型链 __proto__,也可以创建空原型链的的对象


var prototype = {

? foo: 'foo',

? name: 'prototoype'

};

var o = Object.create(prototype);

var o2 = Object.create(null);

o.__proto__ === prototype; // true


'__protot__' in o2; // false

Object.create 与构造函数的区别


Object.create 直接进行开辟对象空间,绑定隐式原型链属性。而构造函数创建对象除了上面的操作以外,还会运行构造函数。


利用 Object.create 与构造函数,实现继承对象关系


// Shape - superclass

function Shape() {

? this.x = 0;

? this.y = 0;

}


// superclass method

Shape.prototype.move = function(x,y) {

? this.x += x;

? this.y += y;

? console.info('Shape moved.');

};


// Rectangle - subclass

function Rectangle() {

? Shape.call(this); // call super constructor.

}


// subclass extends superclass

Rectangle.prototype = Object.create(Shape.prototype);

Rectangle.prototype.constructor = Rectangle;


var rect = new Rectangle();


console.log('Is rect an instance of Rectangle?',

? rect instanceof Rectangle); // true

console.log('Is rect an instance of Shape?',

? rect instanceof Shape); // true

rect.move(1,1); // Outputs,'Shape moved.'


相关学习文章

  • js中__proto__和prototype的区别和关系? (https://www.zhihu.com/question/34183746/answer/58068402)

  • Object MDN API (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)


转自:https://segmentfault.com/a/1190000011461557

作者:liyanlong


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

更多文章点击?目录?查看(或在导航菜单中查看

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

==========阅读原文==========

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读