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 相关文章推荐
js获得鼠标的坐标值的方法
Mar 13 Javascript
javascript制作sql转换为stringBuffer的小工具
Apr 03 Javascript
JS基于FileSystemObject创建一个指定路径的TXT文本文件
Aug 05 Javascript
js实现Select列表各项上移和下移的方法
Aug 14 Javascript
js窗口关闭提示信息(兼容IE和firefox)
Oct 23 Javascript
JS获取鼠标选中的文字
Aug 10 Javascript
简单三步实现报表页面集成天气
Dec 15 Javascript
vue-cli构建项目使用 less的方法
Oct 04 Javascript
使用axios实现上传图片进度条功能
Dec 21 Javascript
vue用递归组件写树形控件的实例代码
Jul 19 Javascript
JS隐藏号码中间4位代码实例
Apr 09 Javascript
vue+eslint+vscode配置教程
Aug 09 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
PHP5 面向对象程序设计
2008/02/13 PHP
Mysql中limit的用法方法详解与注意事项
2008/04/19 PHP
Smarty foreach控制循环次数的实现详解
2013/07/03 PHP
php中json_encode处理gbk与gb2312中文乱码问题的解决方法
2014/07/10 PHP
php+ajax+json 详解及实例代码
2016/12/12 PHP
thinkphp整合系列之极验滑动验证码geetest功能
2019/06/18 PHP
JS获取scrollHeight问题想到的标准问题
2007/05/27 Javascript
jquery的flexigrid无法显示数据提示获取到数据
2013/07/19 Javascript
使用ajaxfileupload.js实现ajax上传文件php版
2014/06/26 Javascript
node.js使用npm 安装插件时提示install Error: ENOENT报错的解决方法
2014/11/20 Javascript
JQuery.get提交页面不跳转的解决方法
2015/01/13 Javascript
使用jQuery获取data-的自定义属性
2015/11/10 Javascript
js鼠标点击图片切换效果实现代码
2015/11/19 Javascript
深入理解JQuery中的事件与动画
2016/05/18 Javascript
jQuery实现按钮点击遮罩加载及处理完后恢复的效果
2016/06/07 Javascript
批量下载对路网图片并生成html的实现方法
2016/06/07 Javascript
jquery实现网站列表切换效果的2种方法
2016/08/12 Javascript
新手学习前端之js模仿淘宝主页网站
2016/10/31 Javascript
d3.js实现图形拖拽
2019/12/19 Javascript
JavaScript实现电灯开关小案例
2020/03/30 Javascript
微信小程序wx.getUserInfo授权获取用户信息(头像、昵称)的实现
2020/08/19 Javascript
Python3.x版本中新的字符串格式化方法
2015/04/24 Python
Java编程迭代地删除文件夹及其下的所有文件实例
2018/02/10 Python
pandas获取groupby分组里最大值所在的行方法
2018/04/20 Python
python实现音乐下载的统计
2018/06/20 Python
python同时遍历数组的索引和值的实例
2018/11/15 Python
Python线程之定位与销毁的实现
2019/02/17 Python
Django框架HttpResponse对象用法实例分析
2019/11/01 Python
详解Anconda环境下载python包的教程(图形界面+命令行+pycharm安装)
2019/11/11 Python
python实现三种随机请求头方式
2021/01/05 Python
video实现有声音自动播放的实现方法
2020/05/20 HTML / CSS
英国打印机墨盒销售网站:Ink Factory
2019/10/07 全球购物
结婚老公保证书
2015/02/26 职场文书
详解Mysql 函数调用优化
2021/04/07 MySQL
用Python实现屏幕截图详解
2022/01/22 Python
Python利用capstone实现反汇编
2022/04/06 Python