成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

《你不知道的javascript》筆記_對(duì)象&原型

seasonley / 1848人閱讀

摘要:上一篇你不知道的筆記寫(xiě)在前面這是年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響年是向上的一年在新的城市穩(wěn)定連續(xù)堅(jiān)持健身三個(gè)月早睡早起游戲時(shí)間大大縮減,學(xué)會(huì)生活。

上一篇:《你不知道的javascript》筆記_this

寫(xiě)在前面

這是2019年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響2018年是向上的一年:在新的城市穩(wěn)定、連續(xù)堅(jiān)持健身三個(gè)月、早睡早起、游戲時(shí)間大大縮減,學(xué)會(huì)生活。根據(jù)上一年目標(biāo)完成情況,新一年的計(jì)劃將采取【敏捷迭代】的方式:制定大方向,可臨時(shí)更新小目標(biāo)的策略。哈哈,話不多說(shuō)..

在學(xué)習(xí)《javascript高級(jí)程序設(shè)計(jì)》這本書(shū)時(shí),關(guān)于對(duì)象和原型,之前寫(xiě)過(guò)下面幾篇文章,可作參考:

《javascript高級(jí)程序設(shè)計(jì)》筆記:對(duì)象數(shù)據(jù)屬性和訪問(wèn)器屬性

《javascript高級(jí)程序設(shè)計(jì)》筆記:創(chuàng)建對(duì)象

《javascript高級(jí)程序設(shè)計(jì)》筆記:原型圖解

《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承

一、對(duì)象基本知識(shí) 1.1 數(shù)據(jù)屬性與訪問(wèn)屬性

《javascript高級(jí)程序設(shè)計(jì)》筆記:對(duì)象數(shù)據(jù)屬性和訪問(wèn)器屬性,這篇文章對(duì)數(shù)據(jù)屬性和訪問(wèn)器屬性有基本的介紹了,下面會(huì)做出一點(diǎn)補(bǔ)充說(shuō)明:

(1)默認(rèn)值

通過(guò)Object.defineProperty的方式聲明的屬性默認(rèn)值

var obj = { a: 1 };
Object.getOwnPropertyDescriptor(obj, "a");
/*{
    value: 1, 
    writable: true,
    enumerable: true, 
    configurable: true
}*/

通過(guò)Object.defineProperty的方式聲明的屬性默認(rèn)值

var obj = {};
Object.defineProperty(obj, "a", {});
Object.getOwnpropertyDescriptor(obj, "a");
/*{
    value: undefined,
    writable: false,
    enumerable: false,
    configurable: false
}*/

(2)屬性configurable

configurable屬性設(shè)為false為不可逆過(guò)程

configurable:false其他屬性無(wú)法修改同時(shí)會(huì)禁止刪除該屬性

特例configurable: false時(shí),writable的狀態(tài)可由true改為false,但不能由false變?yōu)?b>true

var obj = {};
Object.defineProperty(obj, "a", {
    configurable: false,
    writable: true,
    value: 1
})// {a: 1}
Object.defineProperty(obj, "a", {
    configurable: false,
    writable: false,
    value: 2
})// {a: 2}
Object.defineProperty(obj, "a", {
    configurable: false,
    writable: false,
    value: 3
})// Uncaught TypeError: Cannot redefine property: a

(3)區(qū)分?jǐn)?shù)據(jù)屬性和訪問(wèn)屬性

當(dāng)我們同時(shí)定義這兩個(gè)屬性時(shí),會(huì)提示錯(cuò)誤:

var obj = { _a: 1 };
Object.defineProperty(obj, "a", {
    configurable: true,
    enumerable: true,
    
    writable: true,
    value: 1,
    
    get() { return this._a; },
    set(newVal) { this._a = newVal * 10; }
});
Object.getOwnPropertyDescriptor(obj, "a");
// Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute

