溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法

發(fā)布時(shí)間:2020-07-27 16:58:51 來源:億速云 閱讀:123 作者:小豬 欄目:web開發(fā)

這篇文章主要講解了JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法,內(nèi)容清晰明了,對此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。

類的創(chuàng)建于實(shí)例對象

工廠模型創(chuàng)建對象

function CreatePerson ( name,sex,age ) {
 
 var obj = new Object();
 
 obj.name = name;
 obj.sex = sex;
 obj.age = age;
 
 obj.sayName = function () {
  
  console.log( this.name );
  
 }
 
 return obj;
 
}

var p1 = CreatePerson('zf','女',22);

p1.sayName(); //zf

console.log( p1.name ); //zf

構(gòu)造函數(shù)式

//函數(shù)的第一個(gè)字母大寫(類的模板)
function Person ( name,age,sex ) {
 
 this.name = name;
 this.age = age;
 this.sex =sex;
 
 this.sayName = function () {
  
  alert(this.name);
  
 }
 
}

//構(gòu)造一個(gè)對象, 使用new關(guān)鍵字, 傳遞參數(shù), 執(zhí)行模板代碼, 返回對象。

var p1 = new Person('zf',20,'女'); //類的概念:根據(jù)模板創(chuàng)建出不同的實(shí)例對象
 
console.log( p1.name );

p1.sayName();

創(chuàng)建類的實(shí)例:

  • 當(dāng)作構(gòu)造函數(shù)去使用

    var p1 = new Person('a1',20);

  • 作為普通函數(shù)去調(diào)用

    Person('a2',20); //在全局環(huán)境中定義屬性并賦值, 直接定義在window上。

  • 在另個(gè)一對象的作用域中調(diào)用

    var o = new Object();
     Person.call(o,'a3',23);

Object每個(gè)實(shí)例都會(huì)具有的屬性和方法:

Constructor: 保存著用于創(chuàng)建當(dāng)前對象的函數(shù)。(構(gòu)造函數(shù))
hasOwnProperty(propertyName):用于檢測給定的屬性在當(dāng)前對象實(shí)例中(而不是原型中)是否存在。
isPrototypeOf(Object): 用于檢查傳入的對象是否是另外一個(gè)對象的原型。
propertyIsEnumerable(propertyName):用于檢查給定的屬性是否能夠使用for-in語句來枚舉。
toLocaleString():返回對象的字符串表示。該字符串與執(zhí)行環(huán)境的地區(qū)對應(yīng).
toString():返回對象的字符串表示。
valueOf():返回對象的字符串、數(shù)值或布爾表示。

判斷一個(gè)對象是不是另一個(gè)對象的實(shí)例,通常使用的是 instanceof. 比較少使用constructor。

原型

創(chuàng)建每一個(gè)函數(shù)的時(shí)候,都有一個(gè)prototype屬性. 這個(gè)是屬性,是一個(gè)指針。而這個(gè)對象總是指向一個(gè)對象。
這個(gè)對象 的用途就是將特定的屬性和方法包含在內(nèi),是一個(gè)實(shí)例對象, 起到了一個(gè)所有實(shí)例所共享的作用。
屏蔽了,構(gòu)造函數(shù)的缺點(diǎn),new 一個(gè)對象,就把構(gòu)造函數(shù)內(nèi)的方法實(shí)例化一次。

function Person () {
    
}

var obj = Person.prototype;

console.log( obj ); //Person.prototype 就是一個(gè)對象
//Person.prototype 內(nèi)部存在指針,指針指向一個(gè)對象。 這個(gè)對象稱之為:原型對象。原型對象,被所有的實(shí)例對象所共享。

console.log( obj.constructor ); //function Person(){} //obj這個(gè)對象的構(gòu)造器就是 Person

原型圖例:

JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法

console.log(Person.prototype) 的結(jié)果:

JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法

常用方法

Object.getPrototypeOf()

根據(jù)實(shí)例對象獲得原型對象

