前言

Function类型

前言

我在上一篇【javascript基础】基本概念中介绍了javascript的一些基本概念,多谢大家的阅读和意见,自己写的东西可以被大家阅读,真心高兴,刚开始发布的时候我一直盯着阅读人数,虽然知道大家可能就是点开一下而已,但是还是给我一些继续写下去的信心。那今天写一些关于javascript函数的一些知识,帮助大家熟悉或者复习一些函数的基本知识。

PS:最近jQuery源码交流群( 239147101)加了不少热新人,希望大家还是以学习为主,尽量少灌水,给大家一个好的提升自己的环境。

第一种方式:可以在函数定义之前调用也可以在函数定义之后调用:

简单来说,回调函数:也就是将要执行的函数。

 

由于函数是对象,因此函数名实际上是一个指向函数对象的指针,不会与函数绑定

函数

函数在任何一种编程语言中都是一个很重要的结构或者组成部分,编程中的复杂结构和功能都会有函数的参与。javascript中的函数是一个对象,函数对象时Function类型的实例,由于Function类型是一个引用类型,那么函数可以拥有自己的方法和属性,同时也因为函数是一个对象,那么函数名是一个指向函数对象的指针,可以被赋值。下面详细介绍函数的各个部分。

(0)函数的调用

回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。

我在上一篇【javascript基础】基本概念中介绍了javascript的一些基本概念,多谢大家的阅读和意见,自己写的东西可以被大家阅读,真心高兴,刚开始发布的时候我一直盯着阅读人数,虽然知道大家可能就是点开一下而已,但是还是给我一些继续写下去的信心。那今天写一些关于javascript函数的一些知识,帮助大家熟悉或者复习一些函数的基本知识。

所以没有重载这个概念!!!!!!!!!!!!!!!!!!!!!!!!!!

创建函数

函数的创建有三种方式,分别为使用Function的构造函数、函数声明、函数表达式,下面分别介绍这三种方法。

add(1,2) //可以调用

(1)回调函数的定义

 

function sum1(){}
var sum2 = function(){}; 
 //!!!!分号!!!!将变量sum2定义成function类型

Function构造函数

这种方式是直接new出来一个Function
实例,通过使用Function的构造函数进行创建函数。Function构造函数可以接收任意多个参数,但是最后一个参数会被认为是函数体,前面的所以参数被当做被创建出来的函数的参数。

var test = new Function("a","b","return a + b");//参数a和b,函数体return a + b
console.log(test(1,2));//3

我们可以看出比较的麻烦,并且《javascript高级程序设计》也不推荐我们使用这种方式,主要是因为浏览器要解析常规的javascript代码之外,还要解析传入的参数字符串,这个类似eval()的解释,影响性能。

 

function add(x,y,fn) {
        /*
        * this.x  this.y:属于add类的全局变量的定义
        * */
        this.x=x||1;
        this.y=y||1;

        if(fn){     /*判断是否有回调函数,有的话执行传入的函数(传入参数)*/
            fn(this.x+this.y);
        }
    }

PS:最近jQuery源码交流群(
239147101)加了不少热新人,希望大家还是以学习为主,尽量少灌水,给大家一个好的提升自己的环境。

 

函数表达式

这种方式是创建的常见方式之一,具体请看

var test = function(a,b){
  return a + b;  
}
console.log(test(1,2));

上面的代码就是创建一个函数,使用test()进行调用。其实,上面的代码是先创建了一个匿名的函数,之后把这个匿名的函数赋值给test变量。每个函数有一个name属性,这个属性不是ECMA标准的一部分,但是许多地方可以使用它。我们可以给上面的函数起一个名字,具体下面代码

//函数的名字newName
var test = function newName(a,b){
  return a + b;  
}
console.log(test.name);//newName

//匿名函数
var nTest = function (a,b){
  return a + b;  
}
console.log(nTest.name);//""

这个属性在后面详细解释吧。

(1)函数的定义:

(2)回调函数的调用,一般为匿名函数,此时将匿名函数作为参数传递到函数中,在另一个函数中调用该匿名函数(加传递参数)

 

ECMAScript中的参数

函数声明

这种方式和C语言中的很类似,这种是最常见的一种创建函数的方法。是通过关键字function直接声明,请看

