很快就要从新浪离职了,最近心情比较轻松,抽点空整理一下构造函数和原型的机理。

我们都知道,在经典设计模式中我们最常用的就是工厂模式、构造函数模式、原型模式这几种,听起来‘模式’好像很高大上的样子,实际上我们在日常写js代码中会经常用到。

简单的说,工厂模式就是我们平常写的一个个函数,当要完成某项功能时,就一遍一遍调用这个函数。如:

  1. function add(a,b){
  2. return a+b;
  3. }

这是一个很简单的代码,完成的是一个很简单的两数相加的功能,当我们需要两数相加的计算时,调用这个函数就可以了。

我要在这里申明:工厂模式不一定比构造函数模式低级,因为用的场合不一样。富士康是全球最大的代工工厂,但我们没法说它很low,它的工厂流水模式也是非常先进的。

但是工厂模式无法实现实例识别的问题(太晦涩,不好懂),简单的说就是无法实现java、c#等类的功能。当然js没有类,只是用构造函数模拟类。创建一个类,然后功能相同或相近的都调用这个类,产生不同的实例,这样是不是引用起来就更方便一些呢?

在什么情况下用一般函数就可以,什么时候用类(构造函数)比较好呢?这个我认为没有定论。当实现一个很简单的功能的时候,如上面的这个相加函数,就没有必要变为构造函数模式。但是当我们要封装一个大的模块,比如手机滚动图等比较复杂的功能的时候,用构造函数就相对比较好一些,因为封装成类了,可以保持很好的封装性,更符合面向对象的特性。

这里就不把设计模式往细里谈了,拉回正题。

构造函数我们都知道如何构造,那么当new一个实例的时候,背后发生了什么呢?先看一个构造函数

  1. function Person(name,age,gender){
  2. this.name=name;
  3. this.age = age;
  4. this.gender=gender;
    this.work = function(){
        alert(this.name);
    }
  5. }
  6.  
  7. var person1 = new Person('zhangsan',24,'male');

那么person1这个实例是个什么?函数?对象?

