JavaScript面向對象

1、面向對象基本特徵

  1. 封裝:也就是把客觀事物封裝成抽象的類,而且類能夠把本身的數據和方法只讓可信的類或者對象操做,對不可信的進行信息隱藏。
  2. 繼承:經過繼承建立的新類稱爲「子類」或「派生類」。繼承的過程,就是從通常到特殊的過程。
  3. 多態:對象的多功能,多方法,一個方法多種表現形式。
  4. Javascript是一種基於對象(object-based)的語言。可是,它又不是一種真正的面向對象編程(OOP)語言,由於它的語法中沒有class(類)—–es6之前是這樣的。因此es5只有使用函數模擬的面向對象。

2、對象實例化方式

  1. 原始模式:這樣的寫法有兩個缺點,一是若是多生成幾個(100個!)實例,寫起來就很是麻煩;二是實例與原型之間,沒有任何辦法,能夠看出沒有什麼聯繫。
var Car = {
    color: 'red',//車的顏色
    wheel: 4,//車輪數量
}
var Car2 = {
    color: 'blue',
    wheel: 4,
}
alert(Car.color);//red
複製代碼
  1. 原始模式的改進:經過寫一個函數,解決代碼重複的問題。
function createCar(color,wheel) {
    return {
        color:color,
        wheel:wheel
    }
}
//而後生成實例對象,就等因而在調用函數:
var cat1 = createCar("紅色","4");
var cat2 = createCar("藍色","4");

alert(cat1.color);//紅色
複製代碼
  1. 工廠模式
function createCar(color,wheel){//createCar工廠
    var obj = new Object;//或obj = {} 原材料階段
    obj.color = color;//加工
    obj.wheel = wheel;//加工
    return obj;//輸出產品
}
//實例化
var cat1 = createCar("紅色","4");
var cat2 = createCar("藍色","4");

alert(cat1.color);//紅色
複製代碼
  1. 構造函數模式:爲了解決從原型對象生成實例的問題,Javascript提供了一個構造函數(Constructor)模式。 所謂」構造函數」,其實就是一個普通函數,可是內部使用了this變量。對構造函數使用new運算符,就能生成實例,而且this變量會綁定在實例對象上。加new執行的函數構造內部變化:自動生成一個對象,this指向這個新建立的對象,函數自動返回這個新建立的對象
function CreateCar(color,wheel){//構造函數首字母大寫
    //不須要本身建立對象了
    this.color = color;//添加屬性,this指向構造函數的實例對象
    this.wheel = wheel;//添加屬性

    //不須要本身return了
}

//實例化
var cat1 = new CreateCar("紅色","4");
var cat2 = new CreateCar("藍色","4");
alert(cat1.color);//紅色
複製代碼

3、構造函數注意事項

  1. 此時CreateCar稱之爲構造函數,也能夠稱之類,構造函數就是類 。
  2. cat1,cat2均爲CreateCar的實例對象。
  3. CreateCar構造函數中this指向CreateCar實例對象即 new CreateCar( )出來的對象。
  4. 必須帶new 。
  5. 構造函數首字母大寫,這是規範,官方都遵循這一個規範,如Number() Array()。
  6. contructor:這時cat1和cat2會自動含有一個constructor屬性,指向它們的構造函數,即CreateCar。
alert(cat1.constructor == CreateCar); //true
alert(cat2.constructor == CreateCar); //true
複製代碼
  1. 每定義一個函數,這個函數就有一個 prototype 的屬性{},__proto__ 指向被實例化的構造函數的prototype,prototype默認帶constructor屬性,constructor指向構造函數。
  2. instanceof 運算符:object instanceof constructor運算符,驗證構造函數與實例對象之間的關係。
alert(cat1 instanceof CreateCar ); //true
alert(cat2 instanceof CreateCar ); //true
複製代碼

4、構造函數的問題

構造函數方法很好用,可是存在一個浪費內存的問題。若是如今爲其再添加一個方法showWheel。那麼,CreateCar就變成了下面這樣,這樣作有一個很大的弊端,對於每個實例對象,showWheel都是如出一轍的內容,每一次生成一個實例,都必須生成重複的內容,多佔用一些內存。這樣既不環保,也缺少效率。html

function CreateCar(color,wheel){

    this.color = color;
    this.wheel = wheel;
    this.showWheel = function(){//添加一個新方法
        alert(this.wheel);
    }   
}

//仍是採用一樣的方法,生成實例:
var cat1 = new CreateCar("紅色","4");
var cat2 = new CreateCar("藍色","4");

alert(cat1.showWheel == cat2.showWheel); //false
複製代碼

5、Prototype 原型

Javascript規定,每個構造函數都有一個prototype屬性,指向另外一個對象。這個對象的全部屬性和方法,都會被構造函數的實例繼承。 這意味着,咱們能夠把那些不變的屬性和方法,直接定義在prototype對象上。__proto__是原型鏈,指向實例化的函數原型。es6

function CreateCar(color,wheel){
    //屬性寫構造函數裏面
    this.color = color;
    this.wheel = wheel;
}

//方法寫原型裏面
CreateCar.prototype.showWheel = function(){
    alert(this.wheel);
}
CreateCar.prototype.showName = function(){
    alert('車');
}

