js函数:闭包难点+this的理解

1.函数的定义

1.语法

  function functionName(parameters) {
      执行的代码
    }

2.可以通过通过一个表达式定义,函数表达式可以存储在变量中

var x = function (a, b) {return a * b};
var z = x(4, 3);  //这种函数实际上是一个匿名函数

3.函数的提升

myFunction(5);    //先调用

function myFunction(y) {      //后定义
    return y * y;
}

4.自调用函数:如果表达式后面紧跟 () ,则会自动调用。

(function () {
    var x = "Hello!!";      // 我将调用自己
})();

5.函数可作为一个值、一个表达式使用

function myFunction(a, b) {
    return a * b;
}

var x = myFunction(4, 3);
var x = myFunction(4, 3) * 2;

6.函数的数据类型typeof是一个对象,有属性和方法。

2.参数

1.显式参数
函数显式参数在函数定义时列出,定义显式参数时没有指定数据类型。
2.隐式参数
函数隐式参数在函数调用时传递给函数真正的值。

我认为就是形参与实参

3.arguments 对象

  1. 在函数代码中,使用特殊对象 arguments[],开发者无需明确指出参数名,就能访问它们。 举例: 用arguments[0]可以访问第一个参数的值,相当于数组
  2. 引用属性 arguments.length,可以检测函数的参数个数
  3. 模拟函数重载
function doAdd() {
  if(arguments.length == 1) {
    alert(arguments[0] + 5);
  } else if(arguments.length == 2) {
    alert(arguments[0] + arguments[1]);
  }
}

doAdd(10);	//输出 "15"
doAdd(40, 20);	//输出 "60"

3.调用,关于this

JavaScript 函数有 4 种调用方式,每种方式的不同在于 this 的初始化,this指向函数执行时的当前对象。

  1. 作为函数调用:myFunction() 和 window.myFunction() 是一样的,this指向全局对象,web中的全局对象是浏览器窗口windows。
  2. 作为方法调用:this指向的对象是myObject
var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this.firstName + " " + this.lastName;
    }
}
myObject.fullName();         // 返回 "John Doe
var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this;
    }
}
myObject.fullName();          // 返回 [object Object] (所有者对象)
//函数作为对象方法调用,会使得 this 的值成为对象本身

[object Object] 自定义的对象
第一个object代表用户自定义的对象的属性,
第二个Object代表用户自定义的对象的方法。

3.使用构造函数调用函数
如果函数调用前使用了 new 关键字, 则是调用了构造函数。这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象

// 构造函数:
function myFunction(arg1, arg2) {
    this.firstName = arg1;
    this.lastName  = arg2;
}

   // This    creates a new object
    var x = new myFunction("John","Doe");
    x.firstName;                             // 返回 "John"
    //构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法。

构造函数中 this 关键字没有任何的值。this 的值在函数调用实例化对象(new object)时创建。this指向新的对象。

4.作为函数方法调用函数
JavaScript 函数是对象,有方法和属性。方法有call() 和 apply()

  • apply()方法 :接收两个参数,第一个是函数运行的作用域(this),另一个是参数数组。
    语法:apply([thisObj [,argArray] ]);
  • call()方法 :第一个参数和apply()方法的一样,第一个时作用域this,但是传递给函数的参数必须列举出来。
    语法:call([thisObject[,arg1 [,arg2 [,...,argn]]]]);
    举例:
 function myFunction(a, b) {
    return a * b;
}
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray);  // 返回 20

5. 因为嵌套的原因,嵌套函数里的this指向windows

总结:
1、 谁调用了此函数, 那么this 就指向谁
2、如果遇到函数里面又包了一层函数,那么 this的指向就变成全局的了
3、 如果遇到new 那么指向就是 新创建的实例对象
4、如果遇到call 或apply,那么 this 指向就是 call或apply 里面的第一个参数

4.闭包

1.作用域:函数内部可以直接读取全局变量,在函数外部自然无法读取函数内的局部变量。函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量!
2.如何从外部读取局部变量?
方法:在函数的内部,再定义一个函数。

function f1(){
    var n=999;
    function f2(){
      alert(n); // 999
    }
  }

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。
3.闭包:
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!f1中一定要定义局部变量啊!

function f1(){

    var n=999;

    function f2(){
      alert(n); 
    }

    return f2;

  }

  var result=f1();
  result(); // 999

闭包就是能够读取其他函数内部变量的函数。

4.闭包的作用
一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。所以闭包很占内存!

function f1(){

    var n=999;                     //f1要用var定义,才是局部变量!

    nAdd=function(){n+=1}       //注意:nAdd是一个全局变量

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();                        //result实际就是闭包f2函数

  result(); // 999

  nAdd();      //nAdd的值是一个匿名函数),而这个匿名函数本身也是一个闭包

  result(); // 1000

第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

5.闭包与this
代码一:

var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()());

返回值是The Window,外面的函数指向object,当函数里套一个函数,此时this发生了变化, 指向了全局 window

代码二闭包:

var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()());

返回值是My Object。
作为方法调用,哪个对象调用this就指向哪个对象。
这是一个闭包。

猜你喜欢

转载自blog.csdn.net/weixin_43187545/article/details/83478312
今日推荐