摘要:所有引用類型的原型鏈都可以追溯到構(gòu)造函數(shù)屬性內(nèi)置的一些構(gòu)造函數(shù)有等等它們主要有兩個(gè)共有的屬性。而構(gòu)造函數(shù)創(chuàng)建對(duì)象除了上面的操作以外還會(huì)運(yùn)行構(gòu)造函數(shù)。利用與構(gòu)造函數(shù)實(shí)現(xiàn)繼承對(duì)象關(guān)系相關(guān)學(xué)習(xí)文章中和的區(qū)別和關(guān)系
介紹
Object 構(gòu)造函數(shù)屬性在javascript中, 數(shù)據(jù)類型主要分為原始類型和引用類型兩種。而一切引用類型都來(lái)自于Object的拷貝。所有引用類型的原型鏈都可以追溯到 Object
JavaScript 內(nèi)置的一些構(gòu)造函數(shù)有 Object, Function, Number, String, Boolean, Array, RegExp 等等, 它們主要有兩個(gè)共有的屬性。
length 構(gòu)造函數(shù)參數(shù)個(gè)數(shù)
prototype 構(gòu)造函數(shù)原型對(duì)象
Object原型鏈Object.getPrototypeOf
Object.isPrototypeOf
Object.hasOwnProperty
一切引用對(duì)象的原型都來(lái)自 Object.prototype測(cè)試各個(gè)數(shù)據(jù)類型的引用情況
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); });
每一個(gè)引用類型對(duì)象, 都含有一個(gè)原型屬性__proto__, 它負(fù)責(zé)控制對(duì)象的原型屬性和方法的查詢使用
創(chuàng)建無(wú)Object.prototype的原型鏈對(duì)象// 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 顯示原型.
實(shí)例對(duì)象通過(guò)隱式原型__proto__ 匹配找到對(duì)應(yīng)的函數(shù)和屬性. 而prototype是每一個(gè)構(gòu)造函數(shù)都存在的一個(gè)屬性。其中prototype 包含 constructor屬性
var o = {}; "__proto__" in o; // return true, 說(shuō)明 字面量對(duì)象存在一個(gè)隱式屬性 // 指定隱式屬性 function Foo () {} o.__proto__ = Foo.prototype; o instanceof Foo; // return true o instanceof Object; // return true設(shè)置隱藏原型屬性
var o = {}; "__proto__" in o; function Foo () {} function Bar () {} Bar.prototype = new Foo(); Bar.prototype.constructor = Bar; // 方法一, 直接設(shè)置 __proto__值 o.__proto__ = Foo.prototype; console.log(o instanceof Foo); // return true; // 方法二, 使用 setPrototypeOf Object.setPrototypeOf(o, Bar.prototype); // 設(shè)置新原型 console.log(o instanceof Bar); // return true; // 獲取對(duì)象隱式屬性 Object.getPrototypeOf(o) === Bar.prototype; // return true // 檢查原型 是否存在于對(duì)象屬性的鏈中 Bar.prototype.isPrototypeOf(o); // true Foo.prototype.isPrototypeOf(o); // true Object.prototype.isPrototypeOf(o); // true獲取對(duì)象的實(shí)例屬性
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 返回一個(gè)對(duì)象的實(shí)例可枚舉屬性, 如果使用了Object.defineProperty改變了對(duì)象的某個(gè)屬性, 則無(wú)法通過(guò)Object.keys返回屬性進(jìn)行遍歷屬性, 也無(wú)法使用 for-in循環(huán)。
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() 返回自身實(shí)例屬性名稱, 無(wú)視enumerable: false
var obj = { foo: function () {}, bar: "hello world" }; Object.defineProperty(obj, "foo", { // foo 已被定義, 所以需要顯示設(shè)置 false enumerable: false }); Object.defineProperty(obj, "foo2", { value: function () {}, // foo2 未被定義, 默認(rèn)enumerable為false enumerable: true }); // "bar", "foo2" Object.keys(obj); // "foo", "bar", "foo2" Object.getOwnPropertyNames(obj); "foo" in obj // return true
in 操作符, 檢查屬性是否在能夠獲取, 無(wú)視屬性
對(duì)象定義屬性Object.defineProperty
Object.getOwnPropertyDescriptor
屬性描述一般是由enumrable, value, get, set, configurable, writeable, value 組成, 其中 get, set 與 value 為互斥關(guān)系
定義一個(gè)對(duì)象的描述var obj = Object.create(null); Object.defineProperty(obj, "foo", { value: "foo", configurable: false, writeable: false, enumerable: false }); obj.foo = "change foo"; console.log(obj.foo); // still foo Object.defineProperty(obj, "foo", { writeable: true, configurable: true }); obj.foo = "change foo 2"; console.log(obj.foo); // still foo "foo" in obj; // return true
一旦被定義了configureable: false, 那么后續(xù)再次 defineProperty時(shí)不會(huì)生效。
writeable: false 的情況下, 無(wú)法修改屬性的 value 值
屬性描述中的 value 與 get, setvar obj = Object.create(null); // throw Error // Uncaught TypeError: Invalid property descriptor. // Cannot both specify accessors and a value or writable attribute Object.defineProperty(obj, "foo", { value: "foo", set: function (val) { // this 指向 obj this._foo = val; }, get: function () { return this._foo; } });
因?yàn)?value 與 get, set 為互斥關(guān)系, 所以無(wú)法同時(shí)進(jìn)行定義。
writeable 與 get, setvar obj = Object.create(null); Object.defineProperty(obj, "foo", { // 失效 writeable: false, set: function (val) { // this 指向 obj this._foo = val; }, 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 失效, 無(wú)法對(duì)屬性做任何限制
重復(fù)定義對(duì)象的屬性var obj = Object.create(null); Object.defineProperty(obj, "foo", { configurable: false, value: "foo" }); // Uncaught TypeError: Cannot redefine property: foo Object.defineProperty(obj, "foo", { value: "foo2" });
一旦定義了configurable: false以后, 不允許再次定義 descriptor
獲取對(duì)象的屬性描述var obj = Object.create(null); Object.defineProperty(obj, "foo", { configurable: true, value: "foo" }); var descriptor = Object.getOwnPropertyDescriptor(obj, "foo"); console.log(descrptor); // {value: "foo", writable: false, enumerable: false, configurable: false} // {foo: {value: "foo", writable: false, enumerable: false, configurable: false}} Object.getOwnPropertyDescriptors(obj);對(duì)象拷貝 淺拷貝
Object.assign
將候選的對(duì)象里的可枚舉屬性進(jìn)行引用賦值, 支持多個(gè)候選的對(duì)象傳遞
var o = { foo: "foo", bar: "bar" }; Object.defineProperty(o, "foo", { 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 處于淺拷貝的關(guān)系, 所以返回的key 都為簡(jiǎn)單的引用方式.
深度拷貝使用 對(duì)象系列化方式copy數(shù)據(jù)格式
// 該方法只能拷貝基本數(shù)據(jù)類型 var obj = {a: 1, b: 2, c: function () { console.log("hello world");}, d: {e: 3, f: 4}}; JSON.parse(JSON.stringify(obj));
自行實(shí)現(xiàn)深度拷貝
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
深度拷貝對(duì)象函數(shù), 內(nèi)置的對(duì)象和數(shù)組都被完整的拷貝出來(lái)。
循環(huán)引用拷貝問(wèn)題
var o = {a: 1, b: 2}; // 循環(huán)引用問(wèn)題 o.foo = o; // Uncaught TypeError: Converting circular structure to JSON JSON.stringify(o); // Uncaught RangeError: Maximum call stack size exceeded deepClone(o); // 將循環(huán)引用的key設(shè)置為不可枚舉型 Object.defineProperty(o, "foo", {enumerable: false}); // OK {"a":1,"b":2} JSON.stringify(o);
避免重復(fù)循環(huán)引用的深度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)) { // 對(duì)象重復(fù)引用 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 創(chuàng)建對(duì)象實(shí)例
一般創(chuàng)建對(duì)象有三種方式
字面量方式 var o = {};
構(gòu)造函數(shù)方式 var o = new Object();
Object.create();
Object.create 與 字面量創(chuàng)建的區(qū)別
Object.create 可以指定創(chuàng)建的對(duì)象的隱式原型鏈 __proto__, 也可以創(chuàng)建空原型鏈的的對(duì)象
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 與構(gòu)造函數(shù)的區(qū)別
Object.create 直接進(jìn)行開(kāi)辟對(duì)象空間, 綁定隱式原型鏈屬性。而構(gòu)造函數(shù)創(chuàng)建對(duì)象除了上面的操作以外, 還會(huì)運(yùn)行構(gòu)造函數(shù)。
利用 Object.create 與構(gòu)造函數(shù), 實(shí)現(xiàn)繼承對(duì)象關(guān)系
// 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."相關(guān)學(xué)習(xí)文章
js中__proto__和prototype的區(qū)別和關(guān)系?
Object MDN API
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/88887.html
摘要:基于對(duì)象字面量,但是獨(dú)立于任何編程語(yǔ)言,真正重要的是表示法本身,所以在學(xué)習(xí)之前不必先學(xué)習(xí)。鍵必須是字符串,值可以是合法的數(shù)據(jù)類型字符串?dāng)?shù)字對(duì)象數(shù)組布爾值或。布爾類型中的布爾值僅可使用小寫(xiě)形式或,其他任何寫(xiě)法都會(huì)報(bào)錯(cuò)。 什么是JSON JSON全稱是Javascript Object Notation(對(duì)象表示法),是一種在不同平臺(tái)間傳遞數(shù)據(jù)的文本格式(數(shù)據(jù)交換格式)。常見(jiàn)的數(shù)據(jù)交換格式...
摘要:基于對(duì)象字面量,但是獨(dú)立于任何編程語(yǔ)言,真正重要的是表示法本身,所以在學(xué)習(xí)之前不必先學(xué)習(xí)。鍵必須是字符串,值可以是合法的數(shù)據(jù)類型字符串?dāng)?shù)字對(duì)象數(shù)組布爾值或。布爾類型中的布爾值僅可使用小寫(xiě)形式或,其他任何寫(xiě)法都會(huì)報(bào)錯(cuò)。 什么是JSON JSON全稱是Javascript Object Notation(對(duì)象表示法),是一種在不同平臺(tái)間傳遞數(shù)據(jù)的文本格式(數(shù)據(jù)交換格式)。常見(jiàn)的數(shù)據(jù)交換格式...
某熊的技術(shù)之路指北 ? 當(dāng)我們站在技術(shù)之路的原點(diǎn),未來(lái)可能充滿了迷茫,也存在著很多不同的可能;我們可能成為 Web/(大)前端/終端工程師、服務(wù)端架構(gòu)工程師、測(cè)試/運(yùn)維/安全工程師等質(zhì)量保障、可用性保障相關(guān)的工程師、大數(shù)據(jù)/云計(jì)算/虛擬化工程師、算法工程師、產(chǎn)品經(jīng)理等等某個(gè)或者某幾個(gè)角色。某熊的技術(shù)之路系列文章/書(shū)籍/視頻/代碼即是筆者蹣跚行進(jìn)于這條路上的點(diǎn)滴印記,包含了筆者作為程序員的技術(shù)視野、...
閱讀 1915·2021-11-25 09:43
閱讀 1421·2021-11-22 15:08
閱讀 3870·2021-11-22 09:34
閱讀 3292·2021-09-04 16:40
閱讀 3411·2021-09-04 16:40
閱讀 606·2019-08-30 15:54
閱讀 1397·2019-08-29 17:19
閱讀 1819·2019-08-28 18:13