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

資訊專欄INFORMATION COLUMN

條理清晰的JavaScript面向?qū)ο?

elliott_hu / 2159人閱讀

摘要:當(dāng)去調(diào)用一個(gè)函數(shù)這個(gè)時(shí)候函數(shù)中的就指向創(chuàng)建出來的對(duì)象而且函數(shù)的的返回值直接就是隱式返回有一個(gè)默認(rèn)慣例就是構(gòu)造函數(shù)的名字首字母大寫。面向?qū)ο箨P(guān)注特征和功能。

最近一直在搞基礎(chǔ)的東西,弄了一個(gè)持續(xù)更新的github筆記,可以去看看,誠意之作(本來就是寫給自己看的……)鏈接地址:Front-End-Basics

此篇文章的地址:面向?qū)ο?

基礎(chǔ)筆記的github地址:https://github.com/qiqihaobenben/Front-End-Basics ,可以watch,也可以star。

正文開始…… JavaScript的面向?qū)ο?/b> JavaScript的對(duì)象

對(duì)象是JavaScript的一種數(shù)據(jù)類型。對(duì)象可以看成是屬性的無序集合,每個(gè)屬性都是一個(gè)鍵值對(duì),屬性名是字符串,因此可以把對(duì)象看成是從字符串到值的映射。這種數(shù)據(jù)結(jié)構(gòu)在其他語言中稱之為“散列(hash)”、“字典(dictionary)”、“關(guān)聯(lián)數(shù)組(associative array)”等。

原型式繼承:對(duì)象不僅僅是字符串到值的映射,除了可以保持自有的屬性,JavaScript對(duì)象還可以從一個(gè)稱之為原型的對(duì)象繼承屬性,對(duì)象的方法通常是繼承的屬性,這是JavaScript的核心特征。

JavaScript對(duì)象是動(dòng)態(tài)的—可以新增屬性也可以刪除屬性,但是他們常用來模擬靜態(tài)以及靜態(tài)類型語言中的“結(jié)構(gòu)體”

創(chuàng)建對(duì)象 1、對(duì)象直接量

創(chuàng)建對(duì)象最簡(jiǎn)單的方式就是在JavaScript代碼中使用對(duì)象直接量。

var book = {
            "main title": "guide",  //屬性名字里有空格,必須加引號(hào)
            "sub-title": "JS",  //屬性名字里有連字符,必須加引號(hào)
            for: "development",  //for是關(guān)鍵字,不過從ES5開始,作為屬性名關(guān)鍵字和保留字可以不加引號(hào)
            author: {
                firstname: "David",  //這里的屬性名就都沒有引號(hào)
                surname: "Flanagan"
            }
        }

注意: 從ES5開始,對(duì)象直接量中的最后一個(gè)屬性后的逗號(hào)將被忽略。

擴(kuò)展: [JavaScript中的關(guān)鍵字和保留字
](http://blog.mingsixue.com/it/...

2、通過new創(chuàng)建對(duì)象

new 運(yùn)算符創(chuàng)建并初始化一個(gè)新對(duì)象。關(guān)鍵字new后跟一個(gè)函數(shù)調(diào)用。這里的函數(shù)稱做構(gòu)造函數(shù)(constructor),構(gòu)造函數(shù)用以初始化一個(gè)新創(chuàng)建的對(duì)象。JavaScript中的數(shù)據(jù)類型都包含內(nèi)置的構(gòu)造函數(shù)。

var o = new Object(); //創(chuàng)建一個(gè)空對(duì)象,和{}一樣。
var arr = new Array(); //創(chuàng)建一個(gè)空數(shù)組,和[]一樣。

擴(kuò)展 1:new

new 是一個(gè)一元運(yùn)算符,專門運(yùn)算函數(shù)的。new后面調(diào)用的函數(shù)叫做構(gòu)造函數(shù),構(gòu)造函數(shù)new的過程叫做實(shí)例化。
當(dāng)new去調(diào)用一個(gè)函數(shù) : 這個(gè)時(shí)候函數(shù)中的this就指向創(chuàng)建出來的對(duì)象,而且函數(shù)的的返回值直接就是this(隱式返回)
有一個(gè)默認(rèn)慣例就是構(gòu)造函數(shù)的名字首字母大寫。

注意:
當(dāng)return的時(shí)候,如果是后面為簡(jiǎn)單類型,那么返回值還是這個(gè)對(duì)象;
如果return為對(duì)象類型,那么返回的就是return后面的這個(gè)對(duì)象。

擴(kuò)展 2:基本類型和對(duì)象類型(復(fù)雜類型)的區(qū)別

賦值:
基本類型 : 賦值的時(shí)候只是值的復(fù)制
對(duì)象類型 : 賦值不僅是值的復(fù)制,而且也是引用的傳遞(可以理解為內(nèi)存地址)可以理解為賦址。

比較相等
基本類型 : 值相同就可以
對(duì)象類型 : 值和引用都相同才行

擴(kuò)展 3:原型 prototype

每一個(gè)JavaScript對(duì)象(null除外)都和另一個(gè)對(duì)象相關(guān)聯(lián),這個(gè)對(duì)象就是原型,每一個(gè)對(duì)象都從原型繼承屬性。

3、Object.create()

Object.create() 這個(gè)方法是ES5定義的,它創(chuàng)建一個(gè)新對(duì)象,其中第一個(gè)參數(shù)是這個(gè)對(duì)象的原型。第二個(gè)參數(shù)是可選參數(shù),用以對(duì)對(duì)象屬性進(jìn)行進(jìn)一步描述。

可以通過傳入?yún)?shù) null 創(chuàng)建一個(gè)沒有原型的新對(duì)象,不過這個(gè)新對(duì)象不會(huì)繼承任何東西,甚至不包括基礎(chǔ)方法。
var o = Object.create(null); //o不會(huì)繼承任何屬性和方法,空空的。

