JavaScript面向对象和原型————呱呱二号

面向对象

1、工厂模式

function createObject(name,age){
  let obj = new Object();
  this.name = name;
  this.age = age;
  return obj;            
}
let objA = createObject('Tom',24);
let objB = createObject('Jane',23);
typeof ObjA;    //Object
typeof ObjB;    //Object
ObjA instanceof Object;
ObjA instanceof Object;
//方法缺点:不能区分对象实例,所有对象实例都由Object实例化

2、构造函数模式

function Box(name,age){
  this.name = name;
  this.age = age;     
  this.run = function (){
    return this.name + this.age;
  }  
}
function Desk(name,age){
  this.name = name;
  this.age = age;   
  this.run = function (){
    return this.name + this.age;
  }       
}
let box = new Box('Tom',24);
let desk = new Desk('Jane',23);
box instanceof Box;  //true
box instanceof Desk;  //false
desk instanceof Desk;  //true
//
//知识延伸,对象冒充
let o = new Object();
Box.call(o,'Ha',25);
o.name;

构造函数方式和原型方式变量存储的方式

JavaScript面向对象和原型————呱呱二号

JavaScript面向对象和原型————呱呱二号

 3、原型

  我们创建的每一个函数都有一个prototype(原型属性),这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype通过调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。(我自己的理解,通过构造函数创建的对象会自动创建一个原型对象prototype。)

function Box(){}

Box.prototype.name = 'Lee';  //原型属性

Box.prototype.age = 100;

Box.prototype.run = function () {  //原型方法

  return this.name + this.age + '运行中';

}

证明:原型对象内的属性和方法都被实例对象共用

let box1 = new Box();

let box2 = new Box();

Object.is(box1.run,box2.run);  //true  Object.is(),判断两个变量是否相等 (等于box1.run === box2.run);

说明box1和box2中的run方法都指向同一个引用地址。

JavaScript面向对象和原型————呱呱二号

在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。__proto__属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。通过这两个属性,就可以访问到原型里的属性和方法了。

//判断一个实例对象是否指向了原型对象,只要实例化了,会自动指向的

Box.prototype.isPrototypeOf(box1);  //true    接着上面的代码

let obj = new Object();  //

Box.prototype.isPrototypeOf(obj);

 

如果实例对象中有name属性,原型对象中也有name属性,通过 . 访问name会打印处实例对象中的name属性。

function Box () {}

Box.prototype.name = 'guaguaerhao';

let box1 = new Box();

box1.name = '呱呱二号';

console.log(box1.name);  //呱呱二号

原型模式的执行流程:

1、先查找实例对象中是否存在属性,如果存在,则返回

2、如果实例对象中没有该属性,则在原型对象中查找,如果存在,则返回

 判断实例中是否存在属性

box1.hasOwnProperty('name');  //true

(name in box1)  //不管是原型中有name属性还是实例中有name属性,都会返回true

判断只有原型中是否存在属性

function hasPrototypeProperty(object,property){

  return !object.hasOwnProperty(property) && (property in object);

}

4、字面量原型模式

function Box () {}

Box.prototype = {

  constructor: Box,  //将原型对象的constructor强制指向回Box

  name: 'guaguaerhao',

  age: 24,

  run: function(){

    return this.name + this.age;

  }

}

 ps:原型中最大的缺点就是它的优点,共享。原型模式创建的对象,省略了构造函数传参,带来的缺点就是初始化的值都是一样的。

 5、构造函数加原型模式(构造函数和方法分开,没有一种封装的感觉,感觉很零碎)

function Box(name,age){    //不共享的使用构造函数

  this.name = name;

  this.age = age;

  this.family = ['爸爸','妈妈','哥哥','我'];

}

 Box.prototype = {    //共享的使用原型

  constructor: Box,

  run: function () {

    return this.name + this.age;

  }

}

6、动态原型模式

 function Box(name,age){

  this.name = name;

  this.age = age;

  //可是,实例化对象的时候,每次都会创建run()方法,浪费内存,因为他在每一个对象中都是一样的功能,没有必要,每次实例化都创建,实际上只需要创建一次。

  Box.prototype.run = function () {

    return this.name + this.age;

  }

}

所以

function Box(name,age){

  this.name = name;

  this.name = age;

  if(typeof this.run !== 'function'){  //只会实例化一次

    Box.prototype.run = function () {

      return this.name + this.age;

    }

  }

}

7、寄生构造函数(工厂模式+构造函数)

