zoukankan      html  css  js  c++  java
  • [JavaScript]JavaScript中的函数(1)

    关于JavaScript中函数的学习:
    MDN
    阮一峰老师的教程

    关于函数的定义:

    阮一峰老师:函数是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。

    MDN:Function 构造函数 创建一个新的Function对象。 在 JavaScript 中, 每个函数实际上都是一个Function对象。

    函数的声明方式和name

    函数的声明方式有目前来说有5种,每一个函数都有他的一个name属性(包括匿名函数),要注意。

    • 具名函数
    function fn(x,y) {
        console.log(x + y)
    }
    fn.name //"fn"
    
    • 匿名函数
    var fn
    f = function(x,y){
        console.log(x + y)
    }
    f.name //"f"
    
    • 具名函数赋值
    var fn
    fn = function f(x,y) {
        console.log(x + y)
    }
    fn.name //"f"
    f.name	//f is not defined
    
    • window.Function
    var f = new Function('x','y','return x+y')
    f.name // "anonymous"
    
    • 箭头函数
    var fn = (x,y) => {return x + y}
    f.name  //"fn"
    

    现在最常用的就是具名函数和箭头函数。

    函数的调用和call()

    在声明了一个函数之后,我们就可以调用这个函数了。

    但是,我们在调用一个函数的时候,究竟发生了什么,搞清楚其中的机制,可以帮助我们更深入地了解函数。

    现梳理一下我的关于函数调用的思路:

    首先我们声明了一个函数:

    var fn = function(x,y){
        retrun x + y
    }
    

    因为Function也是属于一种对象,所以这个变量就有了一个地址A,这个地址A就指向堆内存中的对象B,对象B中就存放着我们的函数参数与函数体。

    如图所示:

    在这个对象B中的__proto__指向了Function.prototype,在Function.prototype中有一个特殊的call()属性,这个方法对我们“调用函数”的这个动作来说至关重要。

    每次调用函数时,其实就是使用这个call()属性来执行函数体中的内容。

    由于JavaScript这门语言的历史遗留问题,fn.call()才是函数真正的调用方法。

    注意

    fn(1,2)等价于fn.call(undefined,1,2)

    fn(1,2)相当于一种语法糖,但是call()方法能让学习者更好地理解关于函数中的this和arguments概念,所以建议在学习过程中函数调用使用call(),直到掌握this为止。

    函数中的this和arguments

    函数中的 this指的到底是什么?

    先下结论:this指的就是call()中的第一个参数,第一个参数往后都是arguments。

    对此,我的理解是,他指的是一种域,一种范围(可适当理解为函数的作用域),结合call()来看的话就很清晰明了了。

    且看,我们声明了一个函数:

    var fn = function(x,y){
        console.log('x:'+x,'y:'+y)
        console.log(this)
    }
    fn(1,2)
    fn.call(undefined,1,2)
    

    两者的运行结果都是:

    两者的this都是一个window全局对象,我们来转变一下:

    var a = 3
    var obj = {
        a: 4
    }
    var fn = function(x,y){
        console.log('x:'+x,'y:'+y)
        console.log(this.a)
    }
    fn(1,2)
    fn.call(obj,1,2)
    

    运行结果如下:

    我们可以看到,因为我们在代码前面声明了一个赋值为3的全局对象a,第一个fn的调用中的this没有改变,依然是window全局对象,所以函数fn中的this.a找的是全局作用域中的a,也就是打印出了3。

    我们还在代码前面声明了一个对象,其中包含了一个key a,key的值为 4,第二个fn调用的时候,我们把对象obj当成参数传给了fn,这个对象 obj就变成了fn的 this!!所以代码运行时,函数fn中的this.a找的就是对象obj中的a。

    因为正常的函数调用fn()简化了传入this的一步,而fn.call()则需要把this作为参数传入,所以使用call()来学习this 是有好处的。

    注意

    普通模式与严格模式

    在普通模式和严格模式下,this表现会有所不同:

    // 严格模式
    var fn = function(x,y){
        'use strict'
        console.log('x:'+x,'y:'+y)
        console.log(this)
    }
    fn.call(undefined,1,2)
    fn.call(1,1,2)
    

    // 普通模式
    var fn = function(x,y){
        console.log('x:'+x,'y:'+y)
        console.log(this)
    }
    fn.call(undefined,1,2)
    fn.call(1,1,2)
    

    在普通模式下,如果this是undefined,浏览器会自动把this变成Window;如果是其他的值,则会打出一个对象(比如说1,则会打出一个Number 1的对象);

    严格模式下,如果this是undefined,他就是undefined,如果是其他的值,则会打出这个值本身。

    arguments

    arguments指的就是函数的参数。

    使用arguments可以打出一个伪数组,伪数组就是像数组,但是__proto__中没有Array.prototype的对象。

    // 普通模式
    var fn = function(x,y){
        console.log('x:'+x,'y:'+y)
        console.log(arguments)
    }
    fn.call(undefined,1,2)
    

    下一篇博文会接着总结一下函数中的作用域和闭包。

  • 相关阅读:
    XML基础介绍【二】
    XML基础介绍【一】
    Java面向对象(三) 【面向对象深入:抽象类,接口,内部类等】
    Java面向对象(二)
    Java面向对象(一)
    main特别之处
    c语言线性表
    c语言三元组
    线性表(顺序表的创建)
    创建一个三元组
  • 原文地址:https://www.cnblogs.com/No-harm/p/9539406.html
Copyright © 2011-2022 走看看