如果想創(chuàng)建一個(gè)普通的空對(duì)象,需要傳入Object.prototype
var o = Object.create(Object.prototype); //o相當(dāng)于{}

對(duì)象屬性的獲取和設(shè)置

可以通過點(diǎn)(.)或方括號(hào)([])運(yùn)算符來獲取和設(shè)置屬性的值。

var author = book.author;
var title = book["main title"];

在JavaScript中能用 . 連接的都可以用 []連接。有很多 . 運(yùn)算符不能用的時(shí)候,就需要用[]代替。
1、在屬性名可變的情況下用[]

function getAttr (obj, attr) {
    console.log(obj[attr])
}

2、屬性名有空格或者連字符等時(shí)用[]
var title = book["main title"];

刪除屬性

delete運(yùn)算符可以刪除對(duì)象的屬性。
delete只是斷開屬性和宿主對(duì)象的聯(lián)系,而不會(huì)去操作屬性中的屬性,如果刪除的屬性是個(gè)對(duì)象,那么這個(gè)對(duì)象的引用還是存在的。

var a = {b:{c:1}};
var b = a.b;
console.log(b.c); // 1
console.log(a.b); // {c:1}
delete a.b;
console.log(b.c); // 1
console.log(a.b); //undefined

delete只能刪除自有屬性,不能刪除繼承屬性。

返回值
返回值為true

當(dāng)delete表達(dá)式刪除成功或沒有任何副作用(比如刪除不存在的屬性),或者delete后不是一個(gè)屬性訪問表達(dá)式,delete會(huì)返回 true ;

var a = {b:{c:1}};
console.log(delete a.b);
console.log(delete a.b);
console.log(delete a.toString);
console.log(delete 1);

以上都會(huì)打印true
返回值為false

delete不能刪除那些可配置性為false的屬性,例如某些內(nèi)置對(duì)象的屬性是不可配置的,通過變量聲明和函數(shù)聲明創(chuàng)建的全局對(duì)象的屬性。

var a = {};
Object.defineProperty(a,"b",{
    value:1,
    configurable: false // 設(shè)置為不可配置
})
console.log(delete a.b)
console.log(delete Object.prototype)
var x = 1;
console.log(delete this.x);
console.log(delete x)

以上打印都為false
檢測(cè)屬性 in 運(yùn)算符

in 運(yùn)算符的左側(cè)是屬性名(字符串),右側(cè)是對(duì)象。如果對(duì)象的自有屬性或繼承屬性中包含這個(gè)屬性則返回true。

var a = {b:1};
console.log("a" in window); // true 聲明的全局變量"a"是window的屬性
console.log("b" in a); // true "b"是a的屬性
console.log("toString" in a); // true a繼承了toString屬性
console.log("c" in a); // false "c"不是a的屬性

跟in運(yùn)算符類似的,還可以用"!=="判斷一個(gè)屬性是否是undefined,但是有一種場(chǎng)景只能使用in運(yùn)算符,in可以區(qū)分不存在的屬性和存在但值為undefined的屬性。