function Box(name,age){

  let obj = new Object();

  obj.name = name;

  obj.age = age;  

  obj.run = function (){

    return this.name + this.age;

  }

  return obj;

}

let obj = new Box('ha',24);

obj.run();

7、寄生构造函数(工厂模式+构造函数)

function Box(name,age){

  let obj = new Object();

  obj.name = name;

  obj.age = age;  

  obj.run = function (){

    return this.name + this.age;

  }

  return obj;

}

let obj = Box('ha',24);

obj.run();

 继承

1、继承是面向对象中比较核心的概念,ECMAScript只支持继承:

JavaScript面向对象和原型————呱呱二号

function Parent(){

  this.name = 'p';

}

function Child(){

  this.name = 'c';

}

//通过原型链继承,父类实例化后的对象实例,赋值给子类型的原型属性

//new Parent()会将构造函数里的信息和原型的信息都交给Child

Child.prototype = new Parent();

2、对象冒充模式

为了解决引用共享和超类型无法传参的问题,采用一种叫借用构造函数的技术,或者成为对象冒充

function Parent(name,age){

  this.name = name;

  this.age = age;

}

//Parent.prototype.family = '家庭';  //child实例无法访问

function Child(name,age){

  Parent.call(this,name,age);  //对象冒充,给父类传递参数,对象冒充只能继承构造函数中的属性,原型中的无法访问

}

let child = new Child('haha',24);

child.name;

child.family;  //undefined

3、原型链加借用构造函数,组合模式

function Parent(age){

  this.age = age;

}

Parent.prototype.run = function () {  //解决了方法共享

  return this.age;

}

function Child(age){

  Parent.call(this,age);

}

Child.prototype = new Parent();

(4-6未完善,日后再补,邪恶脸)

4、原型式继承:这种继承借助原型并基于已有的对象创建新对象,同事不必因此创建自定义类型。

//临时中转函数

function obj(o){  //o表示将要传递进入的一个对象

  function F(){}  //F构造是一个临时新建的对象,用来存储传递过来的对象

  F.prototype = o;  //将o对象实例赋值给F构造的原型对象

  return new F();  //最后返回这个得到传递过来的对象的对象实例

}

 

//其实F.prototype = o;就相当于 Child.prototype = new Parent();

 

//这是字面量的声明方式,相当于var box = new Box();

var box = {

  name: 'lee',

  age: 100,

  family: ['haha','hehe']

}

//box1就等于new F();

var box1 = obj(box);

alert(box1.name);

box1.family.push('xixi');

alert(box1.family);    //['haha','hehe','xixi']

 

var box2 = obj(box);

alert(box2.family);    //['haha','hehe','xixi']  //对象的引用属性,共享了

 

5、寄生式继承(原型式加工厂模式):

function obj(o){  //o表示将要传递进入的一个对象

  function F(){}  //F构造是一个临时新建的对象,用来存储传递过来的对象

  F.prototype = o;  //将o对象实例赋值给F构造的原型对象

  return new F();  //最后返回这个得到传递过来的对象的对象实例

}

//寄生函数

function create(o){

  var f = obj(o);

  f.run = function () {

    return this.name;

  }

  return f;

}

var box = {

  name: 'lee',

  age: 100,

  family: ['haha','hehe']

}

var box1 = create(box);

alert(box1.name);

6、寄生组合继承

//临时中转函数

function obj(o){  //o表示将要传递进入的一个对象

  function F(){}  //F构造是一个临时新建的对象,用来存储传递过来的对象

  F.prototype = o;  //将o对象实例赋值给F构造的原型对象

  return new F();  //最后返回这个得到传递过来的对象的对象实例

}

//寄生函数

function create(box,desk){

  var f = obj(box.prototype);

  desk.prototype = f;

  return f;

}

function Box(name,age){

  this.name = name;

  this.age = age;

}

Box.prototype.run = function(){

  return this.name + this.age + '运行中...'

}

function Desk(name,age){

  Box.call(this.name);

  this.age = age;

}

//通过寄生组合继承来实现继承

create(Box,Desk);  //这句话用来代替Desk.prototype = new Box()

 

let desk = new Desk('lee',100);

alert(desk.run());

(1、原型链继承,2、借用构造函数继承(对象冒充继承)3、组合继承(结合前两种)4、原型式继承)

 
 
G
M
T
 
Detect languageAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathi*nMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu   AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathi*nMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu          
 
 
 
Text-to-speech function is limited to 200 characters
 
  Options : History : Feedback : Donate Close