function test(a,b){
  return a + b;  
}
console.log(test(1,2));//3
console.log(test.name);//test
function add(x,y) {
       console.log(x+y) ;
    }
  add(1,2,function (v) {//回调函数有返回值
        if(v>0){
            alert("result>0")
        }else{
            alert("result<0")
        }
    })

函数

参数在内部用arguments对象数组来访问,只关心参数数组,不关心参数个数

区别

以上介绍了三个创建函数的方式,现在介绍三种的区别,确切的说是后两种的区别,因为Function不推荐使用,性能是一大原因。区别就是使用函数声明这种方式会使函数的声明提前,类似前面我们提到的变量申明的提前。也就是说,使用函数申明方式,我们可以将函数的声明放在调用函数代码的后面,因为解析器会在代码执行之前将函数的声明提升,提到源代码树的顶部,而函数表达式方式则会报错,具体请看

//调用函数
console.log(test(1,2));//3
//创建函数(函数申明方式)
function test(a,b){
  return a + b;  
}
//上面的函数相等于
//创建函数(函数申明方式)
//function test(a,b){
//  return a + b;  
//}
//console.log(test(1,2));//3

//调用函数
console.log(ntest(1,2));//TypeError: undefined is not a function
//创建函数(函数表达式方式)
var ntest = function (a,b){
  return a + b;  
}

(2)函数的调用

 

 

function doAdd(){
    if(arguments.length == 1){
          alert(arguments[0]+10);
    }else if(arguments.length == 2){
          alert(arguments[0]+arguments[1]);
    }
}

doAdd(10);         //20
doAdd(30,20);    //50

not重载

javascript语言不像java那些语言有函数重载这一概念,其实函数名就是一个指针,指向一个Function实例的地址,当然只能指向一个函数,当然没有重载的概念了,只有覆盖,后面定义的函数覆盖前面定义的函数,具体请看

function test(a,b){
  return a + b;  
}
//下面的函数覆盖上面的
function test(a,b){
  return a + b + 100;  
}

console.log(test(0,0));//100

也就是说如果一个同名的函数表达式和函数申明的函数在一起,无论位置是怎么样的,最后的函数就会是用函数表达式创建的函数,因为函数申明会提升到顶部嘛,看看下面的代码

var test = function (a,b){
  return a + b -100;
}

function test(a,b){//会被下面的函数覆盖
  return a + b;  
}

function test(a,b){//会被函数表达式覆盖
  return a + b + 100;  
}

console.log(test(0,0));//-100
add(1,2)//可以调用

总结:回调函数会自动返回值,在调用时会将匿名函数作为参数传入,作为接受函数的形式参数,此时相当于变成了可以代表匿名函数执行一切权利的代理者,执行后会用返回值。

函数在任何一种编程语言中都是一个很重要的结构或者组成部分,编程中的复杂结构和功能都会有函数的参与。javascript中的函数是一个对象,函数对象时Function类型的实例,由于Function类型是一个引用类型,那么函数可以拥有自己的方法和属性,同时也因为函数是一个对象,那么函数名是一个指向函数对象的指针,可以被赋值。下面详细介绍函数的各个部分。

arguments的值永远与对应命名参数的值保持同步

内部属性

函数的内部有两个重要的对象:arguments和this。

 

 

 

function doAdd(num1,num2){
     arguments[1]=10;
     alert(arguments[0]+num2);
}
//执行这个doAdd()函数会重写第2的参数
x+10 一直执行num1+10

arguments

arguments是一个类似组对象,包含所以传入函数的所有参数,
写程序或者面试中常问的就是如何将arguments转化完成一个数组,请看

Array.prototype.slice.call(arguments);
Array.prototype.slice.call(arguments,0);
Array.prototype.slice.call(arguments,0,arguments.length);
Array.apply(this, arguments); //没用过
Array.apply(null, arguments); //没用过

arguments有一个length属性,表示函数传入参数的个数,还有一个callee属性,这是一个指针,指向拥有这个arguments的函数,这个主要是在函数内部调用自己时使用,也就是递归时使用。看个例子就明白了

