博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript设计模式(一)
阅读量:7098 次
发布时间:2019-06-28

本文共 4913 字,大约阅读时间需要 16 分钟。

声明: 【JavaScript设计模式】 系列 是来自《JavaScript设计模式与开发》这本书的读书笔记,会结合自身的理解和一些项目经验做笔记,原书作者 曾探

前言

什么是设计模式,设计模式就是在某种场合下对某个问题的一种解决方案。说通俗一点就是给一段代码起个名字而已,比如一个用玻璃做的能装水的东西,给它起个名字叫水杯

大家一提到水杯就知道什么对象,具有什么功能,这样大家一想到要喝水就找个水杯这么个东西,满足需求

一、面向对象的JavaScript

1、动态类型语音

JavaScript是一门典型的动态类型语言。记住这一特性很重要,比如js有个数组类型Array,要是一个对象,这个对象具有length属性,还拥有slic,splice方法,那也可以将这个对象当做数组来用。这完全是可以的,因为语言是动态的,我们可以面向接口编程,而不是面向实现编程。

2、多态

也正因为js是动态类型语言,所以js本身具有多态的特性。

什么是多态呢:多态就是同一操作作用于不同对象,产生不同的结果
例子:

function fun(obj) {    obj.log()}function Obj1() {}Obj1.prototype.log = function () {    console.log('....Obj1......')}function Obj2() {}Obj2.prototype.log = function () {    console.log('....Obj2......')}fun(new Obj1()) // ....Obj1......fun(new Obj2()) // ....Obj2......

给函数 fun 传递不同对象,能得到不同的结果

这要是在Java就要设计成子类继承同一个父类,调用的时候向上转型才能调用同一个父类方法得到不同结果,多麻烦呀
JavaScript是一门动态语言,既没有检查创建的对象类型,也没有检查传递的参数类型,所以实现
多态就变得尤为简单,不必诸如向上转型的技术来实现多态

3、封装

JavaScript是没有私有变量和共有变量或共有方法的,但它有个函数作用域,我们可以利用这一特性来满足这一点

例子:

var fun2 = (function () {    var _name = 'my name is 田生'    return {        name: _name,        pubFun: function () {            console.log('.....pubFun.....')        }    }})()console.log(fun2.name)    // my name is 田生console.log(fun2.pubFun()) //.....pubFun.....

4、JavaScript中的原型继承

JavaScript的对象不是通过实例化得到的,而是通过克隆原型对象Object.prototype得到的。

所以经常会预定一个面试题是,js 的 new 操作做了哪些工作?那你可以这样回答,new 操作符是
执行一个构造函数,函数里面克隆了 Object.prototype 对象,并把新对象附上属性值返回出去。
例子:

function Obj() {    this.name = '田生'}var o1 = new Obj()console.log(o1.name) // 田生// 相当于function CloneObj() {    var obj = new Object() // 从 `Object.prototype` 克隆一个新对象    obj.name = '田生'    return obj}var o2 = CloneObj()console.log(o2.name)  // 田生

5、JavaScript中的原型琏

如果对象无法响应某个请求时,它会把这个请求委托给它的构造器的原型prototype去执行

例子:

function Obj() {    this.name = '田生'}var o1 = new Obj()console.log(o1.toString()) // [object Object]console.log(o1)

上面例子克隆了个新的 对象Obj ,新对象没有 toString 方法,所以在调用 toString 方法时,这个请求就会委托给他的原型对象 Objectprototype去执行

那你可能会疑惑,对象 Obj对象 是怎么和 Objectprototype对象挂上钩的呢?
你可以试着在Chrome浏览器的开发者模式中输入上面代码,试着打印 console.log(o1)
会发现 Obj 有个 proto 的属性指向了 Object对象,这就是它们连接的纽带

clipboard.png

二、this、call 和 apply

1、this

当函数作为对象的方法调用时,this 指向改对象

例子:

var Obj = {    name: '田生',    fun: function () {        console.log(this.name)  // this 指向改 对象    }}Obj.fun()  //  田生

当函数不作为对象的属性被调用时,也就是常说的普通方法,此时this指向全局对象

var name = '田生....2'function fun1() {    console.log(this.name) // fun1 当做普通函数,this指向全局    function fun2() {        console.log(this.name)  // fun2 也当做普通函数,this指向全局    }    fun2() // '田生....2'}fun1() // '田生....2'

fun2 函数的this为什么也指向全局呢?有必要再强调一下,当函数不作为对象的属性被调用时,也就是常说的普通方法,此时this指向全局对象!

当然在 ES6 strict 模式下 this为undefined

2、call 和 apply

首先要明确一点,JavaScript 的 Function 实际上是功能完整的对象。那对象就可以调用方法。

所以在看到下面的例子就不要疑惑:

function fun(para) {}fun.lengthfun.apply(null, ['田生'])fun.call(null, '田生')fun.toString()

为什么一个函数有属性呢,为什么一个函数居然可以调用另一个方法呢,因为JavaScript 的 Function 实际上是功能完整的对象啊,对象就有属性和方法啊

(1)、call 和 apply 的区别

没啥区别,就接受参数的方式不一样而已,apply 接受的第二个参数是集合,call接受的参数不固定用逗号隔开。

但可以说 call 是包装在 apply 的语法糖,内部实现也是将参数转数组的形式,所以某种意义上讲
apply的效率高一点。

(2)、call 和 apply 的用途

改变this的指向:

function Obj() {  this.name = 'HI 田生~'  function fun() {      console.log(this.name) // undefined  }  fun()}new Obj()

上面小节也讲了,fun 没绑定到对象上,所以在这里被当做普通函数使用,this指向全局对象,那咱们要

this.name正常输出怎么办:

// 方法一:传统的 _this 传递function Obj() {  this.name = 'HI 田生~'  var _this = this  function fun() {      console.log(_this.name) // HI 田生~  }  fun()}new Obj()// 方法二:借助 apply 或 callfunction Obj() {  this.name = 'HI 田生~'  function fun() {      console.log(this.name) // HI 田生~  }  fun.apply(this)}new Obj()

哪种方法好用我就不多说了

借用其他对象方法

var arr = []Array.prototype.push.apply(arr,[1, 2, 3])console.log(arr)  // [1, 2, 3]

三、闭包和高阶函数

1、闭包

闭包这个概论总是不好理解,你可以简单的理解为 闭包就是能够读取其他函数内部变量的函数

例子:

var func = function () {    var a= 1    return function () {        a++        console.log(a)    }}var fun = func()fun() // 2fun() // 3fun() // 4

变量 a 是函数 func 的局部变量,外部函数或对象无法访问,但 func 内部的匿名函数能访问,那就这个匿名函数就是一个闭包 ,将闭包返回出去,相当于将访问权给了外部环境,外部环境就可以访问一个函数的

局部变量了。

2、闭包的作用

上面第一小点顺带讲了闭包能使外部环境访问局部变量,是作用点之一。闭包还可以延续局部变量的寿命

例子:

// 方式1var report = function (src) {    var img = new Image()    img.src = src}report('http://wwww.tiansheng.logo.png')// 方式2var report = (function () {    var img    return function (src) {        img = new Image()        img.src = src    }})()report('http://wwww.tiansheng.logo.png')

利用方式1有可能图片还没加载完数据就丢失了,因为 report 方法执行完局部变量就销毁了,而方法2

利用闭包的方式延长了变量的寿命

3、高阶函数

高阶函数至少需要满足以下条件之一:

  • 函数可以作为参数传递
  • 函数可以作为返回值输出

我们经常写的带有对调函数就是一个高阶函数

例子:

/** * 高阶函数 * @param name * @param callBack */function fun(name, callBack) {    // do something ...    callBack()}

函数作为返回值输出,其实就是一种闭包的表现

下面一个单例模式的例子:

var getSingle = function (fn) {    var ret;    return function () {        return ret || (ret = fn.apply(this, arguments))    }}var getScript = getSingle(function () {    // ...})var script1 = getScript()var script2 = getScript()console.log(script1 === script2) // true

小结:

本小结写了 【面向对象的JavaScript】、【this、call 和 apply】、 【闭包和高阶函数】 ,为接下去的JavaScript 设计模式做铺垫

转载地址:http://mbeql.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
Mac 键盘快捷键
查看>>
FastDFS海量数据分布式存储方案
查看>>
Nginx实战之--后端节点健康检查
查看>>
redhat 5.3 安装mysql详细步骤
查看>>
Openstack Mitaka for Centos7.2 部署指南(二)
查看>>
服务器上排除问题的头五分钟
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
另一个角度分析共享单车的出路
查看>>
Redhat/CentOS 7下的msSQL安装
查看>>
第54课:Hive集群安装和测试
查看>>
oracle 运行startup报错failure in processing system parameters
查看>>
nginx反向代理配置及优化
查看>>
如何自定义View(转)
查看>>
虚拟化之KVM
查看>>
ExtJS 5正式版
查看>>
android使用系统相机拍照返回照片,并通过webservice上传到服务器上
查看>>
计算机存储数据方式
查看>>
[置顶] Jquery之ShowLoading遮罩组件
查看>>