每次代碼讀取一個(gè)對象的屬性的時(shí)候:首先會(huì)進(jìn)行一次搜索,搜索實(shí)例對象里,看看是否存在,如果沒有,再去實(shí)例所對的原型中尋找屬性.如果有則返回,如果兩次都沒有則返回undefined

function Person () {
}

Person.prototype.name = 'z1';
Person.prototype.age = 20;

Person.prototype.sayName = function () {
 
 console.log( '我是原型對象方法' );
 
}

var p1 = new Person();

console.log( p1.name ); //z1

console.log( Object.getPrototypeOf(p1) ); 
console.log( Object.getPrototypeOf(p1) == Person.prototype ); //true

hasOwnProperty()

判斷是否是 實(shí)例對象自己的屬性

function Person () {
}

Person.prototype.name = 'z1';
Person.prototype.age = 20;

Person.prototype.sayName = function () {
 
 console.log( '我是原型對象方法' );
 
}


// 判斷一個(gè)對象屬性 是屬于 原型屬性 還是屬性 實(shí)例屬性

var p3 = new Person(); 
console.log( p3.name ); //zf 是原型上的

//hasOwnProperty() 是否是 實(shí)例對象自己的屬性 
console.log( p3.hasOwnProperty('name') ); //false 

in 操作符

無論是 原型的屬性, 還是實(shí)例對象的屬性, 都區(qū)分不開。 如果存在,返回true

function Person () {
}

Person.prototype.name = 'z1';
Person.prototype.age = 20;

Person.prototype.sayName = function () {
 
 console.log( '我是原型對象方法' );
 
}


//判斷屬性是否存在 實(shí)例對象 和 原型對象中. 

var p1 = new Person();
console.log('name' in p1); //true //表示,name的屬性到底在不在p1的屬性中 true
var p2 = new Person();

p1.name = 'zzz';

console.log('name' in p1); //true

判斷一個(gè)屬性是否在原型中

function Person () {
}

Person.prototype.name = 'z1';
Person.prototype.age = 20;

Person.prototype.sayName = function () {
 
 console.log( '我是原型對象方法' );
 
}


//判斷屬性是否存在 實(shí)例對象 和 原型對象中. 

var p1 = new Person();
p1.name = '123';

//在原型對象中,是否存在這個(gè)值
//@obj 當(dāng)前對象
//@判斷的屬性
function hasPrototypeProtoperty ( obj,attrName ) {
 
 return !obj.hasOwnProperty(attrName) && (attrName in obj);
 
}

console.log( hasPrototypeProtoperty(p1,'name') ); //false

Object.keys()

function Person () {
}

Person.prototype.name = 'z1';
Person.prototype.age = 20;

Person.prototype.sayName = function () {
 
 console.log( '我是原型對象方法' );
 
}

//ECMA5新特性 Object.keys(); 
//拿到當(dāng)前對象中的所有keys, 返回一個(gè)數(shù)組

var p1 = new Person();
p1.name = 'zz';
p1.age = 20;

var attr = Object.keys(p1);
console.log( attr ); //["name", "age"]

var attr2 = Object.keys(p1.__proto__); 

console.log( attr2 ); //["name", "age", "sayName"]

var attr3 = Object.keys(Person.prototype); 

console.log( attr3 ); //["name", "age", "sayName"]

Object.getOwnPropertyNames()

function Person () {
}

Person.prototype.name = 'z1';
Person.prototype.age = 20;

Person.prototype.sayName = function () {
 
 console.log( '我是原型對象方法' );
 
}

var p1 = new Person();
p1.name = 'zz';
p1.age = 20;

//ECMA5 
//constructor屬性,是無法被枚舉的. 正常的for-in循環(huán)是無法枚舉. [eable = false];

//Object.getOwnPropertyNames(); //枚舉對象所有的屬性:不管該內(nèi)部屬性能夠被枚舉.

var attr4 = Object.getOwnPropertyNames(Person.prototype); //["constructor", "name", "age", "sayName"]

