JavaScript筆記3--封裝JS對象

1. js原始類型

js有5種原始數據類型:即 Undefined、Null、Boolean、Number 和 String。

2. js對象分類


js對象可以分爲3類:本地對象、內置對象、宿主對象。

本地對象:ECMA-262 把本地對象定義爲“獨立於宿主環境的,由ECMAScript 提供的對象”。
再來看一下,“本地對象”包含哪些內容:
Object
Function
Array
String
Boolean
Number
Date
RegExp
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
本地對象就是 ECMA-262 定義的類(引用類型)。

內置對象:ECMA-262 把內置對象定義爲“獨立於宿主環境的,由ECMAScript 提供的對象,在 ECMAScript 程序開始執行時出現”。
這意味着開發者不必明確實例化內置對象,它已被實例化了。直接使用就行了。
ECMA-262 只定義了兩個內置對象,即 Global 和 Math (它們也是本地對象,根據定義,每個內置對象都是本地對象)。

Global對象的屬性列表:
這裏寫圖片描述

Global對象的方法:
例如isNum(),isFinite(),parseInt(),parseFloat()等,都是Global對象的方法。
encodeURI():對傳遞給瀏覽器的URI進行編碼。對應的解碼函數:decodeURI()。
encodeURIComponent():對傳遞給瀏覽器的URI進行編碼。對應的解碼函數:decodeURIComponent()。
這兩個方法的主要區別是:
encodeURI()不對URI中的特殊字符編碼,例如冒號、斜槓、問號和英鎊符號;
encodeURIComponent()會對它發現的所有非標準字符進行編碼。而對應有decodeURI()和decodeURIComponent()解碼函數。
這些URI方法代替了BOM中的escape()和()方法。URI方法更可取,因爲它們會對所有的Unicode符號編碼,而BOM方法只能對ASCII符號正確編碼。應儘量避免使用escape()方法。

Math對象常用方法:
min()、max()
abs()方法返回數字的絕對值。
ceil()表示向上舍入
floor()表示向下舍入
round()標準的四捨五入

宿主對象:由 ECMAScript 實現的宿主環境提供的對象。所有 BOM 和 DOM 對象都是宿主對象。
BOM對象:window、location、screen、history、navigator。
DOM對象:document、form、button等。

開發人員可以自定義對象。

3.封裝JS對象

JavaScript裏一切皆對象。所以函數也是對象,是Function的實例。函數名可以理解爲指向該實例的引用。
JS裏封裝對象的常用方式有5種:
顯示自定義、工廠方法、構造函數方式、原型方式、構造函數+原型方式;

顯式自定義對象

var obj1 = {
    nick: 'Byron',
    age: 20,
    printName: function(){
        console.log(obj1.nick);
    }
}
var obj2 = {
    nick: 'Casper',
    age: 25,
    printName: function(){
        console.log(obj2.nick);
    }
}

適用場合:
臨時對象。比如作爲方法的參數傳遞時,可以這樣封裝對象。
全局常量對象。很少做修改情況下適合這樣封裝對象。比如定義一個AjxxConst對象,該對象的屬性是一些常量值,比如案件狀態–已公開=3.

缺點:
不能很好的複用;
多個客戶端併發訪問時,數據容易被修改;

工廠方法封裝對象

function createObj(name, age){
    var person = new object();
    person.name = name;
    person.age = age;
    person.printName = function(){
        console.log(this.nick);
    }
    return person ;
}

客戶端:
var p1 = createObj('權志龍', 30);
p1.printName ();

適用場合:
創建操作比較頻繁,即經常創建同一類的實例時,可以使用工廠方法。
可以理解爲工廠方法是對“創建object對象”這一操作的封裝。

缺點:
構造出來的對象類型都是Object,沒有識別度;
創建多個實例的同時,還要創建重複的行爲printName;

構造函數方式封裝對象

<script>

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

    function test(){
        var p1 = new Person();
        var p2 = new Person('權志龍');
        var p3 = new Person('權志龍',30);
        p1.sayName();//undefined,undefined
        p2.sayName();//權志龍,undefined
        p3.sayName();//權志龍,30
    }

 </script>

JS裏萬物皆對象,方法也是對象。因此可以通過聲明一個方法來指定對象類型。

適用場合:
沒有固定的場景,自己根據實際情況來決定是否使用吧。
構造方法封裝對象,是不是有點兒類似java了呀,還有比這更類似的呢!

缺點:
創建多個實例的同時,還要創建重複的行爲printName;

原型方式封裝對象

function Person(){
}

Person.prototype.name = "權志龍";
Person.prototype.age = 30;

Person.prototype.printName = function(){
    console.log(this.name);
}

Person.prototype.printAge = function(){
    console.log(this.age);
}

客戶端:
var p1 = new Person();
p1.printName();
p1.printAge();

適用場合:
實例們的屬性值固定不變時,適合這樣封裝對象。

缺點:
參數值綁定的太死了,是不是,是不是,是不是!

構造函數+原型方式封裝對象

function MyObject(otherObject){
    alert("有參構造函數!");
    this.otherObject = otherObject;
}

MyObject.prototype.name = "y0";
MyObject.prototype.age = "0";

