2017/5 JavaScript基础8--- 函数、作用域

一、函数概述

1、概念

函数是一块JavaScript代码块,被定义一次,但可以执行和调用多次。 函数也是对象,可以像其他对象一样操作和传递函数,Js中的函数也称为函数对象。

2、返回值

1、普通函数返回值依赖 return 语句,如果没有return语句默认返回 undefined

2、作为构造器,外部使用new调用,如果没有return 语句,或 return 后为基本类型,会将this 返回,如果返回一个对象,会将对象作为new 构造器的返回值。

3、不同的调用方式

  1. 直接调用:foo();
  2. 作为对象的方法调用: o.method();
  3. 构造器:new Foo();
  4. call/apply/bind : func.call(o);

二、声明和表达式

1、函数声明

以 function 开头,无括号,不赋值给其他变量

function add(a,b){
  a = +a ;
  b = +b ;
  if(isNaN(a)||isNaN(b){
     return;
  }) 
  return a+b
}

2、函数表达式

//匿名函数赋值
var add = function(a,b){
  //do sth
}

//把匿名函数括号括起来 --- 函数表达式 --- 立即执行表达式
(function(){
   //do sth
})();

//将函数对象作为返回值,函数表达式
return function(){
  //do sth
};

//
var add = function foo(a,b){
  //do sth
};

//实名函数赋值 -- 命名式函数表达式
var add = function foo (a,b){
  //do sth
}

3、变量 & 函数的声明前置

函数表达式和函数声明最主要的区别:函数声明会被前置,  

函数表达式必须先声明再调用。

//函数声明
var num = add(1,2);
console.log(num); //3 函数声明可以调用成功

function add(a,b){
  a = +a;
  b = +b;
  if(isNaN(a)||isNaN(b)){
    return ;
  }
  return a+b;
}

//函数表达式  --变量add 会被提前值为undefined
var num = add(1,2);  //undefined is not a function
console.log(num);

var add = function(a,b){  //匿名函数表达式,赋值给add
  a = +a;
  b = +b;
  if(isNaN(a) || isNaN(b)){
    return;
  }
  return a+b;
}

4、命名函数表达式(NFE)

有名字的函数表达式(不常用)

var func = function nfe(){};

//递归调用
var func = function nfe(){
  /***do sth**/
 nfe()
};

5、Function构造器

//1、形参  2、代码
var func = new Function('a','b','console.log(a+b);');
func (1,2);//3

//没有 new 效果一样
var func = Function('a','b','console.log(a+b);');
func (1,2);//3

var func = Function('a','b','console.log(a+b);')(); //立即调用

三、this指针

1、全局作用域下的this(浏览器)

全局作用域this指向全局对象,在浏览器里面,全局对象是 window , this.a 等价于 window.a

1)变量声明

console.log(this.document === document); //true
console.log(this === window); //ture this和 window是相等的

this.a = 37;  //创建一个全局变量a
console.log(window.a) ; //37

2)函数声明

function f1(){
  return this;
}

f1() === window ; // true  浏览器 this指 window,Nodejs this 指 global


function f2(){
  "use strict"; //see thrict mode  “严格模式”
  return this ;  //this 指向undefined
}

f2() === undefined; //true

2、作为对象方法的函数的this

将函数作为对象方法调用时,函数中this指向调用他的对象。

var o = {          // 创建对象自变量 o
  prop:37,
  f:function(){    //创建对象方法
    return this.prop;
  }
};

console.log(o.f()); //logs 37 o.f()调用 this指向 o


var o = { prop :37};  //创建对象自变量

function independent(){
  return this.prop
}
//直接调用independent this指向浏览器中的window

o.f = independent; //创建对象属性f指向 函数对象

console.log(o.f()); //logs 37   //调用时 this指向对象

3、对象原型链上的this

var o = {
  f: function(){     // 对象的方法
    return this.a + this.b;
  }
}

var p = Object.create(o);  //创建对象空对象 p 原型指向 o

p.a = 1; //创建对象上的属性
p.b = 4;

