js面向对象

作者: 好次的猪头饭 | 来源:发表于2016-08-26 21:39 被阅读111次

js面向对象

方法一:工厂模式

所谓工厂模式,简单点儿说就是按照工厂生产的过程创建对象,原材料->加工->返还产品

function createPerson(name,age,job)
{
    //送入原材料
    var o = new Object();
    //加工
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    }
    //出厂
    return o ;
}

var person1 = createPerson("Nicole",12,"software engnieer");
var person2 = createPerson("Join",15,"writer");

优点很明显,解决了创建多个具有相似属性和方法的对象的问题,但是却没有解决对象识别的问题
比方说:

alert(person1 instance of Object);//true
alert(person1 instance of createPerson);//false

方法二:构造函数模式

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

    this.sayName = function(){
        alert(this.name);
    }
}

var person1 = new Person("Nicole",12,"software engnieer");
var person2 = new Person("Join",15,"writer");

从上面可以看出,构造函数模式,不在函数内部创建Object对象,而是用this代替,最后创建实例时使用new
其中:

var person1 = new Person("Nicole",12,"software engnieer");

经历了以下几个过程:
1.var o = new Object();
2.o = this(Person);
3.执行构造函数中的代码;
4.返回新对象

优点:1.使用new创建对象,更符合面向对象的创建习惯;
2.红宝书上说创建构造函数意味着将它的实例标识为一种特定的类型,我的理解是,就是创建了一种类型,你可以用它去创建实例。

   alert(person1 instanceof Object);//true
   alert(person1 instanceof Person);//true

为什么可以这样呢,因为你用Person实例化的对象,它都保存了一个constructor属性,指向Person。

   alert(person1.constructor == Person);//true
   alert(person2.constructor == Person);//true

缺点:首先,我们看一段代码:

   this.sayName = function(){}
   this.sayName = new Function("");

这两段代码在逻辑上是等价的,也就是说在ECMAscript中,函数是对象,每定义一个函数,就会实例化一个对象,因此,不同实例的不同函数是不相等的,用构造函数模式创建的对象,虽然看起来是大家“共用”了一个功能函数,但其实它们都是不同的对象,这就很没有必要。

方法三:原型模式

试想一下,能不能把sayName拿出来放在一个公共区域里,这样举例子可能有些不合适,因为并不是说你用sayName的时候我就不可以用,我们想要的是不管谁去取,多少对象同时使用都可以,但是sayName只有一个。这样的想法就诞生原型模式,这个公共区域就是prototype。

如图所示,无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数。


prototype

创建一个prototype属性,该属性指向函数的原型对象。而原型对象会获取一个constructor属性,该属性指向对应的构造函数。而对象的实例中则含有一个[[prototype]]的属性,它指向原型对象。这个属性对脚本是完全不可见的,但是可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系,如果说[[prototype]]指向调用isPrototype()方法的对象(obj.prototype),这个方法就返回true:

alert(Person.prototype.isPrototypeOf(person1));//true

ECMAscript 5中新增加一个方法Object.getPrototypeOf(),返回[[Prototype]]的值:

alert(Object.getPrototypeOf(person1) == Person.prototype);//true
alert(Object.getPrototypeOf(person1).name);//Nicole

原型创建代码:

function Person(){

      }
      Person.prototype.name = "Nicole";
      Person.prototype.age = 12;
      Person.prototype.job = "software engnieer";
      Person.prototype.sayName = function(){
          alert(this.name);
      }

      var person1 = new Person();
      person1.sayName();//Nicole

      var person2 = new Person();
      person2.sayName();//Nicole

      alert(person1.sayName == person2.sayName);//true

更简单的原型语法:

前面例子每添加一个属性和方法就要敲一遍Person.prototype,很麻烦,可以使用字面量重写整个原型对象:

function Person(){

      }
      Person.prototype = {
          name:"Nicole",
          age:12,
          job:"software engnieer",
          sayName:function(){
              alert(this.name);
          }
      }

在这个例子中,我们将Person.prototype设置等于一个以字面量形式创建的新对象,最终结果相同,但是要注意的是,constructor不再指向Person,指向Object。

alert(Person.prototype.constructor == Person);//false

因此需要人工的配置constructor的指向:

Person.prototype = {
        constructor:Person,
         name:"Nicole",
          age:12,
          job:"software engnieer",
          sayName:function(){
              alert(this.name);
          }
     }

这样写依然有一个问题,就是重写prototype切断了,现有原型和重写前已经存在的实例的联系,它们引用的依然是最初的原型:

function Person(){

     }
     var person1 = new Person();

     Person.prototype = function(){
         constructor:Person,
         name:"Nicole"
     };

     alert(person1.name);//error

原型对象的缺点
共享是把双刃剑,它就带来了便利,也带来了麻烦,比方说:

function Person(){

     };

      Person.prototype = {
        constructor:Person,
         name:"Nicole",
          age:12,
          job:"software engnieer",
          friends:['hah','hhe'],
          sayName:function(){
              alert(this.name);
          }
     };
     var person1 = new Person();
     var person2 = new Person();


     person1.friends.push('black');

     alert(person2.friends);//'hah','hhe','black'

修改一个实例的原型方法或者属性,所有相关实例都会相应的变化。

方法四:组合使用构造函数模式和原型模式

为了解决原型模式的缺点,我们可以使用构造函数定义实例属性,用原型模式定义方法和共享的属性。

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

         this.friends=["hello","world"];
     }

     Person.prototype = {
         constructor:Person;
         sayName:function(){
             alert(this.name);
         }
     }

     var person1 = new Person("Nicole",12,"software engnieer");
     var person2 = new Person("blue",14,"writer");
     
     person1.friends.push("!");

     alert(person1.friends);//"hello","world","!"
     alert(person2.friends);//"hello","world"

相关文章

  • JS面向对象精要(二)_函数

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • JS面向对象精要(三)_理解对象

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • JS面向对象精要(四)_构造函数和原型对象

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • JS面向对象精要(五)_继承

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • js 面向对象和面向过程

    js 面向对象和面向过程

  • 面向对象OOP--JS

    作者:烨竹 JS面向对象简介 JS名言:万物皆对象 JS面向对象比PHP简单很多;因为JS中没有class关键字,...

  • JavaScript笔记(一)

    一、面向对象面向过程的区别 1、什么是js对象 js对象:属性和方法的集合,js所有数据都可以看成对象...

  • JS面向对象

    JS面向对象入门 1、面向对象语言概念面向对象语言主要包括 类、对象、封装、多肽。2、面向对象的编程思想面向过程思...

  • 2018-01-18

    js中的面向对象核心 js是基于对象的编程语言,在后面的学习中我们通过一种模式使其转化成为面向对象的语言。js面向...

  • 浅谈JS中的面向对象

    浅谈JS中的面向对象 本文主要说说本人在JS中对面向对象的理解。 计算机编程语言主要分为面向过程式编程和面向对象式...

网友评论

    本文标题:js面向对象

    本文链接:https://www.haomeiwen.com/subject/mvmzsttx.html