因此:這兩個(gè)屬性不能同時(shí)存在,根據(jù)他們特有的屬性反過(guò)來(lái)判斷究竟是哪種屬性即可

(4)屬性enumerable: false的對(duì)象如何遍歷

可通過(guò)Object.getOwnPropertyNames獲取key,再遍歷

var obj = {};
Object.defineProperty(obj, "a", {value: 10});

// 一般的遍歷無(wú)法獲取
for(let k in obj){
    console.log(k)
}// undefined

Object.getOwnPropertyNames(obj); // ["a"]
1.2 不變性

(1)對(duì)象常量

創(chuàng)建方式:數(shù)據(jù)屬性:wraitable:false,configurable:false
特點(diǎn):不可修改/重定義/刪除

var obj = {};
Object.defineProperty(obj, "MY_CONSTANT", {
    value: 10,
    writable: false,
    configurable: false,
})
obj.MY_CONSTANT = 11;
console.log(obj.MY_CONSTANT); // 非嚴(yán)格模式下為10,嚴(yán)格模式報(bào)錯(cuò)

同樣的,如果這個(gè)對(duì)象常量是對(duì)象

var obj = {};
Object.defineProperty(obj, "MY_CONSTANT_OBJ", {
    value: {a: 1},
    writable: false,
    configurable: false,
})
obj.MY_CONSTANT_OBJ.b = 2;
console.log(obj.MY_CONSTANT_OBJ); // {a: 1, b: 2}

因此:const定義的普通常量類似,只要對(duì)象的地址不變便不會(huì)報(bào)錯(cuò)

(2)禁止擴(kuò)展

創(chuàng)建方式Object.preventExtensions()
特點(diǎn):不可添加新屬性(可刪除可修改可重定義)
判斷Object.isExtensible()不可擴(kuò)展返回false

var obj = {a: 1, b: 2};
Object.preventExtensions(obj);

obj.c = 3; // {a: 1, b: 2} 不可添加
obj.a = 2; // {a: 2, b: 2} 可修改
delete obj.a; // {b: 2} 可刪除
Object.defineProperty(obj, "b", {
    configurable: false,
    value: 3
});
delete obj.b; // {b: 3} 可重定義

Object.isExtensible(obj); // false

(3)密封

創(chuàng)建方式Object.seal()
特點(diǎn):不可添加/修改/刪除
判斷Object.isSealed()密封時(shí)返回true

密封是在禁止擴(kuò)展的基礎(chǔ)上禁止刪除和重定義。相當(dāng)于把現(xiàn)有屬性標(biāo)記為configurable:false

var obj = {a: 1, b: 2};
Object.seal(obj);

obj.c = 3; // {a: 1, b: 2} 不可添加
delete obj.a; // {a: 1, b: 2} 不可刪除
// configurable:false 不可重定義

obj.a = 2; // {a: 2, b: 2} 可修改

Object.isSealed(obj); // true

(4)凍結(jié)

創(chuàng)建方式Object.freeze()
特點(diǎn):最高級(jí)別的不可變
判斷Object.isFrozen()

凍結(jié)是在密封的基礎(chǔ)上把現(xiàn)有屬性標(biāo)記為writable:false,所有屬性相當(dāng)于常量屬性

1.3 存在性

in操作符:檢查屬性是否在對(duì)象及其原型鏈中
hasOwnProperty:僅檢查屬性是否在該對(duì)象上

因此,可結(jié)合二者來(lái)判斷屬性是否僅存在與原型鏈上

function hasPrototypeProperty(obj, property) {
    return (property in obj) && !(obj.hasOwnProperty(property));
}

另外,可獲取的某個(gè)對(duì)象所有key(未遍歷至原型鏈),再判斷指定屬性是否在對(duì)象內(nèi);
遍歷方法:

Object.keys();
Object.getOwnPropertyNames(); // 可獲取不可枚舉的屬性
1.4 深淺拷貝

