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

1.对象封装

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

  1. var Cat = {
  2.     name : '',
  3.     color : ''
  4.   }

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


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

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

  1.  function Cat(name,color){
  2.     return {
  3.       name:name,
  4.       color:color
  5.     }
  6.   }

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

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

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

2.构造函数

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

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

  1. function Cat(name,color){
  2.     this.name=name;
  3.     this.color=color;
  4.   }

生成实例对象:

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

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

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

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

  1.   alert(cat1 instanceof Cat); //true
  2.   alert(cat2 instanceof Cat); //true

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

3.构造函数的深入理解

  1. // 构造函数
  2. function Foo(y) {
  3. // 构造函数将会以特定模式创建对象:被创建的对象都会有"y"属性
  4. this.y = y;
  5. }
  6. // "Foo.prototype"存放了新建对象的原型引用
  7. // 所以我们可以将之用于定义继承和共享属性或方法
  8. // 所以,和上例一样,我们有了如下代码:
  9. // 继承属性"x"
  10. Foo.prototype.x = 10;
  11. // 继承方法"calculate"
  12. Foo.prototype.calculate = function (z) {
  13. return this.x + this.y + z;
  14. };
  15. // 使用foo模式创建 "b" and "c"
  16. var b = new Foo(20);
  17. var c = new Foo(30);
  18. // 调用继承的方法
  19. b.calculate(30); // 60
  20. c.calculate(40); // 80
  21. // 让我们看看是否使用了预期的属性
  22. console.log(
  23. b.__proto__ === Foo.prototype, // true
  24. c.__proto__ === Foo.prototype, // true
  25. // "Foo.prototype"自动创建了一个特殊的属性"constructor"
  26. // 指向a的构造函数本身
  27. // 实例"b"和"c"可以通过授权找到它并用以检测自己的构造函数
  28. b.constructor === Foo, // true
  29. c.constructor === Foo, // true
  30. Foo.prototype.constructor === Foo // true
  31. b.calculate === b.__proto__.calculate, // true
  32. b.__proto__.calculate === Foo.prototype.calculate // true
  33. );

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

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

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

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


  1. function Foo() {
  2. this.bla = 1;
  3. }
  4. Foo.prototype.test = function() {
  5. console.log(this.bla);
  6. };
  7. var test = new Foo();

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

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

4.构造函数问题

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

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

生成实例:

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

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

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

5. Prototype模式的验证方法

1.isPrototypeOf()

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

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

2.hasOwnProperty()

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


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

3.in

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

  1.   alert("name" in cat1); // true
  2.   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. Android日期时间选择器DatePicker、TimePicker日期时间改变事件响应(Android学习笔记)

    activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&qu ...

  2. visual studio installer 卸载时不能删除安装目录问题

      在vs中可以制作安装程序,但是这个安装程序默认卸载的时候不会把安装目录卸载,如果想在卸载的时候删除这个目录,那就要费点周折了.此方法同时适应于程序自删除以及工作目录删除. 基本思路是在程序要退出的 ...

  3. IIS只允许某些IP访问

    1. 2. 3.访问时提示 4.设置允许访问的IP 5.指定的IP访问时没问题了,而其他的IP不允许访问

  4. python中一些算法数列

    斐波那契数列: 1 def fn(n): 2 if n==1: 3 return 1 4 elif n==2: 5 return 1 6 else: 7 return fn(n-1)+fn(n-2) ...

  5. pg_basebackup命令解析

    pg_basebackup命令首先解析输入的参数,再调用BaseBackup()函数进行备份处理. 在BaseBackup()函数内部,会首先传送WAL日志(如果指定了-x选项的话).随后依次遍历所有 ...

  6. 获取 stoken 或者id MVC写法

    //获取地址栏 painting_idvar painting_id = "{$_GET['painting_id']}"; var stoken = "{$_SESSI ...

  7. CentOS 中安装tomcat

    1.安装tomcat前,需要安装JDK 2.下载tomcat安装包 wget http://mirrors.hust.edu.cn/apache/tomcat/tomcat-8/v8.5.31/bin ...

  8. Qt 学习之路 2(56):使用模型操作数据库

    Qt 学习之路 2(56):使用模型操作数据库 (okgogo: skip) 豆子 2013年6月20日 Qt 学习之路 2 13条评论 前一章我们使用 SQL 语句完成了对数据库的常规操作,包括简单 ...

  9. Python之freshman08 Socket

    1. Socket介绍 概念 A network socket is an endpoint of a connection across a computer network. Today, mos ...

  10. JavaWeb学习笔记(九)—— JSTL标签库

    一.JSTL概述 1.1 什么是JSTL  JSTL是apache对EL表达式的扩展(也就是说JSTL依赖EL),JSTL是标签语言!JSTL标签使用以来非常方便,它与JSP动作标签一样,只不过它不是 ...