MyObject.prototype.getName = function getName(){
    console.log(this.name);
};

MyObject.prototype.getAge = function getAge(){
    console.log(this.age);
};

MyObject.prototype.setName = function setName(name){
    this.name = name;
};

MyObject.prototype.setAge = function setAge(age){
    this.age = age;
};

MyObject.prototype.getOtherObject = function getOtherObject(){
    console.log(this.otherObject);
};

MyObject.prototype.setOtherObject = function setOtherObject(otherObject){
    this.otherObject = otherObject;
};

客戶端:
    var myObject1 = new MyObject();
    myObject1.getName();//y0
    myObject1.getAge();//0
    myObject1.setName("yulq");
    myObject1.setAge(18);
    myObject1.getName();//yulq
    myObject1.getAge();//18
    myObject1.getOtherObject();//undefined

    var myObject2 = new MyObject(11);
    myObject2.getName();//y0
    myObject2.getAge();//0
    myObject2.setName("yulq2");
    myObject2.setAge(20);
    myObject2.getName();//yulq2
    myObject2.getAge();//20
    myObject2.getOtherObject();//11

適用場合:
完美。

缺點:
缺點就是太完美了!

4.定義JS變量

JS變量可以分爲三種:私有變量、實例變量、靜態變量。

<script>
    function ClassA(){
        var a = 1; //私有變量,只有函數內部可以訪問
        this.b = 2; //實例變量,只有實例可以訪問
    }
    ClassA.c = 3; // 靜態變量,也就是屬性,類型訪問
    ClassA.prototype.d  = 4;//實例變量,只有實例可以訪問

    function test(){

        console.log(a); // error
        console.log(ClassA.b) // undefined
        console.log(ClassA.c) //3
        console.log(ClassA.d) //undefined

        var classa = new ClassA();
        console.log(classa.a);//undefined
        console.log(classa.b);// 2
        console.log(classa.c);//undefined
        console.log(classa.d);//4
    }

 </script>

5.JS實現繼承

JavaScript並不提供原生的繼承機制,我們自己實現的方式很多,介紹一種最爲通用的。
我們如果實現了兩點的話就可以說我們實現了繼承:
得到一個類的屬性;
得到一個類的方法;

獲得父類屬性

    function Person(name, age){
       this.name = name;
       this.age = age;
    }
    Person.prototype.sayName = function (){
         console.log(this.name);
    }
    ---------------------------
    function SubPerson(name,age,like){
       Person.call(this,name,age);
       this.like = '唱歌';
    }
    ----------------------------
    function test(){
        var p1 = new SubPerson('權志龍',30,'唱歌');
        console.log(p1.name);//權志龍
    }

獲得父類屬性的原理是:
在子類構造函數裏,通過Function.prototype.call(obj,param1,param2…)方法裝配子類對象。
call()方法,將某個對象構造方法裏的this換成第一個參數指定的對象;
因此,通過調用父類的call給子類裝配父類屬性,實現了繼承屬性。

獲得父類方法

我們知道類的方法都定義在了prototype裏面,所以只要我們把子類的prototype改爲父類的prototype的備份就好了。
SubPerson.prototype = Object.create(Person.prototype);
我們通過Object.create()方法clone了一個新的prototype而不是直接把Person.prtotype直接賦值。因爲引用關係,這樣會導致後續修改子類的prototype也修改了父類的prototype,因爲修改的是一個值。
這樣做需要注意一點就是對子類添加方法,必須在修改其prototype之後,如果在之前會被覆蓋掉。

還有個問題,我們知道prototype對象有一個屬性constructor指向其類型,因爲我們複製的父元素的prototype,這時候constructor屬性指向是不對的,導致我們判斷類型出錯:
SubPerson.prototype.constructor; //Person
因此我們需要再重新指定一下constructor屬性到自己的類型:
var _prototype = Object.create(Person.prototype);
_prototype.constructor = SubPerson;
SubPerson.prototype = _prototype;

最終示例如下:

 <script>
    --------------------封裝父類對象-----------------------
    function Person(name, age){
       this.name = name;
       this.age = age;
    }
    Person.prototype.sayName = function (){
         console.log(this.name);
    }


    --------------------封裝子類對象-----------------------
    function SubPerson(name,age,like){
       Person.call(this,name,age);
       this.like = like; 
    }

    var _prototype = Object.create(Person.prototype); 
    _prototype.constructor = SubPerson; 
    SubPerson.prototype = _prototype;

    SubPerson.prototype.sayLike = function (){
         console.log(this.like);
    }


    --------------------客戶端-----------------------
    function test(){
        var p1 = new SubPerson('權志龍',30,'唱歌');
        console.log(typeof SubPerson);
        console.log(p1 instanceof SubPerson);
        p1.sayName();
        p1.sayLike();
    }

 </script>

實現要點:
1,在子類的構造方法裏,通過Father.call(this,param1,param2……..)獲得父類屬性;
2,在擴展子類方法之前,通過Object.create(Father.prototype)克隆一個父類原型,將該原型的constructor 指向SubPerson,最後將子類原型指向克隆出來的父類原型,從而子類獲得了父類方法。

發佈了38 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章