JavaScript深入浅出————函数和作用域(函数,this)(六)

来源:互联网 发布:js引用 编辑:程序博客网 时间:2024/05/01 14:19

一、函数概述

 函数是一块JavaScript代码,被定义一次,但可执行和调用多次.JS中的函数也是对象,所以js函数可以像其它对象那样操作和传递,所以我们也常叫JS中的函数为函数对象
 
 不同的调用方式
 直接调用:foo();
 对象方法:o.method();
 构造器:new Foo();
 call/apply/bind:func.call(o);


二、函数声明和表达式

 1.函数声明   vs  函数表达式
 函数声明:function add(a,b){....}
 
 函数表达式:
 var add=function(a,b){...};
 (function(){...})();//定义匿名函数并立即调用
 return function(){...};
 var add=function foo(a,b){...};
 
 2.变量&函数的声明前置
 函数声明可以在调用之后,而函数表达式必须在调用之前
 
 3.命名函数表达式(NFE)
 var func=function nfe(){};
 alert(func===nfe);//在IE6,7,8弹出false,在IE9+会报错:"nfe" is undefined
 
 //递归调用
 var func=function nfe(){/*do sth*/nfe();}
 
 4.Function构造器
 可以含有n个参数,前面n-1个参数表示形参,最好一个表示函数体里面的代码
 var func=new Function("a","b","console.log(a+b);");
 func(1,2);//3
 
 var func=Function("a","b","console.log(a+b);");
 func(1,2);//3
 
 Function构造器的作用域
 //case1
 Function('var localVal="local";console.log(localVal);')();//localVal仍为局部变量
 console.log(typeof localVal);
 //result:local,undefined
 
 //case2
 var globalVal="global";
 (function(){
  var localVal="local";
  Function("console.log(typeof localVal,typeof globalVal);")();//local不可访问,全局变量global可以访问
 })();
 //result:undefined,string


三、this
 1.全局的this(浏览器)
 在浏览器中,全局的this指window
 console.log(this.document===document);//true
 console.log(this===window);//true
 
 this.a=37;
 console.log(window.a);//37
 
 2.一般函数的this(浏览器)
 function f1(){
  return this;
 }
 f1()===window;//true,在浏览器中this指window,在node.js中指global对象
 
 function f2(){
  "use strict";//see strict mode
  return this;
 }
 f2()==="undefined";//true,严格模式下,this指向undefined
 
 3.作为对象方法的函数的this
 函数作为对象属性的值的时候常常叫做对象方法
 var o={
  prop:37,
  f:function(){
   return this.prop;
  }
 };
 console.log(o.f());//37
 
 var o={prop:37};
 function independent(){
  return this.prop;
 }
 independent();//此时this指window
 o.f=independent;//此时this指o
 console.log(o.f());//37
 
 4.对象原型链上的this
 var o={f:function(){return this.a+this.b;}};
 var p=Object.create(o);//p为空的对象,并且p的原型指向o
 p.a=1;
 p.b=4;
 console.log(p.f());//5
 
 5.get/set方法与this
 function modulus(){
  return Math.sqrt(this.re*this.re+this.im*this.im);
 }
 
 var o={
  re:1,
  im:-1,
  get phase(){
   return Math.agan2(this.im,this.re);
  }
 };
 
 Object.defineProperty(o,"modulus",{
  get:modulus,enumerable,configurable:true
 });
 
 console.log(o.phase,o.modulus);
 
 6.构造器中的this
 function MyClass(){
  this.a=37;
 }//函数没有return语句,会返回this
 
 var o=new MyClass();//o的原型指向MyClass.prototype
 console.log(o.a);//37
 
 function C2(){
  this.a=37;
  return {a:38};
 }
 
 o=new C2();
 console.log(o.a);//38
 
 7.call/apply方法与this
 function add(c,d){
  return this.a+this.b+c+d;
 }
 
 var o={a:1,b:3};
 
 add.call(o,5,7);//1+3+5+7=16
 add.apply(o,[10,20]);//1+3+!0+20=34
 call和apply基本一致,只是传参有所不同,call是将参数一个一个传进去,而apply是将参数作为一个数组传进去
 
 function bar(){
  console.log(Object.prototype.toString.call(this));
 }
 bar.call(7);//"[object Number]"
 
 8.bind方法与this
 function f(){
  return this.a;
 }
 
 var g=f.bind({a:"test"});
 console.log(g());//test
 
 var o={a:37,f:f,g:g};
 console.log(o.f(),o.g());//37,test
 