function test(count){
 console.log("参数:"+arguments[0]+"个数:"+arguments.length);  
  if(count <=  0){
      console.log("递归"+count+" 结束了");
  }else{
        console.log("递归"+count);
        arguments.callee(--count);//调用自己
     }  
}
test(3);
/*
参数:3个数:1
递归3
参数:2个数:1
递归2
参数:1个数:1
递归1
参数:0个数:1
递归0 结束了
*/

 

创建函数

 

this

 javascript中的this和java中的this差不多,this引用的是函数的执行环境,就是this在不同的执行环境中引用的是不同的对象,执行环境这里还没有说到,以后会详细介绍,这里的this也是简单的介绍一下,我以后会整理一些面试题,帮助大家理解。看例子吧,

//全局变量
var color = "red";//相当于window.color = "red"
//定义一个对象
var obj = {color : "blue"};
function pop(color){
  alert(this.color);
}
pop();//相当于window.pop();输入"red"
//obj对象增加一个方法,将pop赋值给它
obj.pop = pop;
obj.pop(); //输出"blue"

解释一下,this这个对象是在函数执行时才绑定的,可以说是一个动态的。pop函数是定义在window下的一个函数,也就是全局作用域的一个函数,当直接执行pop函数时,就是在全局作用域下调用pop时。this引用的是window,this.color就是window.color,输出red。当我们把pop这个函数赋值给obj这个对象并且调用pop的时候,this引用的就是obj这个对象,this.color
就是obj.color,输出blue。

第二种方式:函数的调用只能是在函数定义之后。

 

callee与caller

函数属性和方法

这里说一下函数的属性和方法,包括length,name,prototype,apply,call这几个。

(1)函数的定义

函数的创建有三种方式,分别为使用Function的构造函数、函数声明、函数表达式,下面分别介绍这三种方法。

 

length

这个属性比较简单,就是表示定义函数时定义的参数的个数,要和arguments.length区分开,arguments.length表示实际输入的参数个数,看例子

function test(a,b){
  console.log("输入的参数个数:"+arguments.length);
  console.log("定义的参数个数:"+test.length);
}
test();//0,2
test(1);//1,2
test(1,2)//2,2
test(1,2,3)//3,2
//函数的内部我们可以通过arguments[i],取得输入的参数,假如定义一个参数,输入两个参数,那怎么取得第二个参数呢
function testA(c){
  console.log("输入的参数个数:"+arguments.length);
  console.log("定义的参数个数:"+test.length);
  console.log("第二个参数:"+arguments[1]);
}
testA(1,100);2,2,100
//这里可以遍历取得所有的参数,不讲了
 var add2=function (ax,ay) {
        alert(ax+ay) ;
    }

 

caller
caller返回一个函数的引用,这个函数调用了当前的函数。
使用这个属性要注意:
1 这个属性只有当函数在执行时才有用
2 如果在javascript程序中,函数是由顶层调用的,则返回null

name

这个属性在前面提到了一点,这个就是函数的名字,我们在创建函数的时候说了这个属性,这个属性不是标准属性,但是很多地方就使用这个属性,主要也是在递归调用上使用。name属性是只读属性,不能修改它的值。直接看例子

//修改name属性
function test(){
  console.log(test.name);
  //修改name属性
  test.name = "newName";
  console.log(test.name);
}
test();//test,test
//函数内部使用name属性,递归调用
function testD(count){
 console.log("参数:"+arguments[0]+"个数:"+arguments.length);  
  if(count <=  0){
      console.log("递归"+count+" 结束了");
  }else{
        console.log("递归"+count);
        testD(--count);//调用自己
     }  
}
testD(3);
/*
参数:3个数:1
递归3
参数:2个数:1 
递归2
参数:1个数:1
递归1
参数:0个数:1 
递归0 结束了 
*/

name属性的使用和arguments.callee()的效果是一样的,只不过arguments.callee()更方便些,当函数名字更改时程序不用更改。

 

Function构造函数

functionName.caller: functionName是当前正在执行的函数。

prototype

函数的prototype属性是一个很重要的属性,特别是在自定义引用类型和实现继承时。我们现在这简单的介绍一下它,因为这个属性足以单独写一篇文章。我们可以认为prototype是一个模板,在new
一个对象时候会参照这个模板,将模板里的属性和方法复制给对象,当然你不定义这个模板,这个模板不存在方法和属性。简单例子