var a = {b:undefined};
console.log(a.b !== undefined); //false
console.log(a.c !== undefined); //false
console.log("b" in a); //true
console.log("c" in a); //false
hasOwnProperty

對(duì)象的hasOwnProperty()方法用來檢測(cè)給定的名字是否是對(duì)象的自有屬性。對(duì)于繼承屬性它將返回false

var a = {b:1};
console.log(a.hasOwnProperty("b")); //true
console.log(a.hasOwnProperty("c")); //false
console.log(a.hasOwnProperty("toString")); //false toString是繼承屬性
propertyIsEnumerable

對(duì)象的propertyIsEnumerable()方法只有檢測(cè)到是自身屬性(不包括繼承的屬性)且這個(gè)屬性的可枚舉性為true時(shí)它才返回true。

var a = {b:1};
console.log(a.propertyIsEnumerable("b"));
console.log(a.propertyIsEnumerable("toString"));
包裝對(duì)象

當(dāng)使用原始類型的值(string、number、boolean),在調(diào)用對(duì)應(yīng)屬性和方法的時(shí)候,內(nèi)部會(huì)自動(dòng)轉(zhuǎn)成對(duì)應(yīng)的對(duì)象。隱式創(chuàng)建的這個(gè)對(duì)象,就成為包裝對(duì)象。
基本類型都有自己對(duì)應(yīng)的包裝對(duì)象 : String Number Boolean

包裝對(duì)象的特點(diǎn)  
隱式創(chuàng)建對(duì)象后,可以調(diào)用對(duì)應(yīng)的屬性和方法
使用后,立馬銷毀,所以不能給原始類型的值添加屬性和方法

其過程舉例:str.substring - > new String(1234) - > 找到String的substring -> 將new String銷毀

對(duì)象方法和屬性的匯總 Object靜態(tài)方法

Object.assign()

Object.create()

Object.defineProperty()

Object.defineProperties()

Object.entries()

Object.preventExtensions()

Object.isExtensible()

Object.seal()

Object.isSealed()

Object.freeze()

Object.isFrozen()

Object.keys()

Object.values()

Object.getPrototypeOf()

Object.getOwnPropertyNames()

Object.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptors()

Object的實(shí)例方法(定義在Object.prototype上的)

Object.prototype.hasOwnProperty()

Object.prototype.isPrototypeOf()

Object.prototype.propertyIsEnumerable()

Object.prototype.toString()

Object.prototype.valueOf()


面向?qū)ο?/b> 編碼思想

兩種編程方式:
(1)、面向過程
(2)、面向?qū)ο?

兩者的區(qū)別:
面向過程:關(guān)注實(shí)現(xiàn)過程和每一步的實(shí)現(xiàn)細(xì)節(jié)。
面向?qū)ο螅宏P(guān)注特征和功能。

面向?qū)ο缶幊?/b>

通俗點(diǎn),用對(duì)象的思想寫代碼就是面向?qū)ο缶幊獭?/p> 基本特征

1、抽象:抓住核心問題(簡(jiǎn)單理解為抽出像的部分;將相同或表現(xiàn)與問題相關(guān)特征的內(nèi)容提取出來。)
其核心:抽出、抽離,將相同的部分(可能會(huì)維護(hù)、會(huì)迭代、會(huì)擴(kuò)展)的代碼抽離出來形成一類

2、封裝:就是將類的屬性包裝起來,不讓外界輕易知道它內(nèi)部的具體實(shí)現(xiàn);只提供對(duì)外接口以供調(diào)用

3、繼承:從已有對(duì)象上繼承出新的對(duì)象

4、多態(tài):一個(gè)對(duì)象的不同形態(tài)

面向?qū)ο蟮暮锰?/b>

1、代碼的層次結(jié)構(gòu)更清晰
2、更容易復(fù)用
3、更容易維護(hù)
4、更容易擴(kuò)展

面向?qū)ο笙嚓P(guān)的屬性和概念
__proto__   
屬性原型鏈,實(shí)例對(duì)象與原型之間的連接,叫做原型鏈。

對(duì)象身上只有 __proto__ 構(gòu)造函數(shù)身上有prototype也有 __proto__


constructor  
返回創(chuàng)建實(shí)例對(duì)象的構(gòu)造函數(shù)的引用,每個(gè)原型都會(huì)自動(dòng)添加constructor屬性,for..in..遍歷原型是找不到這個(gè)屬性的。
var a = new A();
console.log(a.constructor == A) //true


hasOwnProperty  
可以用來判斷某屬性是不是這個(gè)構(gòu)造函數(shù)的內(nèi)部屬性(不包括繼承的)

