JS基本之數據類型、對象、原型、原型鏈、繼續

數據範例:

簡樸數據範例:Undefined、Null、String、Number、Boolean、Symbol
龐雜數據範例:Object 
// Undefined:聲明,但未初始化
// Null:空對象指針

typeof操作符(檢測基礎數據範例):

typeof的返回值有哪些:
1. undefined  // 聲明和未初始化的變量,運用typeof都邑返回Undefined
2. boolean
3. string
4. number
5. object  // 當是object、null、array時
6. function // 函數是對象,不是一種數據範例,因為特別,typeof把它從對象中區分出來。typeof 正則也返回function)

typeof 的用處是檢測基礎數據範例,檢測援用範例數的值時,用instanceof

instanceof操作符(肯定實例和原型之間關聯):

如果變量是給定援用範例的實例instanceof操作符就會返回true
比方:

person instanceof Object  
arr instanceof Array  
pattern instanceof RegExp  

(典範題目)推斷一個對象是否是數組:

  1. value instanceof Array
  2. Array.isArray(value)
  3. Object.prototype.toString.call(value) // [object Array]

建立對象:

1. 工場形式

function createPerson(name, age) {
    var o = new Object()     // 顯現地建立對象
    o.name = name
    o.age = age
    o.getName = function () {
        console.log(this.name)
    }
    return o      // 末了須要return
}

實在就是寫了一個函數,每次建立對象就是挪用這個函數。

長處:工場函數處理了建立多個相似對象的題目

瑕玷:沒有處理對象辨認題目(即如何曉得一個對象的範例 constructor)

2. 組織函數形式

組織函數可以建立特定範例的函數,像Object、Array如許的原生組織函數。我們可以建立自定義的組織函數

function Person(name, age) {
    this.name = name
    this.age = age
    this.getName = function() {
        console.log(this.name)
    }
}

var person1 = new Person('zhangsan', 18)
var person2 = new Person('lisi', 20)
new 操作符做了什麼:
1.建立一個新對象
2.將組織函數的作用於賦給新對象(因而this就只想新對象)
3.實行組織函數中的代碼(為這個新對象增加屬性)
4.返回新對象  

person1和person2離別保存着Person的一個差別實例,這兩個對象都有一個constructor(組織函數)屬性,該屬性指向Person

person1.constructor == Person  // true
person2.constructor == Person  // true

對象的constructor屬性最初是用來標識對象種別的。檢測對象範例照樣用instanceof更靠譜(++肯定實例和原型之間關聯++)

person1 instance Person //true        
person1 instance Object //true

組織函數還可以在另一個對象的作用域中挪用

var o = new Object()
Person.call(o, 'xiaoming', 12)  // 在o的作用於挪用Person組織函數,o就具有了Person一切的屬性和要領。
o.getName()   // 'xiaoming'

call()apply()的第一個參數是誰,就是在誰的作用於中挪用組織函數。

長處:(處理了對象辨認題目)建立自定義的組織函數意味着未來可以將它的實例標識為一種特定的範例(Person類),這也是組織函數形式賽過工場形式的處所

瑕玷:組織函數的每一個要領,都要在每一個實例上從新建立一遍。因而差別實例上的同名函數不相等。

person1.getName == person2.getName   // false

3. 原型形式

先明白一些觀點:
我們建立的每一個函數(比方組織函數)都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象(函數的原型對象),這個對象包含一切實例同享的屬性和要領prototype就是經由過程挪用組織函數而建立的誰人對象實例的原型對象。運用原型對象的優點是可以讓一切對象實例同享它所包含的屬性和要領。
比方:給組織函數Person的原型增加屬性和要領,那實例也會同享這些屬性和要領。

function Person() {}
Person.prototype.name = 'zhangsan'
Person.prototype.getName = function() {console.log(this.name)}
var person1 = new Person()
person1.getName()   // 'zhangsan'

每一個函數都有一個prototype屬性,指向該函數的原型對象。而原型對象又有一個constructor(組織函數)屬性,這個屬性是一個指向prototype屬性地點函數的指針。

比方:Person.prototype.constructor 指向 Person    

當挪用組織函數建立一個實例,該實例的內部將包含一個指針_proto_,指向組織函數的原型對象。這個銜接存在於實例與組織函數的原型對象之間,而不是存在於實例和組織函數之間。

Person.prototype.constructor-->Person      
實例person1._proto_-->Person.prototype
Person.prototype.isPrototypeOf(person1)  //true
Object.getPrototypeOf(person1) == Person.prototype  //true

