javascript基础知识分享之类与函数化


Posted in Javascript onFebruary 13, 2016
1.对象适合于收集和管理数据,容易形成树型结构。
Javascript包括一个原型链特性,允许对象继承另一对象的属性。正确的使用它能减少对象的初始化时间和内存消耗。
2.函数它们是javascript的基础模块单元,用于代码复用、信息隐藏和组合调用。函数用于指定对象的行为。一般来说,编程就是将一组需求分解成一组函数和数据结构的技能。
3.模块我们可以使用函数和闭包来构造模块。模块是一个提供接口却隐藏实现状态和实现的函数或对象。

1.自定义类型--构造函数模式(伪类模式)

在基于类的系统中,对象是这样定义的:使用类来描述它是什么样的。假如建筑是基于类的系统,则建筑师会先画出房子的蓝图,然后房子都按照该蓝图来建造。

在使用自定义类型模式实现继承的时候,我们只需要将参数传递给构造函数,然后将参数挂载在实例对象上。其他关于实例对象的方法都不用传递参数,因为通过 实例对象调用的方法内部的this都可以访问到该参数。挂载在实例this对象上的变量称为实例变量。

组合--继承

function Person (name, age, job) {
  // 实例变量
  this.name = name;
  this.age = age;
  this.job = job;
}
Person.prototype.sayName = function () {
  alert(this.name);
}

var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');
function SuperType (name) {
  this.name = name;
  this.colors = ['red','blue', 'green'];
}

SuperType.prototype.sayName = function () {
  console.log(this.name);
}

function SubType (name, age) {
  // 继承属性
  SuperType.call(this,name);
  this.age = age;
}

// 继承方法
SubType.prototype = new SuperType();

SubType.prototype.sayAge = function () {
  console.log(this.age)
}

var instance1 = new SubType('Nicholas', 29);
instance1.colors.push('black')
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType('Greg', 27)
console.log(instance2.colors);
instance2.sayName();
instance2.sayAge();

在继承属性和继承方法上,我们一共调用了两次超类构造函数,当通过new调用超类构造函数创建子类构造函数的原型时,有一个问题,子类构造函数的原型对象现在便是超类构造函数的实例,因此也会有在超类构造函数为实例对象this添加的属性,只是值为undefined而已,也就是说通过new调用超类构造器函数来更改子类改造器的原型时,那么在子类构造器的原型上便会有多余的属性。这便造成了浪费。而我们需要的其实只是,子类构造器的原型能够继承超类构造器原型的方法而已。因此我们需要的,

1.创建一个子类构造器原型对象。

2.此子类构造器原型继承自超类构造器的原型。

3.因为我们在1中改写了子类构造器的原型对象,也就是重新创建了原型对象,因此我们需要在新创建的原型对象上添加constructor属性并将其赋值为子类构造器函数。

将上面的代码改写一些,如下所示。

关于constructor属性:只在构造器函数的原型上才有的属性并指向该构造器,改写了的原型对象默认是没有constructor属性的。

寄生组合式--继承