語法: obj.hasOwnProperty(prop) 返回Boolean

function A (){
    this.b = 1;
}
var a = new A();
console.log(a.hasOwnProperty("b"));  //打印true 
console.log(a.hasOwnProperty("toString")); //toString是繼承屬性 打印 false
console.log(a.hasOwnProperty("hasOwnProperty")); //同上,打印false


instanceof  
二元運(yùn)算符,用來檢測(cè)一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性。

語法: object instanceof constructor 即檢測(cè) constructor.prototype 是否存在于參數(shù) object 的原型鏈上。

// 定義構(gòu)造函數(shù)
function C(){} 
function D(){} 

var o = new C();
o instanceof C; // true,因?yàn)?Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因?yàn)?D.prototype不在o的原型鏈上
o instanceof Object; // true,因?yàn)镺bject.prototype.isPrototypeOf(o)返回true
C.prototype instanceof Object // true,同上


toString  
返回一個(gè)表示該對(duì)象的字符串

作用:
1、進(jìn)行數(shù)字之間的進(jìn)制轉(zhuǎn)換

例如:var num = 255;
alert( num.toString(16) ); //結(jié)果就是"ff"

2、利用toString做類型的判斷

例如:var arr = [];
alert( Object.prototype.toString.call(arr) == "[object Array]" );     彈出true
Object.prototype.toString.call()    得到是類似于"[object Array]"  "[object Object]"
面向?qū)ο蟮膶懛v程 1、原始模式

假如我們有一個(gè)對(duì)象是狗的原型,這個(gè)原型有“名字”和“顏色”兩個(gè)屬性。

var Dog = {
    name: "",
    color: ""
}

根據(jù)這個(gè)原型對(duì)象,我們要生成一個(gè)實(shí)例對(duì)象如下

var hashiqi = {}; //創(chuàng)建空對(duì)象,之后根據(jù)原型對(duì)象的相應(yīng)屬性賦值
hashiqi.name = "hashiqi";
hashiqi.color = "blackandwhite";

缺點(diǎn):
1、如果要生成多個(gè)實(shí)例對(duì)象,要重復(fù)寫多次。
2、實(shí)例和原型之間沒有聯(lián)系。

2、工廠模式

上面原始模式有一個(gè)缺點(diǎn)是要很麻煩的寫很多重復(fù)的代碼,我們可以寫一個(gè)函數(shù)來解決代碼重復(fù)的問題。

function Dog(name, color) {
    var obj = {};
    obj.name = name;
    obj.color = color;
    return obj;
}

var hashiqi = Dog("hashiqi", "blackandwhite");
var jinmao = Dog("jinmao", "yellow");

這種方式只是解決了代碼重復(fù)的問題,但是生成的實(shí)例跟原型還是沒有聯(lián)系,而且hashiqijinmao也沒有聯(lián)系,不能反映出他們是同一個(gè)原型對(duì)象的實(shí)例。

3、構(gòu)造函數(shù)模式

用來創(chuàng)建對(duì)象的函數(shù),叫做構(gòu)造函數(shù),其實(shí)就是一個(gè)普通函數(shù),但是默認(rèn)函數(shù)名首字母大寫,對(duì)構(gòu)造函數(shù)使用new運(yùn)算符,就能生成實(shí)例,并且this變量會(huì)綁定在實(shí)例對(duì)象上。

function Dog(name, color) {
    this.name = name;
    this.color = color;
}

var hashiqi = new Dog("hashiqi", "blackandwhite");
var jinmao = new Dog("jinmao", "yellow");
console.log(hashiqi.name); //hashiqi
console.log(jinmao.name); //jinmao

hasiqi 和 jinmao有一個(gè)共同的構(gòu)造函數(shù) hashiqi.constructor === jinmao.constructor 是true

有以下幾種方法可以驗(yàn)證原型對(duì)象與實(shí)例對(duì)象的關(guān)系:

hashiqi instanceof Dog; // true

Object.getPrototypeOf(hashiqi) === Dog.prototype // true

Dog.prototype.isPrototypeOf(hashiqi) // true

缺點(diǎn):
構(gòu)造函數(shù)解決了代碼重復(fù)和實(shí)例與原型之間的聯(lián)系,但是存在一個(gè)浪費(fèi)內(nèi)存的問題。比如遠(yuǎn)行對(duì)象有一些不變的屬性和通用的方法,這樣沒生成一個(gè)實(shí)例,都必須為重復(fù)的東西多占一些內(nèi)存。