理解深淺拷貝需要對(duì)內(nèi)存有一定理解,如果對(duì)基礎(chǔ)類型和復(fù)雜類型(值類型和引用類型)在內(nèi)存中的區(qū)別仍沒(méi)有清楚的認(rèn)識(shí),可參考《javascript高級(jí)程序設(shè)計(jì)》筆記:值類型與引用類型這篇文章,否則忽略即可

值類型數(shù)據(jù)是直接存在于棧內(nèi)存中,復(fù)制操作是直接開(kāi)辟內(nèi)存并存值;

引用類型數(shù)據(jù)棧內(nèi)存中存儲(chǔ)的只是堆內(nèi)存中真實(shí)數(shù)據(jù)的一個(gè)引用,復(fù)制操作僅復(fù)制引用,并未真實(shí)復(fù)制堆中的數(shù)據(jù);

根據(jù)上面的認(rèn)識(shí),我們思考一下:什么是深拷貝,什么是淺拷貝?

深淺拷貝僅僅是針對(duì)引用類型而言,深拷貝是按照目標(biāo)對(duì)象的結(jié)構(gòu)復(fù)制一份完全相同的對(duì)象,新的對(duì)象與原對(duì)象各個(gè)嵌套層級(jí)上內(nèi)存完全獨(dú)立,修改新對(duì)象不會(huì)更改原對(duì)象;引用類型的拷貝中除深拷貝外的均為淺拷貝(不完全深拷貝)

本文僅介紹我在項(xiàng)目中經(jīng)常使用的深淺拷貝幾種方式,不對(duì)底層實(shí)現(xiàn)探究:

擴(kuò)展運(yùn)算符【淺】

var obj = {a: 1, b: 2};
var arr = [1,2,3,4];
// 對(duì)象
var copyObj = {...obj};
copyObj === obj; // false
// 數(shù)組
var copyArr = [...arr];
copyArr === arr; // false

Object.assign()【淺】

// 對(duì)象
var copyObj = Object.assign({}, obj);
copyObj === obj; // false
// 數(shù)組
var copyArr = Object.assign([], arr);
copyArr === arr; // false

數(shù)組也是對(duì)象,因此Object.assign也可使用,只是一般不這么用且有更簡(jiǎn)單的方式

數(shù)組拷貝實(shí)現(xiàn)【淺】

var copyArr1 = arr.slice();
var copyArr2 = arr.concat();

lodash中的clone/cloneDeep【淺/深】
工具庫(kù)lodash中提供了深淺拷貝的方法,簡(jiǎn)單易用且能夠按需引入

// 全部引入
import _ from "lodash";
// _.clone() _.cloneDeep()

// 按需引入
import clone from "lodash/clone";
import cloneDeep from "lodash/cloneDeep";

JSON方式【深】
這個(gè)是平時(shí)項(xiàng)目中最常用的深拷貝方式,局限性就是,無(wú)法拷貝方法

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

其實(shí),深拷貝就是通過(guò)遞歸逐級(jí)淺拷貝實(shí)現(xiàn)的,因?yàn)閷?duì)于復(fù)雜類型的元素均為值類型的淺拷貝便是深拷貝。例:[1,2,3].slice()便是深拷貝

如需更深入,可參考:JavaScript 淺拷貝與深拷貝

二、原型&繼承
類/繼承描述了一種代碼的組織結(jié)構(gòu)形式——一種在軟件中對(duì)真實(shí)世界中問(wèn)題領(lǐng)域的建模方法

下面會(huì)對(duì)這種建模慢慢闡述

2.1 原型

非常慶幸,之前寫(xiě)過(guò)《javascript高級(jí)程序設(shè)計(jì)》筆記:原型圖解的文章得到了許多朋友的認(rèn)可。關(guān)于原型的一些知識(shí)這里面也說(shuō)的七七八八了,讀完《你不知道的javascript》后再做些許補(bǔ)充