如果console.log(person1) 就可以很清晰的看到,是一个对象{‘name':'zhangsan',age:24,gender:'male',work:function(){alert(this.name)}};

如果再创建一个person2,那么person2里的属性值和person1里的属性值是完全独立的,这样是不是我们就可以通过实例对象进行进一步的操作了呢?

但是这样定义还是有待商榷的,因为每次创建一个实例,都会让构造函数执行一次,所以每个实例里都有相同的work函数定义。这样既耗内存又没有任何必要。所以需要把这个构造函数改造如下:

  1. function Person(name,age,gender){
  2. this.name=name;
  3. this.age = age;
  4. this.gender=gender;
  5. this.work =work;
  6. }
  7. function work(){
  8. alert(this.name);
  9. }
  10. var person1 = new Person('zhangsan',24,'male');

大家看这样是不是就好很多了呢?

但是,这样也不是最优的,因为这个work函数在全局中,但是它的用途只是给Person这个构造函数用的,所以缺点就是1、暴露在全局中 2、没有封装

于是可以利用函数的原型。注意两个概念:函数天生有prototype属性,但是普通对象并没有。普通对象有的是_ _ proto_ _属性,所以实例对象通过__proto__属性可以访问到函数的prototype属性。这也就是原型链的一环。原型链后面再说。

运用prototype可以很好的解决构造函数的上述两个缺点。如下

  1. function Person(name,age,gender){
  2. this.name=name;
  3. this.age = age;
  4. this.gender=gender;
  5.  
  6. }
  7. Person.prototype={
  8. work:function(){
  9. alert(this.name);
  10. }
  11. }
  12. var person1 = new Person('zhangsan',24,'male');

大家看,这样是不是更加优化,更加有面向对象的思想了呢?

原型的由来和好处说完了,再说说上面提到的原型链。

实例person1的__prototype__属性可以访问Person的prototype属性,所以可以正确的解析work函数。这就是原型链。具体来说就是:

person1要寻找属性时,首先看自己有没有这个属性。(不要忘了person1就是一个对象),如果没有,好,那就往Person的protype上找。找到了,然后执行就可以了。

这里注意寻找的顺序: 自身----》构造函数的Prototype---》Object的prototype,如果再没有,就报错了。

那么我们如果要判断一个实例的某个属性是类上的(构造函数)还是类的原型上的呢?这里有in操作符合hasOwnProperty方法来定位。

为什么要判断呢?因为有的需求可能只要实例所在的类上的属性,不要原型上的属性。那么这时这两个操作符/方法就派上大用场了

  1. function Person(name,age,gender){
  2. this.name=name;
  3. this.age = age;
  4. this.gender=gender;
  5.  
  6. }
  7. Person.prototype={
  8. work:function(){
  9. alert(this.name);
  10. }
  11. }
  12.  
  13. var person1 = new Person('zhangsan',24,'male');
  14. console.log(person1.hasOwnProperty('name')) ; //true
  15. console.log('name' in person1); //true

如果hasOwnProperty返回的是true,那么说明name这时属性是类上的。in操作符返回的是true,说明name这个属性肯定是类上的或者类的原型上的。

通过hasOwnProperty和in就可以定位确定啦。

我遇到过一个面试题,是考察构造函数和原型的,大概是这样:

  1. function Person(name,age,gender){
  2. this.name=name;
  3. this.age = age;
  4. this.gender=gender;
  5.  
  6. }
  7. Person.prototype={
  8. work:function(){
  9. alert(this.name);
  10. }
  11. }
  12.  
  13. var person1 = new Person('lisi',34,'male');
  14. Person.study= 'English';
  15. Person.prototype.course='Math';
  16.  
  17. console.log(person1.study);
  18. console.log(person1.course);

ok,看看console.log(person1.study);返回的是什么呢?再看看console.log(person1.course);返回的是什么呢?

呵~呵~

答案是 undefined 和Math

这又是为什么呢?这就涉及到原型的动态性。什么意思?也就是说原型上的属性是动态性的,虽然创建实例在前面,但是当在下面再创建prototype上的属性的时候,prototype会自动更新。

但是构造函数没有动态性,定义了Person类以后再给Person这个类添加属性或方法是不会添加成功的。

要深究起来,构造函数和原型这块确实是水很深,坑不少,需要我们认真研究,不拘泥于效果出来就万事大吉。

先写到这里啦!

深入研究js构造函数和原型的更多相关文章

  1. js 构造函数 & 静态方法 & 原型 & 实例方法

    js 构造函数 & 静态方法 & 原型 & 实例方法 ES5 "use strict"; /** * * @author xgqfrms * @licens ...

  2. 完整原型链详细图解之JS构造函数、原型 原型链、实例化对象

    一.首先说一下什么是构造函数: 构造函数:用来在创建对象时初始化对象.特点:构造函数名一般为大写字母开头:与new运算符一起使用来实例化对象. 举例: function Person(){} //Pe ...

  3. JS构造函数、原型对象、隐含参数this

    This 解析器再调用函数每次都会向函数内部传递一个隐含的参数this,this指向的是一个对象(函数执行的上下文对象) 1.以函数形式调用时,this永远是window. 2.以方法形式调用时,th ...

  4. 笔记: js构造函数与原型

    目录 构造函数与原型介绍 涉及三种引用的操作 有关原型及原型链的一些相关方法总结 @ 构造函数与原型介绍 1.函数与函数的原型对象(prototype object): 在JavaScript中,创建 ...

  5. 一句话总结JS构造函数、原型和实例的关系

    "每个构造函数都有一个原型对象, 原型对象都包含一个指向构造函数的指针, 实例都包含一个指向原型对象的内部指针." --此段话摘自<JavaScript高级程序设计>. ...

  6. JS中构造函数与原型对象的同名属性,实例会取哪一个

    构造函数与原型对象的同名属性,实例会取哪一个? 看了下面的过程,再回忆JS高程3里关于这部分的示意图.实例my在new的时候,本身就获得了a属性,所以my.a是1,倘若在new的时候如果没有赋予a属性 ...

  7. JS构造函数的用法和JS原型

    $(function(){ var rec = new Rectangle(5, 10); //alert(rec.width + "*" + rec.height + " ...

  8. Js笔记(对象,构造函数,原型,原型链,继承)及一些不熟悉的语法

    对象的特性: 1.唯一标识性,即使完全不一样的对象,内存地址也不同,所以他们不相等 2.对象具有状态,同一个对象可能处在不同状态下 3.对象具有行为,即对象的状态可能因为他的行为产生变迁 Js直到es ...

  9. JS高级. 02 面向对象、创建对象、构造函数、自定义构造函数、原型

    面向对象的三大特性: 封装 a)  把一些属性和方法装到一个对象里 2.  继承 a)  js中的继承是指:   一个对象没有一些方法和属性,而另一个对象有 把另一个个对象的属性和方法,拿过来自己用, ...

随机推荐

  1. C#基础——全局静态类中的静态类变量的设置

    前言 今天在设计一个系统用户管理界面的时候,出现了一个问题: 由于要在不同窗体之间传递数据,所以想到了要设置全局变量,比如一个用户有属性,ID,UserName,UserPwd和UserPower,为 ...

  2. 【转载】RMAN备份保留策略设置相关命令

    转自 http://blog.sina.com.cn/s/blog_7c5a82970101g4s7.html 策略有两种,一种是基于恢复窗口策略的,一种是基于冗余策略的. 基于恢复窗口策略: 定义的 ...

  3. React(JSX语法)-----JSX基本语法

    JSX------HTML tags vs React Components: 1.To render a html tag,just use lower-case tag names in JSX; ...

  4. 在项目中导入MRC的文件时解决办法

    1.由于在项目中要使用到第三方框架和其他的类的时候,而它用的是MRC的时候,其最简便的方法:完成从MRC到ARC的转换. 1.点击工程文件,进入到工程的设置里面. 2.看见Build Phases,就 ...

  5. 水平ListView类

    package com.hztbc.android.HorizontalListView; /* * HorizontalListView.java v1.5 * *  * The MIT Licen ...

  6. Android 多线程处理之多线程用法大集合

    handler.post(r)其实这样并不会新起线程,只是执行的runnable里的run()方法,却没有执行start()方法,所以runnable走的还是UI线程. 1.如果像这样,是可以操作ui ...

  7. Xcode LLDB Debug教程

    开胃小菜--简单的断点调试 在xcode中打开一个app,在想要break的行号上单击,即可生成一个深色的箭头标识--断点.如下图,在viewDidLoad:中设置了断点. 运行app,等待...就可 ...

  8. 多系统PE win UBUNTU OSX

    WIN8 PE来自黑果圈中著名的地平线大神- 内置wim安装工具.EFI修复工具 OSX PE来自 FireWolf OS X PE V7.0 UBUNTU 直接安装盘就能当PE用 需要一个FAT32 ...

  9. 移动web

    1.分辨率 1900*1200这就是一个分辨率, 因为pt的存在,因此还会有一个逻辑分辨率的概念 2.ppi = pixels per inch这里inch不是平方英尺,是英尺 3.dp = devi ...

  10. python——socket网络编程

    一.OSI七层模型