美文网首页
JS函数重新学习

JS函数重新学习

作者: 流着万条永远的河 | 来源:发表于2017-11-04 13:28 被阅读0次

函数又叫方法。
学了一段时间JS了,首先,我要如何看待函数?
自己要建立什么观念呢?其实刚开始我本人的做事方法是一口吃个胖子,能一下写一秃噜代码,就一下写到自己所想的再前一步,当然在后面开发项目的时候,代码一写一长溜,后来就觉得不好看,代码太难看了,还有就是函数的复用了。
为什么要用函数?为什么?我经常看老师写代码,明明可以接着写下去的,结果呢,他直接把剩下的思路造了一个函数出来,他就说他喜欢这样,方便。单单方便一个词,这种思维就是一种把步骤封装起来,模块化的感觉,虽然刚开始我是觉得多此一举的,事实上,这是一种做事习惯,态度。事实证明,这样的习惯确实很好,代码漂亮了,其实思路更清晰了,这是关键。所以,我也要如此,有种写代码就要时刻准备着函数的品质的。
对函数本身应该如何看待呢?它是一段命令,构成里面有参数。第一点,就是参数的研究,逻辑上涉及到了传参,赋值,作用域,声明前置但赋值不前置,作用域链,甚至是原型与原型链的那个this。第二点,这个函数要执行的话,在时机上是不是同步的,后续的代码执行要不要必须在它完成之后再执行?比如定时器,node.js的读写文件,上次写无限轮播时的animate的用法,事件处理,还有ajax发请求要数据,数据到了做什么,常识就是回调函数,当然多了就成回调地狱了,后续会有更多的写法,如Promise。

函数的声明,调用

function  functionName(){}   //声明
functionName()     //调用,代码复用
var  a = new sum()     //构造函数,原型对象那里的知识的声明
var a = function(){}    //函数表达式,跟声明是有区别的

函数的参数

调用的时候,会传递进去参数的,所有函数内部都有个arguments对象,类数组对象,arguments[0],就是第一个参数。

function name(a){
  console.log(a)
}
等同于
function name(){
  var a = arguments[0]
  console.log(a)
}

参数传多了,多的就是undefined,少了就是默认的从左到右传进去。
强制限制参数数量:

function(x,y){
  if(arguments.length !==2){...}
}

设置默认参数,其实在上次写Jquary插件的时候,就用到了,那个动画效果中的

function(x,y){
x = x || 0
y = y || 1
return [x,y]
}

把这个arguments转化为数组,方法:

function toArr(arguments){
  return [].slice.call(arguments)      //原型的this的知识
}

没有重载

没有重载,一个函数就是一个函数,再写一遍就覆盖了,如何传递不同参数?
只能在函数内部用if判断参数是哪一个参数,再相应地做事。

函数返回值

跟console.log()区别开,console.log()也是一个函数,这个函数值是undifined。只是把结果展示给控制台。
如果写一个函数没有return,这个函数值就是undifined。
return 会终止这个函数运行,我在项目里加锁经常用的。

声明前置

废话不多说,声明的变量,函数,都会提前,提前到哪里?到它所在的块级元素的最前面,全局作用域下,比较好说,提前到最前面。如果是函数内,就是在整个函数内的最前面。
这里跟后面要学的封装呼应了,想来十几天前刚学封装的时候,经常出错,就是因为在封装的对象里,声明的变量落后于执行它的函数,因为它们不在一个范畴了哦。因为一个this惹的祸。
然后,我要说的点是,只是声明前置,赋值依旧在运行到它所在的那行代码的时候,值才成立的。

console,log(a)   //undifined  而不是报错,也不是3
var a = 3
function foo(){
console.log(tmp)     //undifined    变量已声明前置  
var x > -3
if(x < 0){               //if之流都是语句,不是函数。这个语句有个块内部环境,
                      //但是函数内变量作用域是整个函数。
var tmp = -x
}
console.log(tmp)     //3
}