console.log(p.f()); //5 调用原型链上的方法 this指向 p

4、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 Marh.atan2(this.im , this.re)
  }
}

//给对象添加属性

Object.defineProperty(o,"modulus",{
  get:modulus,enumerable:true,configurable:true
});

cosole.log(o.phase, o.modulus); //-0.78  1.4142  this 都指向 o

5)构造器中的 this

function MyClass(){
  this.a = 37 ; //正常调用 this指向全局对象 window
}

var o = new myClass(); //当把函数作为构造器调用,
//这里this指向 一个空对象o ,且o的原型指向 MyClass.prototype

console.log(o.a); //37 没有返回值时 默认返回this o得到this

function C2() {
  this.a = 37;
  return {a:38}; //返回一个对象,将返回的对象作为返回值
}

o = new C2(); // o 不是 this, o是返回的对象
console.log(o.a); //38

6)call/apply 方法与this

function add(c,d){
  return this.a + this.b + c +d;
}

var o = {a:1,b:3};
// 第一参数 是 想添加的 this对象, 后面是传入的参数。
add.call(o,5,7); //1+3+5+7 =16

//apply 的区别是 传入的参数是数组

add.apply(o,[10,20]); //1+3+10+20= 34


function bar(){
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); //"[object Number]"

7)bind 方法 与 this

//IE9+
function f(){
  return this.a
}
//将 某个对象作为 this, 
var g = f.bind({a:'test'}); f 中 this指向 bind中对象
console.log(g()) ; //test 

//把 f和 g作为对象的方法 赋给对象 o 
var o = {a:37, f:f, g:g};
console.log(o.f, o.g); //37 ,test

四、函数属性 :argument

1、相关参数

  1. foo.name -- 函数名
  2. foo.length -- 形参个数
  3. argument.length -- 实参个数

aegument 是一个类数组的对象,没有join slice等数组方法,但可以根据索引读取

function foo(x,y,z){
  arguments.length; //2-- 得到传入的实参数
  arguments[0]; //1

/******绑定关系******/
  arguments[0] = 10;
  x; //实参变成了10
/*******************/

/***不存在绑定关系***/
  arguments[2] = 100;
  z; //still undefined 未传入参数 ,argument和参数没有绑定关系
/******************/

  arguments.callee === foo; //true
}
//在 "use strict"严格模式下不存在绑定关系,arguments.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);
}

//第一个参数为想要传入的this对象,不是对象会转换为相应的包装类
foo.call(100,1,2); //1,2,Number值(100)
foo.apply(ture,[3,4]); //3,4,Boolean(true) 传入数组
foo.apply(null); //undefined,undefined, window --this指向全局对象
foo.apply(undefined); //undefined,undefined, window --this指向全局对象

//严格模式下
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方法

1)改变函数运行this指向


this.x = 9; //window.x 全局变量x
var module = { //对象自变量
  x:81,
  getX:function(){ return this.x;}
};

module.getX(); //81   

var getX = module.getX; //将方法赋值给变量
getX(); //9 this指向全局变量

//bind 改变函数运行时的 this指向
var boundGetX = getX.bind(module); //当 boundGetX运行时 this指向 module
boundGetX();81

2)函数颗粒化:bind currying

function add(a,b,c){
  return a+b+c; //返回值
}

//不需要改变this,传入 undefined, 并且传入第一个参数 100
var func = add.bind(undefined,100); //a 绑定 100
func(1,2); //103  b =1 ; c =2;

var func2 = func.bind(undefined,200);  // b绑定 200
func2(10); //310  

3)实例

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

3)bind与new

functn foo(){
  this.b = 100;
  return this.a;
}

//foo this指针指向 bind传入的对象
var func = foo.bind({a:1});

func(); //1 this指向 bind参数

// 使用 new 如果return的不是对象,返回this,this被初始化为一个空对象,对象的原型为 foo.prototype
new func(); //返回{b:100}对象自变量 ,忽略bind

4)bind方法模拟

from:慕课网

 

转载于:https://my.oschina.net/u/2991733/blog/903758

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值