擴(kuò)展

我們可以嘗試實(shí)現(xiàn)new運(yùn)算符的邏輯如下:

function New(func) {
    var obj = {};

    //判斷構(gòu)造函數(shù)是否存在原型,如果有實(shí)例的__proto__屬性就指向構(gòu)造函數(shù)的prototype
    if(func.prototype !== undefined) {
        obj.__proto__ = func.prototype;
    }

    // 模擬出構(gòu)造函數(shù)內(nèi)部this指向?qū)嵗倪^程,注意,我們會(huì)拿到構(gòu)造函數(shù)的返回值
    var res = func.apply(obj, Array.from(arguments).slice(1));

    // 正常構(gòu)造函數(shù)是不需要顯式聲明返回值的,默認(rèn)的返回值是生成的實(shí)例,但是一旦在構(gòu)造函數(shù)中return 一個(gè)不是對(duì)象或者函數(shù),就會(huì)改變構(gòu)造函數(shù)的默認(rèn)的返回值,其他的類型是不變的
    if(typeof res === "object" && res !== null || typeof res === "function") {
        return res;
    }

    return obj;
}

var taidi = New(Dog, "taidi", "gray");

注意:
正常的構(gòu)造函數(shù)是不需要自己寫return 的,如果寫了,當(dāng)return的時(shí)候,如果是后面為簡(jiǎn)單類型,那么返回值還是構(gòu)造函數(shù)生成的實(shí)例。如果return為對(duì)象類型或者函數(shù),那么返回的就是return后面的這個(gè)對(duì)象或者函數(shù)。

4、prototype模式

每一個(gè)構(gòu)造函數(shù)都有 prototype 屬性,這個(gè)屬性指向的是一個(gè)對(duì)象,這個(gè)對(duì)象的所有屬性和方法,都會(huì)被構(gòu)造函數(shù)的實(shí)例繼承。
基于這個(gè)屬性,我們就可以有選擇性的將一些通用的屬性和方法定義到 prototype 上,每一個(gè)通過 new 生成的實(shí)例,都會(huì)有一個(gè) __proto__ 屬性指向構(gòu)造函數(shù)的原型即 prototype ,這樣我們定義到構(gòu)造函數(shù)原型對(duì)象的屬性和方法,就會(huì)被每一個(gè)實(shí)例訪問到,從而變成公用的屬性和方法。

function Dog(name, color) {
    this.name = name;
    this.color = color;
}
Dog.prototype.say = function () {
    console.log("汪汪");
}

var hashiqi = new Dog("hashiqi", "blackandwhite");
var jinmao = new Dog("jinmao", "yellow");

hashiqi.say(); // 汪汪
jinmao.say(); // 汪汪
console.log(hashiqi.say === jinmao.say); // true

注意:當(dāng)實(shí)例對(duì)象和原型對(duì)象有相同的屬性或者方法時(shí),會(huì)優(yōu)先訪問實(shí)例對(duì)象的屬性或方法。

面向?qū)ο蟮睦^承 1、構(gòu)造函數(shù)內(nèi)部的屬性和方法繼承

使用call或apply方法,將父對(duì)象的構(gòu)造函數(shù)綁定在子對(duì)象上。

//父類
function Animal() {
    this.species = "動(dòng)物";
}

//子類
function Dog(name, color) {
    Animal.call(this);
    this.name = name;
    this.color = color;
}

var hashiqi = new Dog("hashiqi", "blackandwhite");
console.log(hashiqi.species); //動(dòng)物
2、prototype相關(guān)的繼承
子類的prototype指向父類生成實(shí)例
function Animal() {};
Animal.prototype.species = "動(dòng)物";
function Dog(name, color) {
    this.name = name;
    this.color = color;
}
Dog.prototype = new Animal();
//只要是prototype被完全覆蓋,都得重寫constructor。
Dog.prototype.constructor = Dog;
var hashiqi = new Dog("hashiqi", "blackandwhite");

缺點(diǎn): 每一次繼承都得生成一個(gè)父類實(shí)例,比較占內(nèi)存。


利用空對(duì)象作為中介
function Animal() {}
Animal.prototype.species = "動(dòng)物";
function Dog(name, color) {
    this.name = name;
    this.color = color;
}
//Middle生成的是空實(shí)例(除了__proto__),幾乎不占內(nèi)存
function Middle() {}
Middle.prototype = Animal.prototype;
Dog.prototype = new Middle();
Dog.prototype.constructor = Dog;
var hashiqi = new Dog("hashiqi", "blackandwhite");
console.log(hashiqi.species);