console.log( attr3 );

isPrototypeOf()

判斷原型的方法

原型對象.isPrototypeOf(new instance);

實(shí)現(xiàn)each方法

原型的另外一個(gè)作用就是擴(kuò)展對象中的屬性和方法

//遍歷多維數(shù)組
var arr = [1,2,4,5,[455,[456,[345345]]]];

Array.prototype.each = function ( cb ) {

 try {

  //計(jì)數(shù)器
  this.i || (this.i = 0);

  //核心代碼
  if ( this.length > 0 && cb.constructor === Function ) {

   while ( this.i < this.length ) { //計(jì)數(shù)器 大于 數(shù)組長度跳出

    //獲得每一項(xiàng)值 
    var e = this[this.i];

    //判斷是否是 數(shù)組
    if ( e && e.constructor === Array ) {

     //遞歸
     e.each(cb);

    } else {

     cb.call(null,e);

    }

    this.i++; 

   }

   //使用完之后,釋放變量
   this.i = null;

  }

 } catch (e) {
  //do someting
  
 }

 return this;

};

arr.each(function( val ){

 console.log(val);

});

簡單原型

直接通過對象字面量來重寫整個(gè)原型對象(這種方法會(huì)改變原型對象的構(gòu)造器[改變?yōu)镺bject])

//簡單原型
   
function Person () {
 
}

Person.prototype = {
 
 constructor: Person, //原型的構(gòu)造器改變
 
 name: 'zz',
 age: 20,
 
 say: function () {
  console.log( this.age );
 }
 
}

var p1 = new Person();

console.log( p1.name );
p1.say();

存在的問題,constructor屬性是無法被枚舉的。加在原型對象上,可以被枚舉,被枚舉。不符合要求。

ECMA5中的Object.defineProperty()方法可以為原型對象重新加入構(gòu)造器。constructor問題可以被避免。

//3個(gè)參數(shù), 參數(shù)1:重新設(shè)置構(gòu)造的對象 (給什么對象設(shè)置)  參數(shù)2:設(shè)置什么屬性  參數(shù)3:options配置項(xiàng) (要怎么去設(shè)置)
Object.defineProperty(Person.prototype,'constructor',{
 enumerable: false, //是否是 能夠 被枚舉
 value: Person //值 構(gòu)造器的 引用
});

原型的動(dòng)態(tài)特性

注意原型和創(chuàng)建實(shí)例的前后順序

function Person () {
      
}

var p1 = new Person(); // {}
 
Person.prototype = {
 constructor: Person,
 name: 'zf',
 age: 20,
 say: function () {
  console.log('原型');
 }
}

//先把原型對象寫好,然后再實(shí)例化。

//p1.say(); //error 因?yàn)? 原型對象里面沒有任何屬性和方法

var p2 = new Person();

p2.say();

//注意 簡單原型使用的順序(實(shí)例對象必須在原型對象之后創(chuàng)建)

原型對象的常用開發(fā)模式

組合構(gòu)造函數(shù)式和原型模式

function Person( name,age,firends ) {
 
 this.name = name;
 this.age = age;
 this.firends = firends;
 
}

Person.prototype = {
 constructor: Person,
 sayName: function () {
  console.log( this.name );
 }
}

var p1 = new Person('zz',20,['zf']);
var p2 = new Person('zx',22,['z1']);

console.log( p1.firends ); //['zf']    
console.log( p2.firends ); //['z1']

動(dòng)態(tài)原型模式

就是把信息都封裝到函數(shù)中,這樣體現(xiàn)了封裝的概念。

//動(dòng)態(tài)原型模式:(讓你的代碼 都封裝到一起)
function Person( name,age,firends ) {
 
 this.name = name;
 this.age = age;
 this.firends = firends;
 
 //動(dòng)態(tài)原型方法
 if ( typeof this.sayName !== 'function' ) {
  
  Person.prototype.sayName = function () {
   console.log(this.name);
  }
  
 }
 
}