下面搬出經(jīng)典的鐵三角鎮(zhèn)樓,在原型圖解中已做說(shuō)明,在此不嘮述

(1)原型有什么用

為什么要抽離出原型的概念?在js中原型就相當(dāng)于類;類有什么作用呢?

書(shū)中有一個(gè)恰當(dāng)?shù)谋扔鳎?strong>類相當(dāng)于建造房子時(shí)的藍(lán)圖,實(shí)例相當(dāng)于我們需要真實(shí)建造的房子

這個(gè)藍(lán)圖(類)抽離出了房子的諸多特性(屬性),如寬/高/占地/窗戶數(shù)量/材料等等。我們建造房子(創(chuàng)建實(shí)例)時(shí)只需要按照這些搭建即可,而不是從零開(kāi)始

回到編程中:有了類的概念,針對(duì)一些具有公共的屬性和方法對(duì)象,我們可以將其抽離出來(lái),以便下次使用,簡(jiǎn)化我們構(gòu)建的過(guò)程

這個(gè)是js中數(shù)組的【類】,實(shí)例以后就能夠直接使用,而無(wú)需將公用的方法定義在實(shí)例上

(2)屬性屏蔽規(guī)則

屬性查找規(guī)則:沿著原型鏈查找,到最近的對(duì)象截止,若一直到Object.prototype也無(wú)法找到,則返回undefined

反言之,屬性的屏蔽規(guī)則亦是如此?原型鏈上,同名屬性靠前會(huì)屏蔽掉后面的同名屬性?答案遠(yuǎn)沒(méi)有這么簡(jiǎn)單,分為三種情況考慮:(以myObject.foo = "bar";為例)

1. 如果在原型鏈上層存在名為foo的普通數(shù)據(jù)訪問(wèn)屬性并且沒(méi)有被標(biāo)記為只讀writable:true,那么直接在myObject中添加一個(gè)名為foo的新屬性

function Fn() {}
Fn.prototype.foo = "this is proto property";

var myObject = new Fn();
myObject.foo = "this is my own property";

myObject.foo; // "this is my own property";

2. 如果原型鏈上層存在foo,但是被標(biāo)記為只讀writable:false,那么無(wú)法修改已有屬性或者在myObject中創(chuàng)建屏蔽屬性

function Fn() {}
Object.defineProperty(Fn.prototype, "foo", {
    value: "this is proto property",
    writable: false,
});

var myObject = new Fn();
myObject.foo = "this is my own property";

myObject.foo; // "this is proto property";

3. 如果在原型鏈上層存在foo并且他是一個(gè)setter,那么一定會(huì)調(diào)用這個(gè)setter

function Fn() {}
Object.defineProperty(Fn.prototype, "foo", {
    set(newValue) {
        this._foo = "haha! this is setter prototype";
    },
    get() {
        return this._foo;
    }
});

var myObject = new Fn();
myObject.foo = "this is my own property";

myObject.foo; // "haha! this is setter prototype";

(3)一個(gè)面試題

var anotherObject = { a: 2 };
var myObject = Object.create(anotherObject);
// node1
myObject.a++;

anotherObject.a; // ?
myObject.a; // ?
// node2

上面問(wèn)號(hào)處輸出值為多少?

分析:
node1node2處分別執(zhí)行下面的代碼并輸出

// node1
anotherObject.hasOwnProperty("a"); // true
myObject.hasOwnProperty("a"); // false
// node2
anotherObject.hasOwnProperty("a"); // true
myObject.hasOwnProperty("a"); // true

看到了什么,執(zhí)行完myObject.a++;后實(shí)例對(duì)象創(chuàng)建了一個(gè)自己的屬性;為什么?自增操作相當(dāng)于myObject.a = myObject.a + 1首先查找到屬性,后在實(shí)例對(duì)象上創(chuàng)建一個(gè)新的同名屬性,屏蔽原型上的屬性;
答案:2 3

2.2 繼承

