當前位置:
首頁 > 知識 > JS學習筆記 對象、包裝類、原型、原型鏈、命名空間、對象枚舉

JS學習筆記 對象、包裝類、原型、原型鏈、命名空間、對象枚舉

文章目錄

對象

對象的創建

對象直接量/字面量

構造函數(重點)

系統自帶構造函數

自定義構造函數

Object.create

對象的增刪改查

包裝類

原型

call、apply

原型鏈

原型鏈上屬性的增刪改查

絕大多數對象最終都會繼承自Object.prototype

對象繼承史

傳統模式

借用構造函數

共享原型

聖杯模式

命名空間

對象枚舉

對象

對象是JavaScript的一個基本數據類型,是一種複合值,它將很多值(原始值或者其他對象)聚合在一起,可通過名字訪問這些值。即屬性的無序集合。

對象的創建

對象直接量/字面量

var obj = {

name : "守敬",

age : "18"

}

console.log(obj.name);//守敬

1

2

3

4

5

構造函數(重點)

系統自帶構造函數

var obj = new object();

obj.name = "守敬";

console.log(obj.name);//守敬

1

2

3

自定義構造函數

為了和普通函數區分,構造函數採用大駝峰式命名法。

function Car(carName, color) {

this.name = carName;

this.color = color;

}

var car = new Car("BMW", "red");

console.log(car.name);//BMW

console.log(car.color);//red

1

2

3

4

5

6

7

自定義構造函數內部原理

在函數體最前面隱式的加上this{}

執行this.xxx = xxx;

隱式的返回this(return)

原理解釋:

注意隱士創建的this對象中有個名為__proto__的屬性,其屬性值為該構造函數繼承的原型prototype。