穩(wěn)妥構(gòu)造函數(shù)式

穩(wěn)妥模式就是沒有公共屬性,而且其他方法也不引用this對象,穩(wěn)妥模式最適合在安全的環(huán)境中使用。如果程序?qū)τ诎踩砸蠛芨撸敲捶浅_m合這種模式。
也不能使用new關(guān)鍵字。

//穩(wěn)妥構(gòu)造函數(shù)式 durable object (穩(wěn)妥對象)
//1,沒有公共的屬性
//2,不能使用this對象

function Person ( name,age ) {
 
 //創(chuàng)建一個(gè)要返回的對象。 利用工廠模式思維。
 var obj = new Object();
 
 //可以定義一下是有的變量和函數(shù) private
 
 var name = name || 'zf';
 
//      var sex = '女';
//      var sayName = function () {
//      }

  
 //添加一個(gè)對外的方法
 obj.sayName = function () {
  console.log(name);
 }
 
 return obj;
 
}

var p1 = Person('xixi',20);

p1.sayName(); 

深入原型繼承的概念

如果讓原型對象等于另一個(gè)類型的實(shí)例,結(jié)果會(huì)怎么樣呢?顯然此時(shí)的原型對象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)的另一個(gè)原型中也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針。

原型鏈: 利用原型讓一個(gè)引用類型繼承另外一個(gè)引用類型的屬性和方法。

構(gòu)造函數(shù) 原型對象 實(shí)例對象

  • 構(gòu)造函數(shù).prototype = 原型對象

  • 原型對象.constructor = 構(gòu)造函數(shù)

  • 實(shí)例對象.__proto__ = 原型對象

  • 原型對象.isPrototypeOf(實(shí)例對象)

  • 構(gòu)造函數(shù) 實(shí)例對象 (類和實(shí)例)

isPrototypeOf(); //判斷是否 一個(gè)對象的 原型

JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法

//父類的構(gòu)造函數(shù) Sup
function Sup ( name ) {
 
 this.name = name;
 
}

//父類的原型對象
Sup.prototype = {
 constructor: Sup,
 sayName: function () {
  console.log(this.name);
 }
}

//子類的構(gòu)造函數(shù) Sub
function Sub ( age ) {
 
 this.age = age;
 
}

//如果子類的原型對象 等于 父類的 實(shí)例

//1, 顯然此時(shí)的原型對象將包含一個(gè)指向另一個(gè)原型的指針
//2, 相應(yīng)的另一個(gè)原型中也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針。

//   實(shí)例對象.__proto__ = 原型對象
//    Sup的實(shí)例對象 和 Sup的原型對象 有一個(gè)關(guān)系

Sub.prototype = new Sup('zf');

//   console.log( Sub.prototype.constructor ); //function Sup () {}
//   
//   console.log( Sub.prototype.__proto__ ); //Sup 的 原型對象


var sub1 = new Sub(20);

console.log( sub1.name ); //zf
sub1.sayName(); //zf

原型鏈繼承映射圖

JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法


JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法

繼承的三種方式

原型繼承

//原型繼承的特點(diǎn):
//即繼承了父類的模板,又繼承了父類的原型對象。 (全方位的繼承)
//父類
function Person ( name,age ) {
 
 this.name = name;
 this.age = age;
 
}

Person.prototype.id = 10;

//子類
function Boy ( sex ) {
 
 this.sex = sex;  
 
}

//原型繼承
Boy.prototype = new Person('zz');

var b = new Boy();

console.log( b.name ); //zz
console.log( b.id ); //10

類繼承

類繼承 (只繼承模板) 不繼承原型對象 (借用構(gòu)造函數(shù)的方式繼承)

//父類
function Person ( name,age ) {
 
 this.name = name;
 this.age = age;
 
}

Person.prototype.id = 10;

//子類
function Boy ( name,age,sex ) {
 
 //類繼承
 Person.call(this,name,age);
 
 this.sex = sex;  
 
}