function People(name){
  this.name =  name;
}
//prototype中的属性
People.prototype.home = "jilin";
var hainan = new People("hainan");
console.log(hainan.home);//jilin

先简单介绍到这,后面单独详细说。

(2)函数的调用

 

 

call和apply

这两个方法作用是一样的,就是改变this作用域的值,在特定的作用域中调用自己,也就是设置this的指向,不同点在于参数接收方式不同。apply方法需要两个参数,第一个是指定的作用域,就是要把this指向的对象,第二个是参数数组,函数调用需要的参数,这个参数数组也可以是arguments这个伪数组。call的第一个参数也是给this绑定的值,其他的参数个数不定,其他的参数就是函数调用需要的参数,和apply不同,你要一个一个的都列举出来。看例子

function sum(a,b){
  return a + b;      
}
//arguments参数
function callSum1(a,b){
  return sum.apply(this,arguments);  
}
//数组参数
function callSum2(a,b){
  return sum.apply(this,[a,b]);  
}
//列举所有参数
function callSum3(a,b){
  return sum.call(this,a,b);  
}
console.log(callSum1(1,2));
console.log(callSum2(1,2));
console.log(callSum3(1,2));

上面是传递参数的例子,再看看改变this指向的例子

//全局变量
var color = "red";//相当于window.color = "red"
//定义一个对象
var obj = {color : "blue"};
function pop(color){
  alert(this.color);
}
pop();//相当于window.pop();输入"red"
pop.call(this);//red
pop.call(obj);//blue

解释一下,pop.call(this)这句代码改变了this的指向,因为是在全局中调用的函数,this指向window,输出window.color。pop.call(obj)这句代码将this指向了obj,所以输出obj.color。

 add2(1,2)

这种方式是直接new出来一个Function
实例,通过使用Function的构造函数进行创建函数。Function构造函数可以接收任意多个参数,但是最后一个参数会被认为是函数体,前面的所以参数被当做被创建出来的函数的参数。

 

小结

把函数这部分的基础和大家说了一下,自己讲代码敲了一遍实验了一下,有些东西看着容易懂,写起来还是挺困难的,希望大家也要多写写吧,我一直以为作文就不好,这是难为大家了。要放假了,有点想家了,想吃家里的酸菜了。

 


 

 

 图片 1图片 2

var test = new Function(“a”,”b”,”return a + b”);//参数a和b,函数体return
a + b

  1. var a = function() {   
  2. alert(a.caller);   
  3. }   
  4. var b = function() {   
  5. a();   
  6. }   
  7. b();  

console.log(test(1,2));//3

上面的代码中,b调用了a,那么a.caller返回的是b的引用,结果如下:

我们可以看出比较的麻烦,并且《javascript高级程序设计》也不推荐我们使用这种方式,主要是因为浏览器要解析常规的javascript代码之外,还要解析传入的参数字符串,这个类似eval()的解释,影响性能。

 

 

 

函数表达式

 图片 3图片 4

 

  1. var b = function() {   
  2. a();   
  3. }   

这种方式是创建的常见方式之一,具体请看

如果直接调用a(即a在任何函数中被调用,也就是顶层调用),返回null:

 

 

var test = function(a,b){

 

  return a + b;  

 图片 5图片 6

}

  1. var a = function() {   
  2. alert(a.caller);   
  3. }   
  4. var b = function() {   
  5. a();   
  6. }   
  7. //b();   
  8. a();  

console.log(test(1,2));

输出结果:

上面的代码就是创建一个函数,使用test()进行调用。其实,上面的代码是先创建了一个匿名的函数,之后把这个匿名的函数赋值给test变量。每个函数有一个name属性,这个属性不是ECMA标准的一部分,但是许多地方可以使用它。我们可以给上面的函数起一个名字,具体下面代码

 

 

null

复制代码

callee
callee放回正在执行的函数本身的引用,它是arguments的一个属性
使用callee时要注意:
1 这个属性只有在函数执行时才有效
2
它有一个length属性,可以用来获得形参的个数,因此可以用来比较形参和实参个数是否一致,即比较arguments.length是否等于arguments.callee.length
3 它可以用来递归匿名函数。