《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承這篇文章分析了各種繼承的情況,一步一步演化至更精致的繼承情況

(1)繼承有什么用

需求:為我的汽車建一個(gè)對(duì)象
以前:{id: XX, 牌照: XX, 品牌: XX, 油耗: XX, 載人: XX, 顏色: XX .. }
建模的思想來(lái)搭建類和繼承體系:

抽離交通工具的類 Vehicle = {油耗: XX, 載人: XX, 顏色: XX, drive()}

抽離汽車的類 Car = {繼承Vehicle, 品牌: XX }

實(shí)例化我的汽車 {繼承Car, id: XX, 牌照: XX}

抽離類并繼承,加上實(shí)例對(duì)象特有的屬性便能夠具體某一對(duì)象,達(dá)到高效利用的目的

(2)新的繼承

下面的方式便是在“組合繼承”的進(jìn)一步“精致”,當(dāng)然還有class語(yǔ)法糖(后續(xù)計(jì)劃..)

function Foo(name) {
    this.name = name;
}
Foo.prototype.sayName = function() {
    console.log(this.name);
}
var foo = new Foo("xiaoming");
console.log(foo)

function Bar(name, id) {
    Foo.call(this, name)
    this.id = id;
}

// Object.create()方式
Bar.prototype = Object.create(Foo.prototype);
// Object.setPrototypeOf()方式
// Object.setPrototypeOf( Bar.prototype, Foo.prototype );

Bar.prototype.sayId = function() {
    console.log(this.id);
}
var bar = new Bar("xiaofeng", 1234)
console.log(bar);