function Car(carName, color) {

//隱式創建this對象

//var this = {

// color : "",

// name : "",

// health : "",

// run = function (){

// this.health --;

// }

// };

this. color : color,

this.name : carName,

this.health : 100,

this.run = function () {

//對象方法

this.health --;

}

//return this;返回this對象

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Object.create

此方法創建一個繼承該原型的實例對象

留坑待補

對象的增刪改查

增: 所謂增添一個對象的屬性,就是直接對該屬性進行賦值操作即可,這就相當於為該對象添加了一個新屬性,而列印未添加的屬性,瀏覽器不會報錯,而是會列印出undefined

var obj = {};

console.log(obj.name); //undefined (不會報錯)

obj.name = "shoujing";

console.log(obj.name); // shoujing

1

2

3

4

刪:我們通過delete操作符來刪除一個對象的屬性

var obj = {

name : "shoujing"

}

console.log(obj.name); //shoujing

delete obj.name;

console.log(obj.name); //undefined

1

2

3

4

5

6

改: 修改一個對象的屬性是最簡單的了,直接通過賦值操作賦予其其他的值即可

var obj = {

name: "shoujing"

}

console.log(obj.name); //shoujing

obj.name = "obj";

console.log(obj.name); // obj

1

2

3

4

5

6

查:查詢一個對象的屬性值有兩種方法

var obj = {

name: "shoujing"

};

// 第一種方法

console.log(obj["name"]); //shoujing

// 第二種方法

console.log(obj.name); //shoujing

//p.s.最本質的是第一種方法,因為在使用第二種方法時,後台自動將其轉換為第一種字元串的形式來查詢

1

2

3

4

5

6

7

8

p.s.以上的增、刪、改三種操作都只是針對當前對象的屬性進行操作,而不會影響到當前對象的原型的屬性。而查詢是先看看當前對象本身是否設置了該屬性,如果當前對象未設置該屬性,則再看該對象的原型中是否設置了該屬性,若兩者都沒有,則返回undefined

包裝類

五個原始值:number, string , boolean, undefined, null.其中number, string, boolean是分別擁有自己的包裝類,而undefined和null是沒有自己的包裝類的

原始值不是對象,無法擁有自己的屬性,但因為的包裝類的存在,原始值就好似可以擁有自己的屬性了,但其擁有的屬性又有點特殊之處,如下用string來舉例:

引例:

// str是string類型的,非對象,不能擁有屬性,為什麼能列印出 str.length?

var str = "abcd";

console.log(str.length); //4

1

2

3

解釋:

// 因為每次執行完一條完整js語句後該類型對象的包裝類就會將該語句包裝,所以也就不會導致報錯了

var str = "abcd";

// var str = new String("abcd");

console.log(str.length); //4

str.len = 4;

consloe.log(str.len);//undefinend

//length較為特殊,如果是自定義的len屬性,則系統會進行如下過程:

//(new string("abcd")).len = 4; delete

//因此最後列印就是undefinde

1

2

3

4

5

6

7

8

9

舉例

var str = "abcd";

str.lenth = 2;

console.log(str); // ab or abcd ? answer is abcd

console.log(str.length); // 2 or 4 ? answer is 4

1

2

3

4

原型

原型的定義: 原型是function對象的一個屬性,它定義了構造函數製造出的對象的公共祖先。通過該構造函數產生的對象,可以繼承該原型的屬性和方法。原型也是對象。

利用原型特點和概念,可以提取共有屬性。將一類對象的共有屬性提取出來,放到該類對象的原型中,從而不需要每次用new操作符時都重新定義一遍該共有屬性。

如下,定義一個Person構造函數,而屬於Person多構造對象共有的屬性方法,則定義到Person的原型中

Person.prototype = {

eat : function (food) {

console.log("I have eated " + food);

},

sleep : function () {

console.log("I am sleeping");

}

}

// 人的構造函數

function Person (name, age) {

this.name = name;

this.age = age;

}

var person1 = new Person("shoujing", 18);

console.log(person1.name); //shoujing

person1.eat("apple"); //I have eated apple

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

如何查看原型:

之前是不允許我們查看構造函數的原型的,但後來提供了一個可查看構造函數原型的介面:隱士屬性__proto__(其實我們能夠訪問原型的屬性,或者說繼承原型,靠的就是__proto__屬性連接著構造函數和原型,可以說沒有__proto__屬性的存在,就無法實現原型的繼承)

首先我們先說明一下__proto__這個介面是存放到哪裡的看過以上對象創建過程的都應該知道在用new創建一個對象時,內部會隱式自動創建一個this的對象,進過一系列處理後再隱士將this對象返回。而__proto__就在隱士創建的this對象中,如下代碼:

// 原型

Person.prototype = {

say: function () {

console.log("I am saying ");

},

play: function () {

console.log("I am playing");

}

}

// 構造函數

function Person (name) {

// var this = Object.create(Person.prototype);

// p.s.在隱士創建的this對象中存在一個屬性,即__proto__,該屬性存儲了Person.prototype

this.name = name;

// return this;

}

// 對象的創建

var person1 = new Person("lyl");

// 列印原型

console.log(person1.__proto__);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

- 如何查看對象的構造函數,我們通過屬性constructor來查看:contructor屬性位於構造函數的原型中,其中存儲的是構造函數信息,所以在不知道原型的情況下,由原型繼承原理,我們可以用實例對象來直接訪問constructor,即獲取創建該實例的構造函數。

1

function Person () {

this.name = "myName";

this.age = 18;

}

var person = new Person();

console.log(person.constructor); // function Person(){...}

1

2

3

4

5

6

call、apply

call和apply的作用是改變構造函數中this的指向,二者唯一的區別在一參數傳遞的方式不同,如:

function Person (name, age, sex) {

this.name = name;

this.age = age;

this.sex = sex;

}

function Student (name, age, sex, grade){

Person.call(this, name, age, sex)//call傳參

Person.apply(this, [name, age, sex])//apply傳參使用數組

this.grade = grade;

}

1

2

3

4

5

6

7

8

9

10

11

原型鏈

定義:顧名思義,原型鏈就是將一個個原型串連起來,形成一條原型繼承的鏈子。

原型鏈的構成

如下代碼例子, Son繼承Father, Father繼承Grand, 而Grand沒有自定義原型,所以默認為原型鏈的最頂端new Object();為什麼Object為最頂端,因為Object.prototype為null,為null是沒有原型的。

//原型鏈 Son --> new Father() --> new Grand() --> new Object();

function Grand () {

}

Father.prototype = new Grand();

function Father () {

}

Son.prototype = new Father();

function Son () {

}

var son = new Son();

console.log(son);

1

2

3

4

5

6

7

8

9

10

11

原型鏈上屬性的增刪改查

以上述原型鏈為例說明:Son --> new Father() --> new Grand() --> new Object()

為son實例對象添加屬性,總是添加為其自己本身的屬性,為對原型和原型鏈是沒有影響的。(再具體說即對和其相同構造函數構造的實例對象無法造成影響,以下說法同此)

使用delete操作符只能刪除son實例對象自己本身的屬性,而無法刪除由原型繼承而來的屬性.

若修改的屬性為繼承自原型的,且值類型為原始值,則僅僅修改的是該實例對象的屬性,對原型無法造成影響。

若修改的屬性為繼承自原型的,屬性值類型為引用值,則對引用值的修改又分兩種情況

是直接對該修改的屬性賦值 => 此情況僅僅修改的是實例對象的該屬性,無法對原型造成影響

對該修改的屬性添加內容或去除內容,而不是對其重新賦值 => 此情況會對原型造成影響。如下例

Person.prototype = {

has : [1, 2, 3]

}

function Person () {

this.name = "shoujing";

}

var person1 = new Person();

var person2 = new Person();

person1.has.push(4);

//person1 和 person2都改變了,因為person1的修改影響到了原型,進而影響到了另一個實例對象

console.log(person1.has); //[1, 2, 3, 4]

console.log(person2.has); // [1, 2, 3, 4]

1

2

3

4

5

6

7

8

9

10

11

12

查詢過程如下,首先看構造函數中是否有要查詢的屬性,若有,則直接返回,若沒有,則看其原型有沒有要查詢的屬性,若沒有,則再看原型的原型上是否有要查詢的屬性,以此順序在原型鏈上查詢,若一直到原型鏈頂端後仍沒有要查詢的屬性,則返回undefined

絕大多數對象最終都會繼承自Object.prototype

null,和undefined是沒有原型的

對象繼承史

傳統模式

即正常的通過構造函數創建實例對象,來繼承原型–>原型鏈

缺點:繼承了過多不必要的屬性

借用構造函數

原理是通過call/apply改變構造函數內this對象的引用

不能繼承借用構造函數的原型

每次構造函數都要多走一個函數

舉例

function Person (name, age, sex) {

this.name = name;

this.age = age;

this.sex = sex;

}

function Student (name, age, sex, grade){

Person.call(this, name, age, sex)//call傳參

//Person.apply(this, [name, age, sex])//apply傳參使用數組

this.grade = grade;

}

var student = new Student("張三", 18, "male", 2107);

console.log(student);

1

2

3

4

5

6

7

8

9

10

11

12

13

共享原型

即將其他構造函數的原型直接賦值給本構造函數的原型

兩個原型會相互影響,更改其中一個原型,另一個對應的原型也會被更改。

舉例

Person.prototype = {

name : "shoujing",

age : 18,

sex : "male"

}

function Person () {

this.hooby = "sing";

}

Student.prototype = Person.prototype;

function Student() {

this.grade = 2017;

}

Son.prototype = Person.prototype;

function Son () {

this.grand = "luo";

}

var person = new Person();

var student = new Student();

var son = new Son();

console.log(person.age);//18

console.log(student.age);//18

console.log(son.age);//18

//原型繼承成功

Student.prototype.age = 20;//更改其中一個原型的age屬性

console.log(student.age);//20

console.log(son.age);//20

//繼承Person原型的Student和Son相互影響

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

聖杯模式

每次繼承的都是新創建的F構造函數實例,相互之間不會影響。其實此處針對F形成了閉包,Target引用了F,導致F不會銷毀。

正常函數形式:

function inherit (Target, Origin) {

// 借用F這個中間量來繼承,而不是直接共享原型

var F = function (){}

F.prototype = Origin.prototype;

Target.prototype = new F();

// 自定義構造函數原型時,同時要更正自定義原型的constructor,否則一般默認為Object(),次函數若不指定constructor,則constructor為Origin

Target.prototype.constructor = Target;

Target.prototype.uber = Origin; //記錄真正繼承的是誰

}

1

2

3

4

5

6

7

8

9

10

閉包形式(推薦,YUI)

var inherit = (function(){

var F = function (){};

return function (Target, Origin) {

F.prototype = Origin.prototype;

Target.prototype = new F();

Target.prototype.constructor = Target;

Target.prototype.uber = Origin;

}

})();

1

2

3

4

5

6

7

8

9

命名空間

我們可以利用對象(閉包)創建命名空間來管理變數,防止污染全局,適用於模塊開發,舉個例子:

var workSpace = {

person1: {

name: "one",

age: 18

},

person2: {

name: "two",

age: 20

}

}

// 這樣兩個人雖然有同名變數,但不會相互影響,因為位於不同命名空間

// 訪問第一個人的姓名

console.log(workSpace.person1.name); // one

console.log(workSpace.person2.name); //two

1

2

3

4

5

6

7

8

9

10

11

12

13

14

對象枚舉

prop in obj

var obj = {

name : "123",

age : 18,

sex : "male",

height : 180,

weight : 75,

}

for (var prop in obj) {

console.log(obj[prop]);

}

1

2

3

4

5

6

7

8

9

10

obj.hasOwnProperty(『prop』);

該方法的作用是來判斷對象obj的自身屬性中是否含有屬性prop,自身屬性是在構造函數中生成的或者實例對象後來自己添加的,而繼承屬性則是從原型上繼承的屬性,所以該方法就是判斷該屬性是從原型繼承來的還是自身的。返回結果為true,則為自身屬性。

var obj = {

name : "123",

age : 18,

sex : "male",

height : 180,

weight : 75,

__proto__ : {

lastName : "deng"

}

}

for (var prop in obj) {

if(obj.hasOwnProperty(prop)) {

console.log(obj[prop]);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

object instanceof Object;

instanceof操作符用來判斷object實例對象是否為Object構造函數創建的,舉例

Person.prototype.age = 18;

function Person () {

this.name = "lyl";

}

var person = new Person();

console.log(person instanceof Person); // true

console.log(new Object() instanceof Person); //false

---------------------

作者:shoujing1001

原文:https://blog.csdn.net/shoujing1001/article/details/85487979

版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

JS學習筆記 對象、包裝類、原型、原型鏈、命名空間、對象枚舉

打開今日頭條,查看更多圖片
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

默認終端 + iTerm2 + agnoster theme +……打造macOS終端
前端項目中常用es6知識總結——箭頭函數及this指向、尾調用優化

TAG:程序員小新人學習 |