//函数的名字newName

 

var test = function newName(a,b){

 图片 7图片 8

  return a + b;  

  1. var a = function() {   
  2. alert(arguments.callee);   
  3. }   
  4. var b = function() {   
  5. a();   
  6. }   
  7. b();  

}

a在b中被调用,但是它返回了a本身的引用,结果如下:

console.log(test.name);//newName

 

 

 图片 9图片 10

//匿名函数

  1. var a = function() {   
  2. alert(arguments.callee);   
  3. }   

var nTest = function (a,b){

constructor

  return a + b;  

constructor 属性返回对创建此对象的数组函数的引用。

}

object.constructor

<script type="text/javascript">

var test=new Array();

if (test.constructor==Array)
{
document.write("This is an Array");
}
if (test.constructor==Boolean)
{
document.write("This is a Boolean");
}
if (test.constructor==Date)
{
document.write("This is a Date");
}
if (test.constructor==String)
{
document.write("This is a String");
}

</script>

console.log(nTest.name);//undefined

输出:

复制代码

This is an Array

这个属性在后面详细解释吧。

如何使用 constructor 属性:

 

<script type="text/javascript">

function employee(name,job,born)
{
this.name=name;
this.job=job;
this.born=born;
}

var bill=new employee("Bill Gates","Engineer",1985);

document.write(bill.constructor);

</script>

函数声明

输出:

 

function employee(name, jobtitle, born)
{this.name = name; this.jobtitle = job; this.born = born;}

这种方式和C语言中的很类似,这种是最常见的一种创建函数的方法。是通过关键字function直接声明,请看

this

 

this指的是调用函数的那个对象,this一般情况下是全局对象global,作为方法调用时,this指的是当前对象。

function test(a,b){

 

  return a + b;  

apply与call

}

call方法: 
语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 
定义:调用一个对象的一个方法,以另一个对象替换当前对象。 
说明: 
call 方法可以用来代替另一个对象调用一个方法。call
方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj
指定的新对象。 
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。 

console.log(test(1,2));//3

apply方法: 
语法:apply([thisObj[,argArray]]) 
定义:应用某一对象的一个方法,用另一个对象替换当前对象。 
说明: 
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个
TypeError。 
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作
thisObj, 并且无法被传递任何参数。

console.log(test.name);//test

 

区别

 

 

prototype原型对象

以上介绍了三个创建函数的方式,现在介绍三种的区别,确切的说是后两种的区别,因为Function不推荐使用,性能是一大原因。区别就是使用函数声明这种方式会使函数的声明提前,类似前面我们提到的变量申明的提前。也就是说,使用函数申明方式,我们可以将函数的声明放在调用函数代码的后面,因为解析器会在代码执行之前将函数的声明提升,提到源代码树的顶部,而函数表达式方式则会报错,具体请看

在JavaScript
中,每当定义一个对象(函数)时候,对象中都会包含一些预定义的属性。其中函数对象的一个属性就是原型对象
prototype。注:普通对象没有prototype,但有__proto__属性。

 

var person = function(name){
   this.name = name
  };
  person.prototype.getName = function(){
     return this.name; 
  }
  var zjh = new person(‘zhangjiahao’);
  zjh.getName(); //zhangjiahao

复制代码

 

//调用函数

理解原型链

console.log(test(1,2));//3

JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例:

//创建函数(函数申明方式)

  console.log(zjh.__proto__ ===
person.prototype) //true

function test(a,b){

同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype

  return a + b;  

  console.log(person.prototype.__proto__ ===
Object.prototype) //true

}

继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null

//上面的函数相等于

  console.log(Object.prototype.__proto__)
//null

//创建函数(函数申明方式)

我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。如下图:
图片 11

//function test(a,b){

 

//  return a + b;  

**内存结构图:
图片 12

//}

画图约定:
图片 13**

//console.log(test(1,2));//3

 

 

 var animal = function(){};
  var dog = function(){};

  animal.price = 2000;//
  dog.prototype = animal;
  var tidy = new dog();


  console.log(dog.price) //undefined
  console.log(tidy.price) // 2000

//调用函数

dog继承了animal,画一下内存图:
图片 14

console.log(ntest(1,2));//TypeError: undefined is not a function

一个完整的例子:

//创建函数(函数表达式方式)

 

var ntest = function (a,b){

function SuperType(){
     this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property; 
};

function SubType(){
    this.subproperty = false;
}

subType.prototype = new SuperType(); //重新原型,继承了SuperType
SubType.prototype.getSubValue = function(){
    return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue());   //true
//instance.constructor指向SuperType
//SubType.prototype中的constructor被重写了
//instance指向SubType的原型,SubType的原型又指向SuperType的原型

  return a + b;  

 

}

搜索步骤:1)实例 2)SubType.prptotype
3)SuperType.prptotype

复制代码

在通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样会重写原型链

not重载

 

 

构造函数、原型、实例的关系

javascript语言不像java那些语言有函数重载这一概念,其实函数名就是一个指针,指向一个Function实例的地址,当然只能指向一个函数,当然没有重载的概念了,只有覆盖,后面定义的函数覆盖前面定义的函数,具体请看

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

 

 

复制代码

function test(a,b){

  return a + b;  

}

//下面的函数覆盖上面的

function test(a,b){

  return a + b + 100;  

}

 

console.log(test(0,0));//100

复制代码

也就是说如果一个同名的函数表达式和函数申明的函数在一起,无论位置是怎么样的,最后的函数就会是用函数表达式创建的函数,因为函数申明会提升到顶部嘛,看看下面的代码

 

复制代码

var test = function (a,b){

  return a + b -100;

}

 

function test(a,b){//会被下面的函数覆盖

  return a + b;  

}

 

function test(a,b){//会被函数表达式覆盖

  return a + b + 100;  

}

 

console.log(test(0,0));//-100

复制代码

内部属性

 

函数的内部有两个重要的对象:arguments和this。

 

arguments

 

arguments是一个类似组对象,包含所以传入函数的所有参数,
写程序或者面试中常问的就是如何将arguments转化完成一个数组,请看

 

Array.prototype.slice.call(arguments);

Array.prototype.slice.call(arguments,0);

Array.prototype.slice.call(arguments,0,arguments.length);

Array.apply(this, arguments); //没用过

Array.apply(null, arguments); //没用过

arguments有一个length属性,表示函数传入参数的个数,还有一个callee属性,这是一个指针,指向拥有这个arguments的函数,这个主要是在函数内部调用自己时使用,也就是递归时使用。看个例子就明白了

 

复制代码

function test(count){

 console.log(“参数:”+arguments[0]+”个数:”+arguments.length);  

  if(count <=  0){

      console.log(“递归”+count+” 结束了”);

  }else{

        console.log(“递归”+count);

        arguments.callee(–count);//调用自己

     }  

}

test(3);

/*

参数:3个数:1

递归3

参数:2个数:1

递归2

参数:1个数:1

递归1

参数:0个数:1

递归0 结束了

*/

复制代码

this

 

 javascript中的this和java中的this差不多,this引用的是函数的执行环境,就是this在不同的执行环境中引用的是不同的对象,执行环境这里还没有说到,以后会详细介绍,这里的this也是简单的介绍一下,我以后会整理一些面试题,帮助大家理解。看例子吧,

 

复制代码

//全局变量

var color = “red”;//相当于window.color = “red”

//定义一个对象

var obj = {color : “blue”};

function pop(color){

  alert(this.color);

}

pop();//相当于window.pop();输入”red”

//obj对象增加一个方法,将pop赋值给它

obj.pop = pop;

obj.pop(); //输出”blue”

复制代码

解释一下,this这个对象是在函数执行时才绑定的,可以说是一个动态的。pop函数是定义在window下的一个函数,也就是全局作用域的一个函数,当直接执行pop函数时,就是在全局作用域下调用pop时。this引用的是window,this.color就是window.color,输出red。当我们把pop这个函数赋值给obj这个对象并且调用pop的时候,this引用的就是obj这个对象,this.color
就是obj.color,输出blue。

 

函数属性和方法

 

这里说一下函数的属性和方法,包括length,name,prototype,apply,call这几个。

 

length

 

这个属性比较简单,就是表示定义函数时定义的参数的个数,要和arguments.length区分开,arguments.length表示实际输入的参数个数,看例子

 

复制代码

function test(a,b){

  console.log(“输入的参数个数:”+arguments.length);

  console.log(“定义的参数个数:”+test.length);

}

test();//0,2

test(1);//1,2

test(1,2)//2,2

test(1,2,3)//3,2

//函数的内部我们可以通过arguments[i],取得输入的参数,假如定义一个参数,输入两个参数,那怎么取得第二个参数呢

function testA(c){

  console.log(“输入的参数个数:”+arguments.length);

  console.log(“定义的参数个数:”+test.length);

  console.log(“第二个参数:”+arguments[1]);

}

testA(1,100);2,2,100

//这里可以遍历取得所有的参数,不讲了

复制代码

name

 

这个属性在前面提到了一点,这个就是函数的名字,我们在创建函数的时候说了这个属性,这个属性不是标准属性,但是很多地方就使用这个属性,主要也是在递归调用上使用。name属性是只读属性,不能修改它的值。直接看例子

 

复制代码

//修改name属性

function test(){

  console.log(test.name);

  //修改name属性

  test.name = “newName”;

  console.log(test.name);

}

test();//test,test

//函数内部使用name属性,递归调用

function testD(count){

 console.log(“参数:”+arguments[0]+”个数:”+arguments.length);  

  if(count <=  0){

      console.log(“递归”+count+” 结束了”);

  }else{

        console.log(“递归”+count);

        testD(–count);//调用自己

     }  

}

testD(3);

/*

参数:3个数:1

递归3

参数:2个数:1 

递归2

参数:1个数:1

递归1

参数:0个数:1 

递归0 结束了 

*/

复制代码

name属性的使用和arguments.callee()的效果是一样的,只不过arguments.callee()更方便些,当函数名字更改时程序不用更改。

 

prototype

 

函数的prototype属性是一个很重要的属性,特别是在自定义引用类型和实现继承时。我们现在这简单的介绍一下它,因为这个属性足以单独写一篇文章。我们可以认为prototype是一个模板,在new
一个对象时候会参照这个模板,将模板里的属性和方法复制给对象,当然你不定义这个模板,这个模板不存在方法和属性。简单例子

 

复制代码

function People(name){

  this.name =  name;

}

//prototype中的属性

People.prototype.home = “jilin”;

var hainan = new People(“hainan”);

console.log(hainan.home);//jilin

复制代码

先简单介绍到这,后面单独详细说。

 

call和apply

 

这两个方法作用是一样的,就是改变this作用域的值,在特定的作用域中调用自己,也就是设置this的指向,不同点在于参数接收方式不同。apply方法需要两个参数,第一个是指定的作用域,就是要把this指向的对象,第二个是参数数组,函数调用需要的参数,这个参数数组也可以是arguments这个伪数组。call的第一个参数也是给this绑定的值,其他的参数个数不定,其他的参数就是函数调用需要的参数,和apply不同,你要一个一个的都列举出来。看例子

 

复制代码

function sum(a,b){

  return a + b;      

}

//arguments参数

function callSum1(a,b){

  return sum.apply(this,arguments);  

}

//数组参数

function callSum2(a,b){

  return sum.apply(this,[a,b]);  

}

//列举所有参数

function callSum3(a,b){

  return sum.call(this,a,b);  

}

console.log(callSum1(1,2));

console.log(callSum2(1,2));

console.log(callSum3(1,2));

复制代码

上面是传递参数的例子,再看看改变this指向的例子

 

复制代码

//全局变量

var color = “red”;//相当于window.color = “red”

//定义一个对象

var obj = {color : “blue”};

function pop(color){

  alert(this.color);

}

pop();//相当于window.pop();输入”red”

pop.call(this);//red

pop.call(obj);//blue

复制代码

解释一下,pop.call(this)这句代码改变了this的指向,因为是在全局中调用的函数,this指向window,输出window.color。pop.call(obj)这句代码将this指向了obj,所以输出obj.color。

我在上一篇【javascript基础】基本概念中介绍了javascript的一些基本概念,多谢大家的阅读和意见,自己写的东西可以被大家阅读,真心…

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图