幾個(gè)月前在 CSDN 面試的時(shí)候,我說了這種繼承方式,面試官就糾結(jié)這樣修改子類的prototype不會(huì)影響父類么?是真的不會(huì)影響的,因?yàn)樽宇惖膒rototype是指向Middle構(gòu)造函數(shù)生成的實(shí)例,如果真的有心要改,得Dog.prototype.__proto__這么著來改。


Object.create()
function Animal() {}
Animal.prototype.species = "動(dòng)物";
function Dog(name, color) {
    this.name = name;
    this.color = color;
}
Dog.prototype = Object.create(Animal.prototype,{
    constructor: {
        value: Dog
    }
})

var hashiqi = new Dog("hashiqi","blackandwhite");
console.log(hashiqi.species); //動(dòng)物
3、拷貝繼承
淺拷貝
function Animal() {}
Animal.prototype.species = "動(dòng)物";
function Dog(name, color) {
    this.name = name;
    this.color = color;
}
function extend(child, parent) {
    var c = child.prototype;
    var p = parent.prototype;
    for(key in p) {
        c[key] = p[key]
    }
}
extend(Dog, Animal);
var hashiqi = new Dog("hashiqi", "blackandwhite");
console.log(hashiqi.species) // 動(dòng)物


深拷貝
function deepCopy(parent, child) {
    var child = child || {};
    for(key in parent) {
        if(typeof parent[key] === "object") {
            child[key] = parent[key].constructor === Array?[]:{};
            deepCopy(parent[key],child[key])
        } else {
            child[key] = parent[key];
        }
    }
    return child;
}
ES6的面向?qū)ο?/b>

上面所說的是JavaScript語言的傳統(tǒng)方法,通過構(gòu)造函數(shù),定義并生成新的對(duì)象。
ES6中提供了更接近傳統(tǒng)語言的寫法,引入了Class(類)的概念,通過class關(guān)鍵字,可以定義類。

語法

ES6的類完全可以看成是構(gòu)造函數(shù)的另外一種寫法。

var method = "say";
class Dog {
    constructor (name,color) {
        this.name = name;
        this.color = color;
    }
 ? ?//注意,兩個(gè)屬性之間跟對(duì)象不同,不要加逗號(hào),并且類的屬性名可以使用變量或者表達(dá)式,如下
    [method] () {
        console.log("汪汪");
    }
}
console.log(typeof Dog); // function 類的數(shù)據(jù)類型就是函數(shù)
console.log(Dog === Dog.prototype.constructor); // true 類本身就是構(gòu)造函數(shù)

既然是構(gòu)造函數(shù),所以在使用的時(shí)候,也是直接對(duì)類使用new命令,跟構(gòu)造函數(shù)的用法完全一致。

var hashiqi = new Dog("hashiqi", "blackandwhite");
console.log(hashiqi.color); // blackandwhite

//上面采用表達(dá)式聲明的類的屬性可以用一下兩種方式調(diào)用
hashiqi[method](); // 汪汪
hashiqi.say(); // 汪汪

注意:
1、先聲明定義類,再創(chuàng)建實(shí)例,否則會(huì)報(bào)錯(cuò)
class 不存在變量提升,這一點(diǎn)與ES5的構(gòu)造函數(shù)完全不同

new Dog("hashiqi","blackandwhite")
class Dog {
    constructor (name,color) {
        this.name = name;
        this.color = color;
    }
}
//Uncaught ReferenceError: Dog is not defined
//上面代碼,Dog類使用在前,定義在后,因?yàn)镋S6不會(huì)把類的聲明提升到代碼頭部,所以報(bào)錯(cuò)Dog沒有定義。

2、必須使用new關(guān)鍵字來創(chuàng)建類的實(shí)例對(duì)象
類的構(gòu)造函數(shù),不使用new是沒法調(diào)用的,會(huì)報(bào)錯(cuò)。 這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別,后者不用new也可以執(zhí)行。

class Dog {
    constructor (name,color) {
        this.name = name;
        this.color = color;
    }
}
Dog(); // Uncaught TypeError: Class constructor Dog cannot be invoked without "new"

3、定義“類”的方法的時(shí)候,前面不需要加上function這個(gè)關(guān)鍵字,直接把函數(shù)定義放進(jìn)去了就可以了。并且,方法之間不需要逗號(hào)分隔,加了會(huì)報(bào)錯(cuò)。