hasOwnPropertyin:

hasOwnProperty檢測屬性存在於實例,照樣原型上。只需屬性值存在於實例時,才返回true
in操作符沒法檢測屬性存在於實例照樣原型上。只需經由過程對象能接見到屬性值,就返回true

function Person() {}
Person.prototype.name = 'zhangsan'
var person1 = new Person()
person1.sex = '男'

person1.hasOwnProperty('name')  //false
person1.hanOwnProperty('sex')  //true
name in person1  //true
sex in person1  // true

推斷屬性僅存在於原型:

function(obj, name) {
    return !obj.hasOwnProperty(name) && (name in obj)
}

for inObject.keys

for in // 實例和原型上一切可羅列的屬性(返回的是一切可以經由過程對象接見的,可羅列的屬性)   
Object.keys // 僅實例上可羅列的屬性 

重寫原型(從新設定constructor):

Person.prototype = {
    constructor: Person,
    name: 'zhangsan',
    getName: function() {
        console.log(this.name)
    }
}

長處:同享函數,不須要每次建立實例都從新建立同名函數。

瑕玷:屬性的同享

4. 組合運用組織函數形式和原型形式(認可度最高的形式)

建立自定義範例最經常使用的體式格局,運用最廣范、認可度最高
集兩種形式之長組織函數形式用於定義實例屬性,原型形式用於定義要領和同享的屬性。如許每一個實例都有本身的一份實例屬性副本,但同時又同享着對要領的援用,最大限制地節省了內存。

5. 動態原型形式
6. 寄生組織函數形式
7. 穩妥組織函數形式

建立對象總結

在沒有類的情況下,可以採納以下體式格局建立對象。

  • 工場形式:運用簡樸的函數建立對象,為對象增加屬性和要領,然後返回對象。這個形式厥後被組織函數形式所庖代。
  • 組織函數形式:可以建立自定義援用範例,可以像建立內置對象實例一樣運用new操作符。不過組織函數形式也有瑕玷,即他的每一個成員都沒法獲得復用,包含函數。因為函數可以不局限於任何對象,因而沒有來由不在多個對象間同享。
  • 原型形式:運用組織函數的prototype屬性來指定那些應當同享的屬性和要領。組合運用組織函數形式和原型形式時,運用組織函數定義實例屬性,運用原型定義同享的屬性和要領

繼承:

重要依託原型鏈來完成繼承

1. 原型鏈

原型鏈的重要頭腦:應用原型讓一個援用範例繼承另一個援用範例的屬性和要領

先回憶下組織函數、原型和實例的關聯:
每一個組織函數都有一個原型對象(prototype),原型對象都包含一個指向組織函數的指針(constructor),而實例都包含一個指向原型對象的內部指針。
那末,如果我們讓原型對象即是另一個範例的實例:

function SuperType() {
    this.type = true
}
SuperType.prototype.getSuperValue = function() {
    return this.type
}
function SubType() {
    this.subtype = false
}
// 繼承了SuperType
SubType.prototype = new SuperType()   //實例賦值給原型的體式格局
SubType.prototype.getSubValue() {
    return this.subtype
}
var instance = new SubType()
console.log(instance.getSuperValue())  // true

以上定義了兩個範例:SuperTypeSubType。每一個範例離別有一個屬性和要領。
SubType繼承了SuperType,而繼承是經由過程建立SuperType實例,並將該實例賦給SubType.prototype來完成的(以一個新範例的實例重寫原型對象)。因而,本來存在於SuperType的實例中的一切屬性和要領,如今也存在於SubType.prototype中了。
終究:instance指向SubType的原型,SubType的原型又指向SuperType的原型

當接見實例屬性時,首先在示例中搜刮該屬性,如果沒找到該屬性,則會繼承搜刮氣力的原型,如果還沒找到,就沿着原型鏈繼承往上找。

原型鏈的題目:

  1. 原型屬性會被一切實例所同享。此要領完成繼承,原型現實上變成了另一個範例的實例。SuperType的屬性就變成了SubType原型上的屬性了,就會被SubType的實例instance1、instance2等所繼承。
  2. 在建立子範例實例時,不能向超範例實例通報參數。

因而現實中很少零丁運用原型鏈。

function SuperType() {
    this.colors = ['red', 'blue']
}
function SubType() {}

SubType.prototype = new SuperType()  // 繼承了SuperType

var instance1 = new SubType()
instance1.colors.push('black')
console.log(instance.coloes)  // 'red', 'blue', 'black'

