1.函数概述
JS中函数比较特殊,函数也是对象中的一种。常叫做函数对象。
所以JS函数可以像其它对象那样操作和传递,所以我们也常叫JS中的函数为函数对象。
函数的返回值依赖return,一般的函数调用:没有return就会默认在所有代码执行完返回一个undefined;
如果作为构造器,外部使用new去调用,这样没有return语句或者return后边是基本类型的话,那么会将this作为返回;反之如果return了一个对象的话,这个对象作为new构造器的返回值。
函数4调用方式(不同调用方式this指向不同):
JavaScript核心:this,arguments,构造函数,作用域,不同调用方式,不同创建方法,闭包,原型链prototype,原型继承_proto_
…
2.函数声明与表达式
定义函数的三种形式:
1.函数声明
function add(a,b){
a = +a;
b = +b;
if(isNaN || isNaN(b)){
return;
}
return a+b;
}
2.函数表达式
// function variable
var add = function(a,b){
};
//IEF(Immediately Executed Function) 立即执行函数表达式
(function(){
})();
//first-class function 作为返回值的函数表达式
return function(){
}
//NFE(Named Function Expression) 已命名的函数表达式
var add = function(a,b){
}
3.Function构造器
var func = new Function('a','b','console(a+b);')
func(1,2); //3
var func = Function('a','b','console(a+b);')
func(1,2); //3
附注:
一个完整语句,以function开头,例如:
// 这是函数声明
function foo() {
}
而用括号括起来的,或者前面有一元操作符的,都是函数表达式,例如:
// 函数表达式
(function foo() {
})
// 函数表达式
!function foo() {
}
// 函数表达式
+function foo() {
}
函数声明和函数表达式的区别:函数声明会被前置。
// 函数声明(函数声明被提前)
var num = add(1,2);
console.log(num); // 3
function add(a,b){
return a+b;
}
// 函数表达式(变量add被提前,但是是undefined)
var num = add(1,2);
console.log(num); //undefined is not a function
var add = function(a,b){
return a+b;
}
Function构造器作用域和处理与一般函数有一定区别:
注:声明未定义和未声明的变量经过typeof都返回undefined
1.在函数构造器里面定义的变量是局部变量
Function('var localVal = "local";console.log(localVal);')();// 可以立即调用执行
console.log(typeof localVal);
// result:local,undefined (localVal仍为局部变量)
2.不能访问拿到外层函数的局部变量localVal(可以拿到全局对象,但是拿不到外层局部变量)
var globalVal = 'global';
(function(){
var localVal = 'local';
Function('console.log(typeof localVal,typeof globalVal);')();
})();
// result: undefined,string (local不可访问,全局变量global可以访问)
函数构造器(Constructor):
函数构造器就是可以用来构建生成新的函数或者对象的函数。
函数构造器也是一个普通函数,只不过在使用该函数构造生成新的函数或者对象的时候,该函数才会称为函数构造器。
构建的过程简单来说分两步:
1、创建一个空对象,并执行类似构造函数bind该空对象的过程。也就是把构造函数中的this指向新的空对象然后执行一遍,这个过程可以叫初始化。
2、把空对象的原型指向构造函数的原型,也就是构建原型链继承。
构建出的对象或者函数可以称为构造函数的一个实例,因为在完成初始化的过程就设定新对象的许多私有属性,而且该对象也继承了构建函数的原型链,及上面的共有属性。
3.this
this对象就是谁调用指向谁.
this在运行时才确定所指向的具体对象是谁。
1.当函数作为对象的方法调用时,this指向该对象。
2.当函数作为淡出函数调用时,this指向全局对象(严格模式时,为undefined)
3.构造函数中的this指向新创建的对象
4.嵌套函数中的this不会继承上层函数的this,如果需要,可以用一个变量保存上层函数的this。
再总结的简单点,如果在函数中使用了this,只有在该函数直接被某对象调用时,该this才指向该对象。
fn.call(o); //改变函数fn的作用域对象
fn.apply(o); //改变函数fn的作用域对象
fn.bind(o); //将函数fn的作用域绑定到对象o上
1.全局作用域下this(浏览器):
console.log(this.document === document); //true
console.log(this === window); //true
this.a = 37;
console.log(window.a); //37
2.一般函数的this(浏览器):
全局作用域下,this指向window,nodejs下是global;
严格模式下,this是undefined;
function f1(){
return this;
}
f1() === window; //true,global object
function f2(){
"use strict";
return this;
}
f2() === undefined; //true
3.作为对象方法的函数this
this作为方法调用:作为对象方法调用 指向该对象
函数作为一个对象的属性的值,也常常叫作一个对象的方法。
// 函数作为一个对象的属性的值,也常常叫作一个对象的方法。
var o = {
prop:37,
f:function(){
return this.prop;
}
};
//调用对象的方法,该方法就是一个函数
console.log(o.f()); // 37 this指向对象o
var o = {prop:37};
function independent(){
return this.prop;
}
// 函数赋给对象的属性
o.f = independent;
console.log(o.f()); // 37
4.对象原型链上的this
对象原型链上的this,不管是原型链上的还是本身,都可以拿到.
var o = {f:function(){return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
get/set方法与this:指向get set方法所在的对象里面
function modulus(){
return Math.sqrt(this.re*this.re + this.im*this.im);
}
var o = {
re:1,
im:-1,
get phase(){
return Math.atan2(this.im,this.re);
}
}
Object.defineProperty(o,'modulus',{
get:modulus,enumerable:true,configurable:true
)};
console.log(o.phase,o.modulus); // -0.78 1.4142
5.构造器中的this
构造器中的this,若没有return,this的指向会作为返回值.
函数的返回值依赖return,一般的函数调用:没有return就会默认在所有代码执行完返回一个undefined;
如果作为构造器,外部使用new去调用,这样没有return语句或者return后边是基本类型的话,那么会将this作为返回;反之如果return了一个对象的话,这个对象作为new构造器的返回值。
function MyClass(){
this.a =37;
}
var o = new MyClass();
console.log(o.a); //37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // 38
6.call/apply方法与this
call/apply方法与this的应用场景及用法,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+10+20 = 34
function bar(){
console.log(Object.prototype.toString.call(this));
}
bar.call(7);// "[object Number]"
7.bind方法与this
bind将一个对象绑定为某对象里的(此处为函数)this后,被绑定的对象可以以特定的this,实现重复使用。
如这里的g()函数
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,使用bind绑定this
4.arguments
this始终指向的是调用者,当函数作为构造器时,this指向的新创建的空对象,然后就会执行构造器的所有代码,碰见this.XXX就是为新建对象添加属性.如果构造器最后没有显示的使用return返回一个值,那么就会返回this即新建对象.
函数属性和arguments:
arguments是一个类数组对象,原型不是Array.prototype,所以它没有join等数组对象才有的方法。
可以通过索引访问arguments对象。
function foo(x,y,z){ //形参
arguments.length;// 2 实参个数
arguments[0];//1
// 绑定关系
arguments[0] = 10;
x;//10
// 未传参数,失去绑定关系
arguments[2] = 100;
z;//undefined
arguments.callee === foo;//true
}
foo(1,2)
foo.length;// 3 形参个数
foo.name;// "foo" 函数名
arguments.length 实参个数
apply/call方法(浏览器)
function foo(x,y){
console.log(x,y,this);
}
foo.call(100,2,,3);// 2,3,Number(100)不是对象的会转变成对象
foo.apply(true,[3,4]);// 3,4,Boolean
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
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);
改变函数运行是的this,绑定了module
bondGetX();// 81
bind与currying
function add(a,b,c){
return a+b+c;
}
var func = add.bind(undefined,100);
func(1,2); // 103
// 100+200+10 =310
var func2 = func.bind(undefined,200);
func2(10); // 310
bind与new
function foo(){
this.b = 100;
return this.a;
}
var func = foo.bind({a: 1});
func();//1
new func();// {b:100}
bind方法模拟: