JavaScript创建对象主要是3种方法:工厂模式、构造函数模式、原型模式。其实对于构造函数的概念,我们并不陌生。在之前学习c++语言的时候,也有提到过构造函数的概念。除了创建对象,构造函数(constructor) 可以自动为创建的新对象设置原型对象(prototype object) ,原型对象存放于Constructor Function.prototype 属性中。

1.对象封装

如果一个对象具有属性"(property)和"方法"(method),我们希望封装成一个对象,甚至要从原型对象生成一个实例对象,那么就诞生了构造函数的思想。首先来看原始的实现方式:

var Cat = {
    name : '',
    color : ''
  }

现在可以根据这个原型对象的规格(schema,生成两个实例:


var cat1 = {}; // 创建一个空对象
    cat1.name = "大毛"; // 按照原型对象的属性赋值
    cat1.color = "黄色";
  var cat2 = {};
    cat2.name = "二毛";
    cat2.color = "黑色";

为了解决代码重复赘余问题,上述代码可以改进如下:

 function Cat(name,color){
    return {
      name:name,
      color:color
    }
  }

接下来是生成实例对象,即调用函数:

 var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");

问题:at1和cat2之间没有内在的联系,不能反映出它们是同一个原型对象的实例

2.构造函数

为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。

所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。

function Cat(name,color){
    this.name=name;
    this.color=color;
  }

生成实例对象:

    var cat1 = new Cat("大毛","黄色");
  var cat2 = new Cat("二毛","黑色");
  alert(cat1.name); // 大毛
  alert(cat1.color); // 黄色

这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。

   alert(cat1.constructor == Cat); //true
  alert(cat2.constructor == Cat); //true

Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系。

  alert(cat1 instanceof Cat); //true
  alert(cat2 instanceof Cat); //true

构造函数方法很好用,但是存在一个浪费内存的问题。

3.构造函数的深入理解

// 构造函数
function Foo(y) {
// 构造函数将会以特定模式创建对象:被创建的对象都会有"y"属性
this.y = y;
} // "Foo.prototype"存放了新建对象的原型引用
// 所以我们可以将之用于定义继承和共享属性或方法
// 所以,和上例一样,我们有了如下代码: // 继承属性"x"
Foo.prototype.x = 10; // 继承方法"calculate"
Foo.prototype.calculate = function (z) {
return this.x + this.y + z;
}; // 使用foo模式创建 "b" and "c"
var b = new Foo(20);
var c = new Foo(30); // 调用继承的方法
b.calculate(30); // 60
c.calculate(40); // 80 // 让我们看看是否使用了预期的属性 console.log( b.__proto__ === Foo.prototype, // true
c.__proto__ === Foo.prototype, // true // "Foo.prototype"自动创建了一个特殊的属性"constructor"
// 指向a的构造函数本身
// 实例"b"和"c"可以通过授权找到它并用以检测自己的构造函数 b.constructor === Foo, // true
c.constructor === Foo, // true
Foo.prototype.constructor === Foo // true b.calculate === b.__proto__.calculate, // true
b.__proto__.calculate === Foo.prototype.calculate // true );

上述代码可以表示关系为:

JavaScript 中的构造函数和其它语言中的构造函数是不同的。 通过 new 关键字方式调用的函数都被认为是构造函数。

在构造函数内部 - 也就是被调用的函数内 - this 指向新创建的对象 Object。 这个新创建的对象的 prototype 被指向到构造函数的 prototype。

如果被调用的函数没有显式的 return 表达式,则隐式的会返回 this 对象 - 也就是新创建的对象。


function Foo() {
this.bla = 1;
} Foo.prototype.test = function() {
console.log(this.bla);
}; var test = new Foo();

上面代码把 Foo 作为构造函数调用,并设置新创建对象的 prototype 为 Foo.prototype。

显式的 return 表达式将会影响返回结果,但仅限于返回的是一个对象。

4.构造函数问题

可能会浪费内存。那就是对于每一个实例对象,如果这些实例的某些属性和方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。能不能让一模一样的属性和方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的,Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

 function Cat(name,color){
    this.name = name;
    this.color = color;
  }
  Cat.prototype.type = "猫科动物";
  Cat.prototype.eat = function(){alert("吃老鼠")};

生成实例:

  var cat1 = new Cat("大毛","黄色");
  var cat2 = new Cat("二毛","黑色");
  alert(cat1.type); // 猫科动物
  cat1.eat(); // 吃老鼠

这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。

  alert(cat1.eat == cat2.eat); //true

5. Prototype模式的验证方法

1.isPrototypeOf()

这个方法用来判断,某个proptotype对象和某个实例之间的关

  alert(Cat.prototype.isPrototypeOf(cat1)); //true
  alert(Cat.prototype.isPrototypeOf(cat2)); //true

2.hasOwnProperty()

每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。


 alert(cat1.hasOwnProperty("name")); // true
 alert(cat1.hasOwnProperty("type")); // false

3.in

in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。

  alert("name" in cat1); // true
  alert("type" in cat1); // true

参考资料:

阮一峰http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

JavaScript探秘:构造函数 Constructorhttp://www.nowamagic.net/librarys/veda/detail/1642

ife task0003学习笔记(四):JavaScript构造函数的更多相关文章

  1. ife task0003学习笔记(一):JavaScript作用域

    在学习JavaScript作用域概念之前,首先要明白几个概念:执行环境.变量对象.作用域链. 一.JavaScript执行环境(execution context): 在<Professiona ...

  2. ife task0003学习笔记(三):JavaScript闭包

    一.this易错分析 在学习闭包的时候,有一个概念this很重要,关于this的理解,下面3种情况:this指向谁? fn.call(obj1); obj2.fn() fn() 答案是obj1 obj ...

  3. ife task0003学习笔记(五):JavaScript面向对象

    JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.在 Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.而在 JavaScript 中,this ...

  4. ife task0003学习笔记(二):JavaScript原型

    function aaa(){} aaa.prototype.bbb=function(){} var obj1=new aaa() var obj2=new aaa() obj1和obj2都有一个属 ...

  5. seaJs学习笔记之javascript的依赖问题

    之前分别为大家介绍了有关javascript中的冲突和性能问题,今天为大家介绍一下有关javascript中的依赖问题.我们将继续就之前javascript中性能问题继续介绍. 先来回顾一下性能问题的 ...

  6. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  7. Typescript 学习笔记四:回忆ES5 中的类

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  8. 【学习笔记】JavaScript的基础学习

    [学习笔记]JavaScript的基础学习 一 变量 1 变量命名规则 Camel 标记法 首字母是小写的,接下来的字母都以大写字符开头.例如: var myTestValue = 0, mySeco ...

  9. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

随机推荐

  1. 使用Oracle(SQL Plus)

    error: connection as sys should be as SYSDBA or SYSOPER 用户名 :sys 密码:  自己设定的database:ORCLconnect as : ...

  2. 用原生css实现高斯模糊、黑白等滤镜效果

    —引导— 在CSS3中,有一个强大的属性,那就是filter属性,filter顾名思义就是“滤镜”的意思,用filter属性可以让图片无需PS处理就达到一些简单的显示效果. —定义和使用— filte ...

  3. 构建空Datatable

    方法一 DT = new DataTable(); DataRow DR = DT.NewRow(); //构建列(名称,数据类型) DT.Columns.Add("代码", Ty ...

  4. angular Dom属性绑定

  5. HBase基准性能测试报告

    作者:范欣欣 本次测试主要评估线上HBase的整体性能,量化当前HBase的性能指标,对各种场景下HBase性能表现进行评估,为业务应用提供参考.本篇文章主要介绍此次测试的基本条件,HBase在各种测 ...

  6. spring+hibernate中的事务

    上下文: 从数据库服务器上获取数据可以,保存的时候增加了事务提交,即em.flush方法,报错no transaction in progress 报错信息: no transaction in pr ...

  7. avascript的匿名函数

    一.什么是匿名函数? 在Javascript定义一个函数一般有如下三种方式: 函数关键字(function)语句: function fnMethodName(x){alert(x);} 函数字面量( ...

  8. C# 使用List<T> 内存溢出

    class Program    {        static void Main(string[] args)        {            var all = new List< ...

  9. java的几种对象(PO,VO,DAO,BO,POJO,DTO)解释

    一.PO:persistant object 持久对象,可以看成是与数据库中的表相映射的java对象.最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合.PO中应该不包含任何对数 ...

  10. redux超易学三篇之二(开始使用react-redux)

    其实 redux 真正让人感到混乱的还是在 react-redux 的使用中. 请配合完整代码参考~:完整源代码 也不是说混乱,主要是网上 推崇 最佳实践.学习一个新东西的时候,本来就很陌生,上来就用 ...