屬性概念
constructor  構(gòu)造函數(shù)

構(gòu)造方法constructor是一個(gè)類必須要有的方法,默認(rèn)返回實(shí)例對(duì)象;創(chuàng)建類的實(shí)例對(duì)象的時(shí)候,會(huì)調(diào)用此方法來初始化實(shí)例對(duì)象。如果你沒有編寫constructor方法,執(zhí)行的時(shí)候也會(huì)被加上一個(gè)默認(rèn)的空的constructor方法。

constructor方法是必須的,也是唯一的,一個(gè)類體不能含有多個(gè)constructor構(gòu)造方法。

class Dog {
    constructor (name,color) {
        this.name = name;
        this.color = color;
    }
    //定義了兩個(gè)constructor,所以會(huì)報(bào)錯(cuò)
    constructor () {
        
    }
}
new Dog("hashiqi", "blackandwhite")
//Uncaught SyntaxError: A class may only have one constructor


Class表達(dá)式

與函數(shù)一樣,類可以使用表達(dá)式的形式定義。

const Hashiqi = class Dog {
    constructor (name,color) {
        this.name = name;
        this.color = color;
    }
    getName () {
        //此處的Dog就是Dog構(gòu)造函數(shù),在表達(dá)式形式中,只能在構(gòu)造函數(shù)內(nèi)部使用
        console.log(Dog.name);
    }
}
var hashiqi = new Hashiqi("hashiqi", "blackandwhite"); // 真正的類名是Hashiqi
var jinmao = new Dog("jinmao", "yellow"); // 會(huì)報(bào)錯(cuò),Dog沒有定義

通常我們的表達(dá)式會(huì)寫成如下,省略掉類后面的名稱

const Hashiqi = class {
    constructor (name,color) {
        this.name = name;
        this.color = color;
    }
}
var hashiqi = new Hashiqi("hashiqi", "blackandwhite");


實(shí)例方法和靜態(tài)方法  
實(shí)例化后的對(duì)象才可以調(diào)用的方法叫做實(shí)例方法。
直接使用類名即可訪問的方法,稱之為“靜態(tài)方法”

類相當(dāng)于實(shí)例的原型,所有在類中定義的方法,都會(huì)被實(shí)例繼承。如果在一個(gè)方法前,加上static關(guān)鍵字,就表示該方法不會(huì)被實(shí)例繼承,而是直接通過類來調(diào)用,這就稱為“靜態(tài)方法”。

class Dog {
    constructor (name,color) {
        this.name = name;
        this.color = color;
    }
    static say () {
        console.log("汪汪");
    }
}
Dog.say(); //汪汪

靜態(tài)方法和實(shí)例方法不同的是:靜態(tài)方法的定義需要使用static關(guān)鍵字來標(biāo)識(shí),而實(shí)例方法不需要;此外,靜態(tài)方法通過類名來的調(diào)用,而實(shí)例方法通過實(shí)例對(duì)象來調(diào)用。

類的繼承
extends

類之間可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承,這比ES5的通過修改原型鏈實(shí)現(xiàn)繼承,要清晰和方便很多。

class Dog extends Animal{}

extends的繼承目標(biāo)
extends關(guān)鍵字后面可以跟多種類型的值,有三種特殊情況

1、子類繼承Object類

class A extends Object {}
console.log(A.__proto__ === Object) //true
console.log(A.prototype.__proto__ == Object.prototype) //true
//這種情況下,A其實(shí)就是構(gòu)造函數(shù)Object的復(fù)制,A的實(shí)例就是Object的實(shí)例。

2、不存在繼承

class A {}

console.log(A.__proto__ === Function.prototype) // true
console.log(A.prototype.__proto__ === Object.prototype) // true
//這種情況下,A作為一個(gè)基類(即不存在任何繼承),就是一個(gè)普通函數(shù),所以直接繼承Funciton.prototype。
//但是,A調(diào)用后返回一個(gè)空對(duì)象(即Object實(shí)例),所以A.prototype.__proto__指向構(gòu)造函數(shù)(Object)的prototype屬性。

3、子類繼承null

class A extends null {}
console.log(A.__proto__ === Function.prototype) //true
console.log(A.prototype) //只有一個(gè)constructor屬性,沒有__proto__屬性
這種情況與第二種情況非常像。A也是一個(gè)普通函數(shù),所以直接繼承Funciton.prototype。
但是,A調(diào)用后返回的對(duì)象不繼承任何方法,所以沒有__proto__這屬性


