JavaScript面向?qū)ο?/h2>

一、面向?qū)ο蠡咎卣?/h4>
  1. 封裝:也就是把客觀事物封裝成抽象的類,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
  2. 繼承:通過繼承創(chuàng)建的新類稱為“子類”或“派生類”。繼承的過程,就是從一般到特殊的過程。
  3. 多態(tài):對象的多功能,多方法,一個方法多種表現(xiàn)形式。
  4. Javascript是一種基于對象(object-based)的語言。但是,它又不是一種真正的面向?qū)ο缶幊蹋∣OP)語言,因為它的語法中沒有class(類)—–es6以前是這樣的。所以es5只有使用函數(shù)模擬的面向?qū)ο蟆?/li>

二、對象實例化方式

  1. 原始模式:這樣的寫法有兩個缺點,一是如果多生成幾個(100個!)實例,寫起來就非常麻煩;二是實例與原型之間,沒有任何辦法,可以看出沒有什么聯(lián)系。
var Car = {
    color: 'red',//車的顏色
    wheel: 4,//車輪數(shù)量
}
var Car2 = {
    color: 'blue',
    wheel: 4,
}
alert(Car.color);//red
  1. 原始模式的改進:通過寫一個函數(shù),解決代碼重復(fù)的問題。
function createCar(color,wheel) {
    return {
        color:color,
        wheel:wheel
    }
}
//然后生成實例對象,就等于是在調(diào)用函數(shù):
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;//輸出產(chǎn)品
}
//實例化
var cat1 = createCar("紅色","4");
var cat2 = createCar("藍色","4");

alert(cat1.color);//紅色
  1. 構(gòu)造函數(shù)模式:為了解決從原型對象生成實例的問題,Javascript提供了一個構(gòu)造函數(shù)(Constructor)模式。 所謂”構(gòu)造函數(shù)”,其實就是一個普通函數(shù),但是內(nèi)部使用了this變量。對構(gòu)造函數(shù)使用new運算符,就能生成實例,并且this變量會綁定在實例對象上。加new執(zhí)行的函數(shù)構(gòu)造內(nèi)部變化:自動生成一個對象,this指向這個新創(chuàng)建的對象,函數(shù)自動返回這個新創(chuàng)建的對象
function CreateCar(color,wheel){//構(gòu)造函數(shù)首字母大寫
    //不需要自己創(chuàng)建對象了
    this.color = color;//添加屬性,this指向構(gòu)造函數(shù)的實例對象
    this.wheel = wheel;//添加屬性

    //不需要自己return了
}

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

三、構(gòu)造函數(shù)注意事項

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

四、構(gòu)造函數(shù)的問題

構(gòu)造函數(shù)方法很好用,但是存在一個浪費內(nèi)存的問題。如果現(xiàn)在為其再添加一個方法showWheel。那么,CreateCar就變成了下面這樣,這樣做有一個很大的弊端,對于每一個實例對象,showWheel都是一模一樣的內(nèi)容,每一次生成一個實例,都必須生成重復(fù)的內(nèi)容,多占用一些內(nèi)存。這樣既不環(huán)保,也缺乏效率。

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

五、Prototype 原型

Javascript規(guī)定,每一個構(gòu)造函數(shù)都有一個prototype屬性,指向另一個對象。這個對象的所有屬性和方法,都會被構(gòu)造函數(shù)的實例繼承。 這意味著,我們可以把那些不變的屬性和方法,直接定義在prototype對象上。__proto__是原型鏈,指向?qū)嵗暮瘮?shù)原型。

function CreateCar(color,wheel){
    //屬性寫構(gòu)造函數(shù)里面
    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方法,其實都是同一個內(nèi)存地址,指向prototype對象,因此就提高了運行效率。
alert(cat1.showWheel == cat2.showWheel );//true
alert(cat1.showName == cat2.showName );//true
console.log(cat1.__proto__ === CreateCar.prototype); //true

六、對象和函數(shù)的關(guān)系

對象是由函數(shù)構(gòu)造出來的。

  1. Object是Function 的一個實例。
Object.constructor  == Function  //true
  1. 函數(shù)是Function 的實例,但不是Object 的實例。
function fn(){}
fn.constructor  == Function  //true
fn.constructor  == Object    //false 
  1. {} 與 Object 的關(guān)系。
var obj = {};
obj.constructor  === Object   //true

七、靜態(tài)方法和靜態(tài)屬性

只屬于類而不屬于實例化對象

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

foo.test = 123; //靜態(tài)屬性

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

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

八、對象繼承

  1. 利用call()for in繼承 。
    給對象的constructor.prototype添加方法屬性,對象就會繼承,如果要實現(xiàn)一個對象繼承其他對象,采用如下方法。
//人類
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('嚶嚶嚶');
}
//會發(fā)現(xiàn)Person的prototype也改變了,因為復(fù)雜對象的賦值操作是引用而不是賦值
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__指向被實例化的構(gòu)造函數(shù)的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__指向被實例化的構(gòu)造函數(shù)的prototype
ClassB.prototype.constructor = ClassB;
console.log(ClassB.prototype);
var xiaoming = new ClassB('小明');
xiaoming.showName();

九、多態(tài)

同一個方法,面對不同的對象有不同的表現(xiàn)形式就叫做多態(tài)。

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

十、hasOwnProperty

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

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

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

十一、描述符(修飾符)

描述符是對一個屬性的特性的描述,defineProperty設(shè)置描述符(修飾符),value設(shè)置屬性值,configurable是否允許修飾符被改變 默認為false,enumerable 是否可以被枚舉 默認為false,writable 是否可以被 = 等號改變 默認為false。

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

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

    configurable : true,//是否可以再次修改修飾符
});
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容