function inheritPrototype (subType,superType) {
  var prototype = Object.creat(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
};

function SuperType (name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
  console.log(this.name);
}
function SubType(name, age) {
  //继承属性
  SuperType.call(this,name);
  this.age = age;
}
//继承方法
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function () {
  console.log(this.age);
}

var instance = new SubType();

通过隐藏那些所谓的prototype操作细节,现在看起来没那么怪异了。但是否真的有所发现:
没有私有环境,所有属性都是公开的。无法访问父类的方法。难以调试

2.原型

在一个纯粹的原型模式中,我们会摈弃类,转而专注对象。基于原型的继承相比基于类的继承在概念上更简单:一个新对象可以继承一个旧对象的属性。你通过构造有用的对象开始,接着可以构造更多和那个对象类似的对象。这就可以完全避免把一个应用拆解成一系列嵌套抽象类的分类过程
在基于原型的系统中,我们创建的对象,看起来要像我们想要的所有这种类型的对象那样,然后告诉javascript引擎,我们想要更多像这样的对象。如果建筑是基于原型的,建筑师会先建一所房子,然后将房子都建成像这种模样的。

方法Object.creat()作为new操作符的替代方案,使用它来创建javascript对象时,能增添一种更像是基于原型的感觉。

function myMammal = {
  name : 'Herb the Mammal',
  get_name : function () {
    return this.name;
  },
  says : function () {
    return this.saying || '';
  }
}

var myCat = Object.create(myMammal);
myCat.name = 'Henrietta';
myCat.saying = 'meow';
myCat.purr = function (n) {
  var i, s = '';
  for (i = 0;i < n; i += 1) {
    if(s) {
      s += '-'
    }
    s += 'r';
  }
  return s;
}

myCat.get_name = function () {
  return this.says + ' ' + this.name + this.says;
}

这是一种"差异化继承"。通过定制一个新的对象,我们指明它与所基于的基本对象的区别。
有时候,它对某些数据结构继承于其他数据结构的情形非常有用。

3.函数化--工厂模式

在伪类模式里,构造器函数Cat不得不重复构造器Mammal已经完成的工作。在函数化模式中那不再需要了,因为构造器Cat将会调用构造器Mammal,让Mammal去做对象创建中的大部分工作,所有Cat只关注自身的差异即可。
函数化模式有很大的灵活性。它相比伪类模式不仅带来的工作更少,还让我们得到更好的封装和信息隐藏,以及访问父类方法的能力。

如果我们用函数化得样式去创建对象,并且该对象的所有方法都不用this或that,那么该对象就是持久性的。一个持久性的对象就是一个简单功能函数的集合。

私有变量:任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量。

闭包

闭包是阻止垃圾回收器将变量从内存中移除的方法,使的在创建变量的执行环境的外面能够访问到该变量。
请记住:闭包由函数创建。每次调用函数会创建一个唯一的执行环境对象。函数执行完后,执行对象就会被丢弃,除非调用者引用了它。当然,如果函数返回的是数字,就不能引用函数的执行环境对象。但是如果函数返回的是一个更复杂的结构,像是函数、对象或者数组,将返回值保存到一个变量上,就创建了一个对执行环境的引用。

Function.prototype.method = function (name,func) {
  this.prototype[name] = func;
  return this; 
}
// 工厂mammal函数
var mammal = function (spec) {
  var that = {};

  that.get_name = function () {
    return spec.name;
  }
  that.says = function (spec) {
    return spec.saying || '';
  } 

  return that;
}

// 工厂cat函数(基于mammal的函数)
var cat = function (spec) {
  spec.saying = spec.saying || 'meow';
  var that = mammal(spec);
  that.purr = function (n) {
    var i, s = '';
    for (i = 0; i < n; i += 1) {
      if(s) {
        s += '-';
      }
      s += 'r';
    }
  }
  that.get_name = function () {
    return that.says() + ' ' + spec.name + ' ' + that.says();
  }
  return that;
}

// 创建myCat对象
var myCat = cat({name: 'Henrietta'});

Object.method('superior',function (name) {
  var that = this,
    method = that[name];
  return function () {
    return method.apply(that, arguments)
  }
})

// 工厂coolcat函数(基于cat函数)
var coolcat = function (spec) {
  var that = cat(spec),
    super_get_name = that.superior('get_name');
  that.get_name = function (n) {
    return 'like ' + super_get_name() + ' baby';
  }
  return that;
}

var myCoolCat = coolcat({name : 'Bix'});

var name = myCoolCat.get_name();

函数化模块模式有很大的灵活性。它相比构造函数模式不仅带来的工作更少,还让我们得到更好的封装休息和隐藏,以及访问父类方法的能力。如果对象的所有状态都是私有的,那么该对象就成为一个"防伪(tamper-proof)"对象。该对象的属性是可以被替换或者删除,当该对象的完整性不会受到损坏。我们用函数式的样式创建一个对象,并且该对象的所有方法都不使用this或者that,那么该对象就是持久性对象。一个持久性对象,就是一个简单的函数功能的集合。
一个持久性的对象不会被入侵。访问一个持久性的对象时,除非有方法授权,否则攻击者不会访问对象的内部状态。

模块模式

前面的模式是用于 自定义类型创建私有变量和特权方法的。而道格拉斯所说的模块模式则是为 单例创建私有变量和特权方法。所谓单例指的就是只有一个实例的对象。(就是用对象字面量表示法创建的对象)

var singleton = function () {
  // 私有变量和函数
  var privateVariable = 10;

  function privateFunction () {
    return false;
  }
  //特权/公有方法和属性
  return {
    publicProvperty: true;

    publicMethod: function () {
      privateVariable++;
      return privateFunction();
    }
  }
}

从本质上讲,这个对象字面量定义的是单例的公共接口。这种模式在需要对单例进行某些初始化,同时又需要维护其私有变量时非常有用。简言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法。

增强的模块模式

这种增强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性和方法对其加以增强的例子。

var singleton = function () {
  // 私有变量和函数
  var privateVariable = 10;

  function privateFunction () {
    return false
  }
  // 创建对象
  var object = new CustomType();

  // 添加特权/公有属性和方法
  object.publicProperty = true;
  object.publicMethod = function () {
    privateVariable++;
    return privateFunction();
  }

  return object;
}()
Javascript 相关文章推荐
javaScript 简单验证代码(用户名,密码,邮箱)
Sep 28 Javascript
Javascript图像处理—为矩阵添加常用方法
Dec 27 Javascript
web开发人员学习jQuery的6大理由及jQuery的优势介绍
Jan 03 Javascript
js QQ客服悬浮效果实现代码
Dec 12 Javascript
jQuery实现信息提示框(带有圆角框与动画)效果
Aug 07 Javascript
使用堆实现Top K算法(JS实现)
Dec 25 Javascript
javascript简单比较日期大小的方法
Jan 05 Javascript
JS创建事件的三种方法(实例代码)
May 12 Javascript
Ajax验证用户名或昵称是否已被注册
Apr 05 Javascript
利用SpringMVC过滤器解决vue跨域请求的问题
Feb 10 Javascript
教你如何用node连接redis的示例代码
Jul 12 Javascript
Postman环境变量全局变量使用方法详解
Aug 13 Javascript
JavaScript正则表达式的分组匹配详解
Feb 13 #Javascript
js HTML5 Ajax实现文件上传进度条功能
Feb 13 #Javascript
js随机生成26个大小写字母
Feb 12 #Javascript
jquery实现具有嵌套功能的选项卡
Feb 12 #Javascript
基于jquery实现动态竖向柱状条特效
Feb 12 #Javascript
原生javascript实现自动更新的时间日期
Feb 12 #Javascript
原生javascript实现图片无缝滚动效果
Feb 12 #Javascript
You might like
PHP采用get获取url汉字出现乱码的解决方法
2014/11/13 PHP
JSON两种结构之对象和数组的理解
2016/07/19 PHP
PHP判断是手机端还是PC端 PHP判断是否是微信浏览器
2017/03/15 PHP
YII2框架中日志的配置与使用方法实例分析
2020/03/18 PHP
JS 常用校验函数
2009/03/26 Javascript
jQuery UI Datepicker length为空或不是对象错误的解决方法
2010/12/19 Javascript
jQuery下实现等待指定元素加载完毕(可改成纯js版)
2013/07/11 Javascript
jquery mobile事件多次绑定示例代码
2013/09/13 Javascript
JS简单实现登陆验证附效果图
2013/11/19 Javascript
解析jQuery的三种bind/One/Live事件绑定使用方法
2013/12/30 Javascript
JS图片自动轮换效果实现思路附截图
2014/04/30 Javascript
jQuery内置的AJAX功能和JSON的使用实例
2014/07/27 Javascript
深入理解javascript原型链和继承
2014/09/23 Javascript
微信小程序 wx.request方法的异步封装实例详解
2017/05/18 Javascript
Angular.js前台传list数组由后台spring MVC接收数组示例代码
2017/07/31 Javascript
深入理解vuex2.0 之 modules
2017/11/20 Javascript
基于滚动条位置判断的简单实例
2017/12/14 Javascript
让网站自动生成章节目录索引的多个js代码
2018/01/07 Javascript
vue.js中created方法作用
2018/03/30 Javascript
浅谈Vue render函数在ElementUi中的应用
2018/09/06 Javascript
node.js爬取中关村的在线电瓶车信息
2018/11/13 Javascript
jQuery实现的点击显示隐藏下拉菜单功能完整示例
2019/05/17 jQuery
原生js实现随机点餐效果
2019/12/10 Javascript
vue请求数据的三种方式
2020/03/04 Javascript
Vue-router中hash模式与history模式的区别详解
2020/12/15 Vue.js
python学习笔记:字典的使用示例详解
2014/06/13 Python
使用apidoc管理RESTful风格Flask项目接口文档方法
2018/02/07 Python
python实现单张图像拼接与批量图片拼接
2020/03/23 Python
django inspectdb 操作已有数据库数据的使用步骤
2021/02/07 Python
Ooni英国官网:披萨烤箱
2020/05/31 全球购物
某/etc/fstab文件中的某行如下: /dev/had5 /mnt/dosdata msdos defaults,usrquota 1 2 请解释其含义
2013/04/11 面试题
学习党的群众路线教育实践活动心得体会
2014/03/01 职场文书
学校标语大全
2014/06/19 职场文书
英语邀请函范文
2015/02/02 职场文书
养成教育工作总结
2015/08/13 职场文书
JavaScript实现队列结构过程
2021/12/06 Javascript