四、函数属性、arguments

 1.函数属性 & arguments
 foo.name:函数名
 foo.length:形参个数
 arguments.length:实参个数
 
 function foo(x,y,z){
  arguments.length;//2,实际参数1,2
  arguments[0];//1
  arguments[0]=10;
  x;//change to 10;与上面的arguments[0]为绑定关系
  
  arguments[2]=100;
  z;//still undefined!!!,注意:未传参数失去绑定关系
  arguments.callee===foo;//true
 }
 foo(1,2);
 foo.length;//3,x,y,z三个形参
 foo.name;//"foo",函数名
 
 严格模式:
 function foo(x,y,z){
  "use strict";
  arguments.length;//2,实际参数1,2
  arguments[0];//1
  arguments[0]=10;
  x;//严格模式下仍然是1
  
  arguments[2]=100;
  z;//still undefined!!!,注意:未传参数失去绑定关系
  //严格模式下不能使用callee
 }
 foo(1,2);
 foo.length;//3,x,y,z三个形参
 foo.name;//"foo",函数名
 
 2.apply/call方法(浏览器)
 function foo(x,y){
  console.log(x,y,this);
 }
 foo.call(100,1,2);//1,2,Number(100)
 foo.apply(true,[3,4]);//3,4,Boolean(true)
 foo.apply(null);//undefined,undefined,window
 foo.apply(undefined);//undefined,undefined,window
 
 严格模式下:
 function foo(x,y){
  "use strict"
  console.log(x,y,this);
 }
 foo.apply(null);//undefined,undefined,null
 foo.apply(undefined);//undefined,undefined,undefined
 
 3.bind方法
 this.x=9;
 var module={
  x:81,
  getX:function(){return this.x;}
 };
 
 module.getX();//81
 
 var getX=module.getX;
 getX();//9
 
 var boundGetX=getX.bind(module);//通过bind方法可以改变函数运行时里面对应得this,此时this指向module
 boundGetX();//81
 
 4.bind与currying
 bind除了改变函数里的this外,还有科里化的功能,函数科里化就是将函数拆成多个单元
 
 function add(a,b,c){
  return a+b+c;
 }
 
 var func=add.bind(undefined,100);//相当于100固定赋值给第一个参数a
 func(1,2);//103,此时1给b,2给c
 
 var func2=func.bind(undefined,200);//200绑定给b,100已经绑定给a
 func2(10);//310
 
 实例:
 function getConfig(colors,size,otherOptions){
  console.log(colors,size,otherOptions);
 }
 
 var defaultConfig=getConfig.bind(null,"#cc0000","1024*768");
 
 defaultConfig("123");//#cc0000 1024*768 123
 defaultConfig("456");//#cc0000 1024*768 456
 
 5.bind与new
 function foo(){
  this.b=100;
  return this.a;
 }
 
 var func=foo.bind({a:1});
 
 func();//1
 new func();//{b:100},使用new调用时,bind的作用会被忽略掉
 注意:使用new时,除非是对象,否则会把this作为返回值,并且this会被初始化为一个空对象,这个对象的原型是foo.prototype
 
 6.bind方法模拟(如何在老的ie浏览器中实现bind方法)
 bind方法的两个功能:绑定this和科里化(把函数拆成不同的子函数)
 
 if(!Function.prototype.bind){
  Function.prototype.bind=function(oThis){
   if(typeof this!=="function"){
    //closet thing possible to the ECMAScript 5
    //internal IsCallable function
    throw new TypeError("What is trying to be bound is not callable")
   }
   var aArgs=Array.prototype.slice.call(arguments,1),
    fToBind=this,
    fNOP=function(){},
    fBound=function(){
     return fToBind.apply(this.instanceof fNOP?this:oThis,aArgs.concat(Array.prototype.slice.call(arguments)));
    };
   fNOP.prototype=this.prototype;
   fBound.prototype=new fNOP();
   
   return fBound;
  }
 }
 


 





0 0