var b = new Boy('zf',20,'女');

console.log( b.name ); //zf
console.log( b.age ); //20
console.log( b.sex ); //女
console.log( b.id ); //父類的原型對象并沒有繼承過來. 

混合繼承

原型繼承+類繼承

 
 //父類  (關(guān)聯(lián)父類和子類的關(guān)系)
function Person ( name,age ) {
 
 this.name = name;
 this.age = age;
 
}

Person.prototype.id = 10;
Person.prototype.sayName = function () {
 console.log( this.name );
}

//子類
function Boy ( name,age,sex ) {
 
 //1 類繼承
 Person.call(this,name,age); //繼承父類的模板
 
 this.sex = sex;  
 
}    

//2 原型繼承
//父類的實(shí)例 和 父類的 原型對象的關(guān)系.
Boy.prototype = new Person(); //繼承父類的原型對象

var b = new Boy('z1',20,'女');

console.log( b.name );//z1
console.log( b.sex ); //女
console.log( b.id ); //10

b.sayName(); //z1 

ExtJs底層繼承方式

模擬ExtJs底層繼承一部分代碼

//ExtJs 繼承
//2件事: 繼承了1次父類的模板,繼承了一次父類的原型對象


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

Person.prototype = {
 
 constructor: Person,
 
 sayHello: function () {

  console.log('hello world!');

 }
 
}

function Boy ( name,age,sex ) {
 
 //call 綁定父類的模板函數(shù) 實(shí)現(xiàn) 借用構(gòu)造函數(shù)繼承 只復(fù)制了父類的模板
 
//    Person.call(this,name,age);

  Boy.superClass.constructor.call(this,name,age);
 
 this.sex = sex;  
 
}

//原型繼承的方式: 即繼承了父類的模板,又繼承了父類的原型對象。
//   Boy.prototype = new Person();
//只繼承 父類的原型對象
 extend(Boy,Person); // 目的 只繼承 父類的原型對象 , 需要那兩個(gè)類產(chǎn)生關(guān)聯(lián)關(guān)系.

//給子類加了一個(gè)原型對象的方法。
Boy.prototype.sayHello = function () {
 
 console.log('hi,js');
 
}

var b = new Boy('zf',20,'男');

console.log( b.name );
console.log( b.sex );
b.sayHello(); 

Boy.superClass.sayHello.call(b);

//extend方法

//sub子類, sup 父類
function extend ( sub,sup ) {
 
 //目的, 實(shí)現(xiàn)只繼承 父類的原型對象。 從原型對象入手
 
 //1,創(chuàng)建一個(gè)空函數(shù), 目的:空函數(shù)進(jìn)行中轉(zhuǎn)
 var F = new Function(); // 用一個(gè)空函數(shù)進(jìn)行中轉(zhuǎn)。
 
//    把父類的模板屏蔽掉, 父類的原型取到。
 
 F.prototype = sup.prototype; //2實(shí)現(xiàn)空函數(shù)的原型對象 和 超類的原型對象轉(zhuǎn)換
 
 sub.prototype = new F(); //3原型繼承
 
 //做善后處理。 還原構(gòu)造器 ,
 sub.prototype.constructor = sub; //4 ,還原子類的構(gòu)造器
 
//    保存一下父類的原型對象 // 因?yàn)?①方便解耦, 減低耦合性  ② 可以方便獲得父類的原型對象
 sub.superClass = sup.prototype; //5 ,保存父類的原型對象。 //自定義一個(gè)子類的靜態(tài)屬性 , 接受父類的原型對象。
 
 //判斷父類的原型對象的構(gòu)造器, (防止簡單原型中給更改為 Object)
 if ( sup.prototype.constructor == Object.prototype.constructor ) {
  
  sup.prototype.constructor = sup; //還原父類原型對象的構(gòu)造器
  
 }
 
}

看完上述內(nèi)容,是不是對JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)的方法有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI