一卷仑、面向?qū)ο蠡咎卣?/h4>
- 封裝:也就是把客觀事物封裝成抽象的類姐浮,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作浩嫌,對不可信的進行信息隱藏杂拨。
- 繼承:通過繼承創(chuàng)建的新類稱為“子類”或“派生類”专普。繼承的過程,就是從一般到特殊的過程弹沽。
- 多態(tài):對象的多功能檀夹,多方法,一個方法多種表現(xiàn)形式策橘。
- Javascript是一種基于對象(object-based)的語言炸渡。但是,它又不是一種真正的面向?qū)ο缶幊蹋∣OP)語言丽已,因為它的語法中沒有class(類)—–es6以前是這樣的蚌堵。所以es5只有使用函數(shù)模擬的面向?qū)ο蟆?/li>
二、對象實例化方式
- 原始模式:這樣的寫法有兩個缺點沛婴,一是如果多生成幾個(100個:鹞贰)實例,寫起來就非常麻煩嘁灯;二是實例與原型之間泻蚊,沒有任何辦法,可以看出沒有什么聯(lián)系旁仿。
var Car = {
color: 'red',//車的顏色
wheel: 4,//車輪數(shù)量
}
var Car2 = {
color: 'blue',
wheel: 4,
}
alert(Car.color);//red
- 原始模式的改進:通過寫一個函數(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);//紅色
- 工廠模式
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);//紅色
- 構(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ù)注意事項
- 此時CreateCar稱之為構(gòu)造函數(shù)插勤,也可以稱之類沽瘦,構(gòu)造函數(shù)就是類 。
- cat1农尖,cat2均為CreateCar的實例對象析恋。
- CreateCar構(gòu)造函數(shù)中this指向CreateCar實例對象即
new CreateCar( )
出來的對象。
- 必須帶new 盛卡。
- 構(gòu)造函數(shù)首字母大寫助隧,這是規(guī)范,官方都遵循這一個規(guī)范滑沧,如Number() Array()并村。
- contructor:這時cat1和cat2會自動含有一個constructor屬性,指向它們的構(gòu)造函數(shù),即CreateCar嚎货。
alert(cat1.constructor == CreateCar); //true
alert(cat2.constructor == CreateCar); //true
- 每定義一個函數(shù)橘霎,這個函數(shù)就有一個 prototype 的屬性{},
__proto__
指向被實例化的構(gòu)造函數(shù)的prototype殖属,prototype默認帶constructor屬性姐叁,constructor指向構(gòu)造函數(shù)。
- instanceof 運算符:
object instanceof constructor
運算符洗显,驗證構(gòu)造函數(shù)與實例對象之間的關(guān)系外潜。
alert(cat1 instanceof CreateCar ); //true
alert(cat2 instanceof CreateCar ); //true
四、構(gòu)造函數(shù)的問題
var Car = {
color: 'red',//車的顏色
wheel: 4,//車輪數(shù)量
}
var Car2 = {
color: 'blue',
wheel: 4,
}
alert(Car.color);//red
function createCar(color,wheel) {
return {
color:color,
wheel:wheel
}
}
//然后生成實例對象枯冈,就等于是在調(diào)用函數(shù):
var cat1 = createCar("紅色","4");
var cat2 = createCar("藍色","4");
alert(cat1.color);//紅色
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);//紅色
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);//紅色
new CreateCar( )
出來的對象。alert(cat1.constructor == CreateCar); //true
alert(cat2.constructor == CreateCar); //true
__proto__
指向被實例化的構(gòu)造函數(shù)的prototype殖属,prototype默認帶constructor屬性姐叁,constructor指向構(gòu)造函數(shù)。object instanceof constructor
運算符洗显,驗證構(gòu)造函數(shù)與實例對象之間的關(guān)系外潜。alert(cat1 instanceof CreateCar ); //true
alert(cat2 instanceof CreateCar ); //true
構(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)造出來的酝豪。
- Object是Function 的一個實例涛碑。
Object.constructor == Function //true
- 函數(shù)是Function 的實例,但不是Object 的實例孵淘。
function fn(){}
fn.constructor == Function //true
fn.constructor == Object //false
- {} 與 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());
八、對象繼承
- 利用
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();
- 采用中介
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);
- 采用中介么抗,使用
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,//是否可以再次修改修飾符
});