javascript中的递归、闭包、原型与继承

javascript中的递归、闭包、原型与继承

来自网络

2018-09-28 08:39 阅读 49 喜欢 3 javascript的原型链 js的递归、闭包

本文主要讲解、理清一些函数常用的知识点:递归、闭包是什么、闭包使用场景、什么是原型和原型链、如何实现继承、继承的原理。

递归

函数的递归就是在函数中调用自身

举一个实例,著名斐波那契数列如何求得,问题是这样的:

  1. 第一个月初有一对刚诞生的兔子
  2. 第二个月之后(第三个月初)它们可以生育
  3. 每月每对可生育的兔子会诞生下一对新兔子
  4. 兔子永不死去

定义出来的数列是

我们需要求得 n 月有多少对兔子,通过递归算法可以求得

function fn(n) {
  return n < 2 ? 1 : fn(n - 1) + fn(n - 2)
}
var count = fn(30);
console.log(count);

闭包

什么是闭包?闭包就是函数,它可以继承并访问自身所被声明的函数作用域内的变量。

function fn1 () {
  var a = 'hello'
  function fn2 () {
    console.log(a)
  }
}
fn1() // 其中 fn2 就是闭包函数

闭包的使用场景

闭包有很多使用场景,以下举例:

1. 私有变量
function Person(){    
  var name = "default";       
  return {    
    getName : function(){    
      return name;    
    },    
      setName : function(newName){    
      name = newName;    
    }    
  }    
};
var person = Person()
console.log(person.getName()) // default
person.setName('xiaomuchen')
console.log(person.getName()) // xiaomuchen
var person2 = Person()
console.log(person2.getName()) // default

上述函数,使用闭包创建私有变量 name,变量不可被外部直接操作、获取,只能通过返回的接口控制。

2. 匿名自执行函数

比如在开发页面时,需要在页面初始化时,你需要立即做一些操作,那么可以在页面中使用匿名自执行函数,它会在 JS 引擎读取到这部分代码时就立即执行。

// 在 title 上添加页面打开时间
(function(){
  var openTime = new Date()
  document.title = document.title + openTime
})();  

原型、原型链、继承

先问一个问题:__proto__ 和 prototype 会出现在什么地方?它们之间是什么关系?实现继承依赖什么?

__proto__ 和 prototype 的区别

1.JavaScript 中每一个对象都拥有原型链(__proto__)指向其构造函数的原型(prototype)

var a = {}
a.__proto__ === Object.prototype // true

function Person () {}
Person.__proto__ === Function.prototype // true

var p = new Person()
p.__proto__ === Person.prototype // true

2.JavaScript 中每一个函数都拥有原型(prototype),原型也是一个对象,这个对象包括:原型链、原型方法(属性)、函数构造,同理它的原型链指向其构造函数的原型

function Person () {}
Person.prototype.getName = function () {}
Object.getOwnPropertyNames(Person.prototype) // ["constructor", "getName"]
Person.prototype.__proto__ === Object.prototype // true

3.当访问一个函数上的属性时,先尝试访问自身上的属性,再尝试访问其原型上的属性。当访问一个对象上的属性时,先尝试访问自身上的属性,再通过原型链尝试访问其构造函数原型上的属性。如果没有则通过原型上的原型链,继续向上查找,直到访问 Object.prototype 上的属性,如果还是没有,因为 Object.prototype 是一个没有 __proto__ 的对象,则查询到此为止,返回 undefined。

function Person () {}
Person.getName = function () {
  console.log('Person1')
}
Person.prototype.getName = function () {
  console.log('Person2')
}
var p = new Person()

Person.getName() // Person1
p.getName() // Person2
console.log(typeof p.getClass) // undefined
继承

JavaScript 函数通过原型和原型链实现继承

function superA (name) {
  this.name = name
}
superA.prototype.getName = function () {
  console.log(this.name)
}
function subA (name) {
  superA.call(this, name) // 继承属性
}
subA.prototype = new superA() // 继承方法

var a1 = new subA('xiaomuchen')
a1.getName() // xiaomuchen

上述代码,描述了一个函数的经典继承,其工作原理是这样的:

  1. 声明父类 superA、子类 subA
  2. 重写子类 subA 的原型,指向 superA 的实例
  3. 当实例化 a1 时,a1.__proto__ => subA.prototype => new superA() => superA.prototype,所以 a1 的构造函数是 superA
  4. 同时,运行 subA 也就是 superA.call(this, 'xiaomuchen'),其中 this 指向 a1 所以 a1 继承了 name 属性
  5. 这样子类 subA 的实例 a1 就继承了 superA 的原型方法和属性

总结

本文概括了递归、闭包、原型、继承,理清这些基本的概念,有助于你接纳更多的东西,我们会在下一个章节对函数进行更深入的讨论。


作者:肖沐宸,github


如果对你有用的话,请赏给作者一个馒头吧 ...或帮点下页面底部的广告,感谢!!

赞赏支持
提交评论
评论信息(请文明评论)
暂无评论,快来快来写想法...
推荐
现象:在IOS中,jsp页面绑定的点击事件,点击后延迟很大,接近1000ms,反应很慢
关于web打印,需要对页面内容进行页面样式设置,呈现出分页的样子,同时对于题目中的图片或表格尽量不分到两个页面中,因此实现了一个jquery的web打印插件,当然,这个插件目前只适用于部分情况,仅供借鉴
如何通过js调用本地摄像头呢?获取后如何对视频进行截图呢?在这里跟大家做一个简易的Demo来实现以上几个功能。
最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也有同样的记号。求最大公约数有多种方法,常见的有质因数分解法、短除法、辗转相除法、更相减损法。与最大公约数相对应的概念是最小公倍数,a,b的最小公倍数记为[a,b]。
今天刷codewars的题目的时候碰到一个通过js来实现字符串转base64的题目,base64虽然在js或nodejs中经常用,但是我还真没有仔细去看过原理以及如何实现,这回绕不过去了,赶紧找了找资料看了下。
java 对象中有很多引用,甚至会出现循环引用,比如 user 对象中有 school 对象,school 对象中又有 user 对象,这样在对 user 对象序列化的时候,就会出现死循环,导致内存溢出。通过一定的方式,将每个对象增加ID 和 REF 引用标识最终可以解决这个问题
this 是 JavaScript 的一大难点,多年经验的前端程序员都可能对这方面模糊。this 在大量的函数、类库中都有使用,理清显式绑定和隐式绑定有助于理解或书写这类函数。
web开发中,前台有时候会需要一个随机数或序列,通常来说,这个随机数可能只在当前页面中使用,并不需要太过严格,大体上重复率低即可。