super

uper這個(gè)關(guān)鍵字,既可以當(dāng)作函數(shù)使用,也可以當(dāng)作對(duì)象使用。

1、super作為函數(shù)調(diào)用時(shí),代表父類的構(gòu)造函數(shù)。作為函數(shù)時(shí),super()只能用在子類的構(gòu)造函數(shù)之中,用在其他地方就會(huì)報(bào)錯(cuò)。

2、super作為對(duì)象時(shí),在普通方法中,指向父類的原型對(duì)象;在靜態(tài)方法中,指向父類。

class Animal {
    constructor (name) {
        this.name = name;
        this.species = "動(dòng)物";
    }
    say (){
        return this.species;
    }
}
class Dog extends Animal{
    constructor (name, color) {
        // 只要是自己在子類中定義constructor,必須調(diào)用super方法,否則新建實(shí)例會(huì)報(bào)錯(cuò)
        //super作為函數(shù)調(diào)用,只能用在子類的constructor中
        super(name);
        this.color = color;
    }
    getInfo () {
        //普通方法中,super指向父類的原型對(duì)象
        console.log(super.say()+": "+this.name +","+this.color);
    }
}
var hashiqi = new Dog("hashiqi", "blackandwhite");
hashiqi.getInfo() //動(dòng)物:hashiqi,balckandwhite

注意:
1、子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)。這是因?yàn)樽宇悰]有自己的this對(duì)象,而是繼承父類的this對(duì)象,然后對(duì)其進(jìn)行加工。如果不調(diào)用super方法,子類就得不到this對(duì)象。

2、在子類的普通方法中,由于super指向父類的原型對(duì)象,所以定義在父類實(shí)例上的方法或?qū)傩?,是無法通過super調(diào)用的。

3、使用super的時(shí)候,必須顯式指定是作為函數(shù)、還是作為對(duì)象使用,否則會(huì)報(bào)錯(cuò)。

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

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

相關(guān)文章

  • 條理清晰Ajax基礎(chǔ)講解

    摘要:在拼接數(shù)據(jù)的時(shí)候要用來包一下,不然在低版本瀏覽器中使用中文會(huì)亂碼的。如果后端返回的內(nèi)容有中文編碼格式,那么直接輸入到頁面中就能變成中文了。事件這個(gè)事件會(huì)在瀏覽器接收新數(shù)據(jù)期間周期性地觸發(fā)。 最近一直在搞基礎(chǔ)的東西,弄了一個(gè)持續(xù)更新的github筆記,可以去看看,誠意之作(本來就是寫給自己看的……)鏈接地址:Front-End-Basics 此篇文章的地址:Ajax基礎(chǔ)相關(guān) 基礎(chǔ)...

    The question 評(píng)論0 收藏0
  • PHP面向對(duì)象編程偷懶技巧-代碼重用等總結(jié)

    摘要:一個(gè)不相關(guān)的總結(jié)鄙人現(xiàn)在寫代碼容易用一句話總結(jié)根本停不下來。這種狀況讓人生活狀態(tài)極差,黑夜白天顛倒,飽一頓餓一頓,體質(zhì)下降,妹紙盡失我要遠(yuǎn)離這種狀態(tài)。所以決定以后寫代碼盡可能只寫到點(diǎn),要緊的話再趕趕,一般就停下來寫寫總結(jié)泡泡腳藍(lán)后碎覺。 1、OOP在粗粒度上面向?qū)ο螅诩?xì)粒度上面向過程:即總體上看起來是一個(gè)模塊一個(gè)模塊的,細(xì)分起來還是需要一步一步執(zhí)行的; 2、OOP提高了代碼重用效率,...

    xiaodao 評(píng)論0 收藏0
  • 2018年騰訊前端二面總結(jié)(面向2019屆學(xué)生)

    摘要:前言很認(rèn)真的說吧,在和騰訊面試官的面試的過程。騰訊二面自我介紹二面的面試官和一面不是同一個(gè)面試官,所以在這個(gè)時(shí)候,我的基本介紹還是和一面一樣,介紹自己的基本信息,以及怎么想到學(xué)習(xí)前端和怎么學(xué)習(xí)前端。 前言 很認(rèn)真的說吧,在和騰訊面試官的面試的過程。有點(diǎn)感覺是在聊天一樣,他們是面試官,但是感覺更像是引路人,不管結(jié)果的好壞,在騰訊面試的過程,只要你認(rèn)真去聽去問,就可以學(xué)到很多東西吧。 如果...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<