var instance2 = new SubType()
console.log(instance2.colors)  // 'red', 'blue', 'black'

2. 借用組織函數(典範繼承)

基礎頭腦: 在子範例組織函數內部挪用超範例組織函數

函數只不過是在特定環境中實行代碼的對象,因而經由過程運用apply()和call()要領也可以在(未來)新建的對象上實行組織函數。
function SuperType() {
    this.colors = ['red', 'blue']
}
function SubType() {
    // 繼承了SuperType
    SuperType.call(this)
}
var instance1 = new SubType()
instance1.push('black')
console.log(instance1.colors)  //'red', 'blue', 'black'

var instance2 = new SubType()
console.log(instance2.colors)  //'red', 'blue'

經由過程運用call()要領或許apply()要領,我們現實上是在(未來)新建立的SubType實例的環境下挪用SuperType組織函數

通報參數:

function SuperType(name) {
    this.name = name
}
function SubType() {
    // 繼承了SuperType,同時還通報了參數
    SuperType.call(this, 'zhangsan')
    this.age = 20
}
var instance = new SubType()
console.log(instance.name)   // zhangsan
console.log(instance.age)    // 20

瑕玷:和組織函數形式存在一樣的題目,函數沒法復用。

3. 組合繼承(最經常使用的繼承形式)

原型鏈和借用組織函數的手藝結合到一塊,發揮二者之長的繼承形式

基礎頭腦:運用原型鏈完成對原型屬性和要領的繼承,經由過程借用組織函數來完成對實例屬性的繼承。如許既經由過程在原型上定義要領完成了函數的復用,又可以保證每一個函數都有本身的屬性。

function SuperType(name) {
    this.name = name
    this.color = ['red', 'blue']
}
SuperType.prototype.getName = function() {
    console.log(this.name)
}

function SubType(name, age) {
    SuperType.call(this, name)  // 繼承屬性
    this.age = age
}
SubType.prototype.getAge = function() {
    console.log(this.age)
}

SubType.prototype = new SuperType()  // 繼承要領
SubType.prototype.constructor = SubType

var instance1 = new SubType('zhangsan', 18)
instance1.colors.push('black')
console.log(instance1.colors)  // 'red', 'blue', 'black'
console.log(instance1.getName)  // 'zhangsan'
console.log(instance1.getAge)   // 18

var instance2 = new SubType('lisi', 20)
console.log(instance2.colors)   //  'red', 'blue'
console.log(instance2.getName)  // 'lisi'
console.log(instance2.getAge)  // 20
4. 原型式繼承
Object.create()
5. 寄生式繼承

繼承總結

javascript重如果經由過程原型鏈完成繼承。原型鏈的構建是經由過程將一個範例的實例賦值給另一個組織函數的原型完成的。如許,子範例可以接見超範例的一切屬性和要領。原型鏈的題目是對象實例同享一切繼承的屬性和要領,因而不適合零丁運用。處理這個題目的手藝是借用組織函數,即在子範例組織函數的內部挪用超範例組織函數。如許就可以做到每一個實例都有本身的屬性,同時還能保證只是用組織函數形式來定義範例。運用最多的繼承形式是組合繼承,這類形式運用原型鏈繼承同享的屬性和要領,而經由過程借用組織函數繼承實例屬性。

ES6:

1.建立對象

    1. class關鍵字
    2. 定義屬性:constructor(xxx) { this.xxx = xxx }
    3. 定義要領,要領之間不須要“;”
class Person{                   // 運用class,而不是function
    constructor(name, age=18) { // 類的傳參
        this.name = name        // 定義此類的屬性
        this.age = age
    }
    introduce() {                // 定義要領
        return `我叫${this.name},本年${this.age}歲`
    }
    sayName() {
        console.log(this.name)
    }
    sayAge() {
        console.log(this.age)
    }
}
const me = new Person('張三', 20)
console.log(me.introduce())

2.繼承

class Coder extends Person{
    constructor(name, age, job="Html") {  // 繼承父類屬性,並新加屬性
        super(name, age) // 必需傳參;子類必需在constructor中挪用super,不然報錯(因為子類沒有本身的this對象,而是繼承父類的this對象並對其加工,如果不挪用super,子類得不到this對象)
        this.job = job
    }
    showJob() { // 子類的新要領
        console.log(this.job)
    }
}
// 挪用
const coder1 = new Coder('李四', 22, 'js')
coder1.sayName()
coder1.showJob()
    原文作者:於見
    原文地址: https://segmentfault.com/a/1190000014715515
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