兩者對(duì)比而言,顯然Object.setPrototypeOf()方式更加完備一些(無(wú)需再次聲明constructor

2.3 原型本質(zhì)【行為委托】
對(duì)象之間并非從屬關(guān)系,而是委托關(guān)系,js中委托關(guān)系正是通過(guò)Object.create()完成

Object.create()方法創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來(lái)提供新創(chuàng)建的對(duì)象的__proto__

在上面的繼承中,我們已經(jīng)看到了Object.create()的身影;下面來(lái)對(duì)比類和委托思維模型

// 類/繼承模型
function Foo(who) {
    this.me = who;
}
Foo.prototype.identify = function() {
    return "I am " + this.me;
};

function Bar(who) {
    Foo.call( this, who );
}
Bar.prototype = Object.create( Foo.prototype );
Bar.prototype.speak = function() {
    alert( "Hello, " + this.identify() + "." );
};

var b1 = new Bar( "b1" );
var b2 = new Bar( "b2" );

b1.speak();
b2.speak();

// 委托模型
Foo = {
    init(who) {
        this.me = who;
    },
    identify() {
        return "I am " + this.me;
    }
};

Bar = Object.create( Foo );
Bar.speak = function() {
    alert( "Hello, " + this.identify() + "." );
};

var b1 = Object.create( Bar );
b1.init( "b1" );
var b2 = Object.create( Bar );
b2.init( "b2" );

b1.speak();
b2.speak();

類風(fēng)格的代碼強(qiáng)調(diào)的是實(shí)體與實(shí)體之間的關(guān)系,委托風(fēng)格的代碼強(qiáng)調(diào)的是對(duì)象之間的關(guān)聯(lián)關(guān)系;

如何選用?像上面章節(jié)舉的例子:交通工具-->汽車-->具體某個(gè)汽車的關(guān)系,選用類;沒(méi)有太大關(guān)聯(lián)的對(duì)象可直接用委托實(shí)現(xiàn)

上一篇:《你不知道的javascript》筆記_this

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100761.html

相關(guān)文章

  • 你不知道javascript筆記_this

    下一篇:《你不知道的javascript》筆記_對(duì)象&原型 寫(xiě)在前面 上一篇博客我們知道詞法作用域是由變量書(shū)寫(xiě)的位置決定的,那this又是在哪里確定的呢?如何能夠精準(zhǔn)的判斷this的指向?這篇博客會(huì)逐條闡述 書(shū)中有這樣幾句話: this是在運(yùn)行時(shí)進(jìn)行綁定的,并不是在編寫(xiě)時(shí)綁定,它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件this的綁定和函數(shù)聲明的位置沒(méi)有任何關(guān)系,只取決于函數(shù)的調(diào)用方式當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)...

    cpupro 評(píng)論0 收藏0
  • 前端筆記——JS基礎(chǔ)(原型&&原型鏈)

    摘要:基礎(chǔ)原型原型鏈構(gòu)造函數(shù)默認(rèn)有這一行張三李四構(gòu)造函數(shù)擴(kuò)展其實(shí)是的語(yǔ)法糖其實(shí)是的語(yǔ)法糖其實(shí)是使用判斷一個(gè)函數(shù)是否是一個(gè)變量的構(gòu)造函數(shù)原型規(guī)則和示例所有的引用類型數(shù)組對(duì)象函數(shù),都具有對(duì)象屬性即可自有擴(kuò)展的屬性,除外所有的引用類型數(shù)組對(duì)象函數(shù), JavaScript基礎(chǔ) —— 原型&&原型鏈 構(gòu)造函數(shù) function Foo(name, age) { this.name = na...

    n7then 評(píng)論0 收藏0
  • 深入JavaScript(一)this & Prototype

    摘要:然而事實(shí)上并不是。函數(shù)本身也是一個(gè)對(duì)象,但是給這個(gè)對(duì)象添加屬性并不能影響。一圖勝千言作者給出的解決方案,沒(méi)有麻煩的,沒(méi)有虛偽的,沒(méi)有混淆視線的,原型鏈連接不再赤裸裸。所以是這樣的一個(gè)函數(shù)以為構(gòu)造函數(shù),為原型。 注意:本文章是個(gè)人《You Don’t Know JS》的讀書(shū)筆記。在看backbone源碼的時(shí)候看到這么一小段,看上去很小,其實(shí)忽略了也沒(méi)有太大理解的問(wèn)題。但是不知道為什么,我...

    The question 評(píng)論0 收藏0
  • 淺談 null & undefined

    摘要:初識(shí)在中有兩種特別的基本數(shù)據(jù)類型初學(xué)者對(duì)其也很模糊或者直接認(rèn)為它倆相等。作為函數(shù)參數(shù),表示該函數(shù)的參數(shù)不是對(duì)象對(duì)象原型鏈的終點(diǎn)。對(duì)象屬性沒(méi)有賦值,該屬性為當(dāng)函數(shù)沒(méi)有返回值時(shí),默認(rèn)返回第一次分享文章,如有錯(cuò)誤請(qǐng)斧正 1.初識(shí) null & undefined 在javascript 中有兩種特別的基本數(shù)據(jù)類型 null undefined 初學(xué)者 對(duì)其也很模糊或者直接認(rèn)為它倆相等。 確實(shí)...

    lewif 評(píng)論0 收藏0
  • 筆記-你不知道JS-原型

    摘要:如果存在于原型鏈上層,賦值語(yǔ)句的行為就會(huì)有些不同。中包含的屬性會(huì)屏蔽原型鏈上層的所有屬性,因?yàn)榭偸菚?huì)選擇原型鏈中最底層的屬性。如果不直接存在于中而是存在于原型鏈上層時(shí)會(huì)出現(xiàn)的三種情況。類構(gòu)造函數(shù)原型函數(shù),兩個(gè)函數(shù)通過(guò)屬性和屬性相關(guān)聯(lián)。 1 [[Prototype]] 對(duì)于默認(rèn)的 [[Get]] 操作來(lái)說(shuō),如果無(wú)法在對(duì)象本身找到需要的屬性,就會(huì)繼續(xù)訪問(wèn)對(duì)象的 [[Prototype]] ...

    vincent_xyb 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<