fn()                             //报错了
var fn = function(){
console.log('fn,,,')
}
等同于
var fn
fn()      //fn不是一个函数
fn=function(){
console.log('fn,,,')
}

命名冲突

原理就是声明前置🏠后面的声明赋值覆盖。

var fn = 3
function fn(){}
console.log(fn)   //3
等同于
var fn
function fn(){}
fn = 3
console.loog(fn)


function fn(fn){
  console.log(fn)     //相当于前面有个 var fn = arguments[0] = 10
var fn = 3
console.log(fn)
}
fn (10)  // 10   3

递归

自己调用自己,
比如阶乘。
效率很低,思路简单,逻辑清晰。

function fact(n){
  if(n ===1){
return  1
}
return  n*fact(n-1)
}

作用域与上下文

首先,作用域的研究对象是函数里的变量有意义的地方,那一块叫作用域。而上下文的研究对象是调用当前代码的对象的引用,也就是那个恶心的this。一个是变量作为研究时出现的,一个是这行代码对应的对象this作为研究时出现的。十几天前第一次讲原型对象时,我错误地认为作用域就是this,但是作用域还有作用域链,又感觉怪怪的,而且没有this的属性方法。

作用域

一提它,就想变量。
全局的,就是声明在全局,局部的就是声明在函数体内。
全局变量一直存在,随时调用,修改。
局部的变量只在局部有作用,跟局部外一点关系都木有,也不会影响到外部的其他代码,也不会被外部所知道。每次的存在意义就是在调用函数时才有,而且每次都有不同的作用域,期间只能在作用域内赋值,求值,对值,不能访问作用域外的值。
JS里{}没有带来块级作用域。但ES6里有let,所以函数里是会有的。
if,for循环之类的语句等,定义的变量都是全局的,外边可以访问,这就是块级作用域在JS中无效,有效的话,就不能被语句外访问到定义的变量了。在函数里的话就是函数的全局变量了。


立刻执行的函数表达式

这是模拟块级作用域的实例,也是闭包的应用。
JS 中,一个函数定义的变量,函数执行后,变量会被销毁的,这样,后续再访问其中的变量就访问不到了。

(function(){})()     //对,括号部分相当于变量了,阻止被解析成声明
function(){}()    //错
var a =function(){}
a()   //对

this上下文

上下文,就是一个函数被new出来时候,或者函数是一个对象的属性或者方法的形式时,反正就不是函数表达式,也不是字面量形式,哎,这时候this就出现了。就是有对象这种类型参与时,上下文就出来了。this是什么东东?
this是调用这个函数时,这个函数所属的对象。

var obj = {
  haha:function(){
    console.log(this === obj)
  }
}
obj.haha()      //true

全局变量都是window这个对象的属性。

作用域链

JS是单线程语言,在浏览器同时,只能做一件事。初始,默认作用域是全局window。执行函数,先创建它的作用域,是把函数作用域拉到作用域链的顶部,执行。执行完了,就移除,回到以前的作用域,以前的作用域可以是它父亲的作用域,更外边最外边就是全局。

每执行一个函数,就出在一个新作用域下。

作用域链的根本就是,从自己内部找变量,找不到就攀爬作用域链,从自己函数所声明的作用域找,找不到,从自己函数所在作用域代表的函数的作用域找,,,一层一层翻。还有一个注意点,声明前置。
练一练:

var a =1
function fn1(){
  function fn2(){
    console.log(a)       //找a,内部没有,从自己函数声明的那个作用域找
  }
  function fn3(){
    var a = 4
    fn2()
  }                 //找fn2
  var a = 2             //找到了,自身作用域有,没有找fn3里的。
  return fn3
}
var fn = fn1()    //找fn3
fn()   //2



var  a= 1
function fn1(){
  function fn3(){
    var a = 4
    fn2()
   }
  var a =2
  return fn3
}
 function fn2(){
    console.log(a)
  }
