一、函数概述
1、概念
函数是一块JavaScript代码块,被定义一次,但可以执行和调用多次。 函数也是对象,可以像其他对象一样操作和传递函数,Js中的函数也称为函数对象。
2、返回值
1、普通函数返回值依赖 return 语句,如果没有return语句默认返回 undefined
2、作为构造器,外部使用new调用,如果没有return 语句,或 return 后为基本类型,会将this 返回,如果返回一个对象,会将对象作为new 构造器的返回值。
3、不同的调用方式
- 直接调用:foo();
- 作为对象的方法调用: o.method();
- 构造器:new Foo();
- 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、相关参数
- foo.name -- 函数名
- foo.length -- 形参个数
- 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:慕课网