//生成實例。
var cat1 = new CreateCar("紅色","4");
var cat2 = new CreateCar("藍色","4");
cat1.showName();//'車'

//這時全部實例的showWheel屬性和showName方法,其實都是同一個內存地址,指向prototype對象,所以就提升了運行效率。
alert(cat1.showWheel == cat2.showWheel );//true
alert(cat1.showName == cat2.showName );//true
console.log(cat1.__proto__ === CreateCar.prototype); //true
複製代碼

6、對象和函數的關係

對象是由函數構造出來的。編程

  1. Object是Function 的一個實例。
Object.constructor  == Function  //true
複製代碼
  1. 函數是Function 的實例,但不是Object 的實例。
function fn(){}
fn.constructor  == Function  //true
fn.constructor  == Object    //false 
複製代碼
  1. {} 與 Object 的關係。
var obj = {};
obj.constructor  === Object   //true
複製代碼

7、靜態方法和靜態屬性

只屬於類而不屬於實例化對象函數

function foo(){
    this.show = function(){
        return this;
    }
}

foo.test = 123; //靜態屬性

foo.say = function(){
    return this;
}
foo.say();

var fn = new foo(); //實例化的新的對象,this指向這個新的對象,不能訪問類的靜態方法
fn.say(); //Noname1.html:45 Uncaught TypeError: fn.say is not a function
console.log(foo.say() == fn.say());
複製代碼

8、對象繼承

  1. 利用call()for in繼承 。 給對象的constructor.prototype添加方法屬性,對象就會繼承,若是要實現一個對象繼承其餘對象,採用以下方法。
//人類
function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype.run = function(){
    console.log('跑路~')
};
Person.prototype.say = function(){
    console.log('說話~')
};

console.log(Person.prototype);

//男人
function Man(){
    this.sex = "男";
}

Man.prototype = Person.prototype;

Man.prototype.yyy = function(){
    console.log('嚶嚶嚶');
}
//會發現Person的prototype也改變了,由於複雜對象的賦值操做是引用而不是賦值
console.log(Person.prototype);
複製代碼
//人類
function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype.run = function(){
    console.log('跑路~')
};
Person.prototype.say = function(){
    console.log('說話~')
};

console.log(Person.prototype);

//男人
function Man(){
    this.sex = "男";
}

for(var key in Person.prototype){
    Man.prototype[key] = Person.prototype[key];
    console.log(key)
}
Man.prototype.yyy = function(){
    console.log('嚶嚶嚶');
}

console.log(Person.prototype);
var xm = new Man();
xm.yyy();
複製代碼
  1. 採用中介
function ClassA(name){
    this.name = name;
}
ClassA.prototype.say = function(){
    console.log(666);
}

//中繼來作準備工做
function Ready(){}//
Ready.prototype = ClassA.prototype;//引用

//須要來繼承ClassA
function ClassB(){}
ClassB.prototype = new Ready();//new 返回了一個新對象 __proto__指向被實例化的構造函數的prototype
ClassB.prototype.constructor = ClassB;
console.log(ClassB.prototype);
複製代碼
  1. 採用中介,使用call改變this指向
function ClassA(name){
    this.name = name;
}
ClassA.prototype.showName = function(){
    console.log(this.name);
}

//中繼來作準備工做
function Ready(){}//
Ready.prototype = ClassA.prototype;//引用

//須要來繼承ClassA
function ClassB(name){
    ClassA.call(this,name);
}
ClassB.prototype = new Ready();//new 返回了一個新對象 __proto__指向被實例化的構造函數的prototype
ClassB.prototype.constructor = ClassB;
console.log(ClassB.prototype);
var xiaoming = new ClassB('小明');
xiaoming.showName();
複製代碼

9、多態

同一個方法,面對不一樣的對象有不一樣的表現形式就叫作多態。ui

var obj = {
    eat : function(_type){
        if(_type == '貓'){
            console.log('貓糧')
        }else if (_type == "狗") {
            console.log('狗糧')
        }else{
            console.log("吃飯");
        }
    }
};
obj.eat("狗");
複製代碼

10、hasOwnProperty

查看該屬性是否在這個對象自己上,只有在自身屬性上纔會返回真,在原型鏈上會返回假。this

function ClassA(){}
ClassA.prototype.test = function(){
    console.log('test')
}

var a = new ClassA();
a.test();
console.log(a.hasOwnProperty('test')); //false
複製代碼

11、描述符(修飾符)

描述符是對一個屬性的特性的描述,defineProperty設置描述符(修飾符),value設置屬性值,configurable是否容許修飾符被改變 默認爲false,enumerable 是否能夠被枚舉 默認爲false,writable 是否能夠被 = 等號改變 默認爲false。es5

var obj = {
    a : 1
};
var c = 666;
Object.defineProperty(obj,'c',{
    //value : 233,
    //enumerable : false,
    //writable : true,//他的值可否改變
			
    //設置的時候調用
    set : function(n){
        //n 就是等號的右邊的值
        c = c*n;
    },

    //獲取的時候調用
    get : function(){
        return c;
    },

    configurable : true,//是否能夠再次修改修飾符
});
複製代碼
相關文章
相關標籤/搜索