var fn = fn1()
fn()   //1  一个意思。fn2的作用域是全局。

这里调用一个函数fn,fn是全局变量,不会被删除,fn函数返回一个函数fn3,就生成一个闭包,保存了返回函数fn3的临时的变量。

闭包重新认知

当一个嵌套函数,在作用域外或者定义外被访问,让它可以在外部函数返回后被执行,就是闭包了。作用就是保存局部变量。

function ha(){
  var a =1
  return function say(){
    return a
  }
}

var haha = ha()
console.log(haha())   //1

保存变量对比:



这里让我想起了上次那个音乐主页做的封装的一个点了,因为要把这个主页分成两部分封装,但是两部分之间有个交互,需要从一个封装对象里传入另一个对象一些参数,并且保存。那里,直接在另一个封装对象里添加了一个属性,让这个属性的值等于参数,就保留了。不一样的想法了,,,

var man = (function (){
  var a =1
  function isman(x){
    a += x
  }
  function iswoman(x){
    a -= x
  }
  return{
    sex:'',
    sexmesold:function(x){
      //do something
    },
    sexget:function(x){
      isman(x)
    }
  }
})()        //立刻执行的变种可以理解为把var obj =man(),obj(),直接一步达到,也不引入新变量obj了。
//私有属性和方法,变量,都在它整个生命周期保留着,通过man.sexget与外部交互,这个sexget自己需求随意创建的,符合你的预期就行。
保护man的全局命名空间,很有用,暴露的接口就是那个回调函数了。

call和apply

所有函数都有这两个方法,只是参数不同。
call函数需要传递参数列表,apply函数允许你传递参数为数组:

function  ha(a,b,'c'){}
ha.call(window,a,b,'c')
ha.apply(window,[a,b,'c'])
//ha函数在window的作用域下执行,并提供了三个参数。为了复用函数,脱离它定义的作用域。只保留方法。

function ha(){
   
          console.log(this.name)

}
function me(){
  this.name = 'me'
ha.call(me)
}
me()  //'me'

function sum(){
}


还有一个bind,还是在原型那部分再写吧。
参考了大神的认识javascript中的作用域和上下文

相关文章

  • JS函数重新学习

    函数又叫方法。学了一段时间JS了,首先,我要如何看待函数?自己要建立什么观念呢?其实刚开始我本人的做事方法是一口吃...

  • JavaScript 05 函数

    js函数的概念和作用,js函数的定义,js函数的调用,js事件驱动的概念,js函数的实参和形参,js的作用域,js...

  • js 深入

    * js语法* js的动态函数和匿名函数* js动态函数Functionnew Function();* 匿名函数...

  • 2018-12-01

    js中括号操作属性 js函数 js换肤 变量和函数预解析 匿名函数 函数传参 函数return关键字 流程控制语句...

  • jQuery入口函数的作用以及jQuery入口函数和js入口函数

    jQuery的入口函数 js和JQuery入口函数的区别 JS入口函数和JQuery入口函数

  • 微信小程序本地和云函数方式获取云存储数据

    本地方式 js代码 云函数方式 js代码 云函数代码

  • JS操作属性、函数

    JS操作style属性 JS操作class属性 函数 匿名函数 函数传参 作业 if练习 switch练习

  • android h5 js 匿名函数通信

    android js 互相调用 支持js匿名函数接收 支持js json对象接收 支持js函数返回值获取 通过注解...

  • 前端面试题(持续补充)

    js,node.js基础: 闭包 闭包是能够读取其他函数内部变量的函数。在js中,只有函数内部的子函数可以访问内部...

  • jquery

    1、jQuery入口函数与Js入口函数的区别【注】js入口函数指的是:window.onload = functi...

网友评论

      本文标题:JS函数重新学习

      本文链接:https://www.haomeiwen.com/subject/uiwtmxtx.html