函数调用模式4种方式详解
2017-03-15 22:17
183 查看
函数调用模式:
函数模式
特征:就是一个简单的函数调用,函数名前面没有任何的引导内容function foo(){} var func = function(){} foo(); func(); (function(){})();
this在函数模式中的含义:
this在函数中表示全局对象,在浏览器中是window对象
方法模式
特征: 方法一定是依附于一个对象, 将函数赋值给对象的一个属性, 那么就成为了方法.function f() { this.method = function () {}; } var o = { method: function () {} }
this在方法模式调用中的含义:表示函数所依附的这个对象
构造器调用模式
由于构造函数只是给 this 添加成员. 没有做其他事情. 而方法也可以完成这个操作, 就 this 而言, 构造函数与方法没有本质区别.特征:使用 new 关键字, 来引导构造函数.
function Person(){ this.name = "zhangsan"; this.age = 19; this.sayHello = function(){ }; } var p = new Person(); p.sayHello();
构造函数中发
this与方法中一样, 表示对象, 但是构造函数中的对象是刚刚创建出来的对象
关于构造函数中return
关键字的补充说明
构造函数中不需要return, 就会默认的
return this
如果手动的添加
return, 就相当于 return this
如果手动的添加
return基本类型; 无效, 还是保留原来 返回
this
如果手动添加
return null; 或
return undefiend, 无效
如果手动添加
return 对象类型; 那么原来创建的
this就会被丢掉, 返回的是
return后面的对象
上下文调用模式
上下文(Context),就是函数调用所处的环境。上下文调用,也就是自定义设置
this的含义。
在其他三种调用模式中,函数/方法在调用的时候,this的值都是指定好了的,我们没办法自己进行设置,如果尝试去给
this赋值,会报错。
上下文调用的语法–call、apply
//第一种, apply 函数名.apply(对象, [参数]); //第二种, call 函数名.call(对象, 参数); //上面两种方式的功能一模一样,只是在传递参数的时候有差异。
功能描述:
语法中的函数名表示的就是函数本身,使用函数调用模式的时候,
this默认是全局对象
语法中的函数名也可以是方法(如:
obj.method),在使用方法模式调用的时候,
this默认是指当前对象
在使用
apply和
call的时候,默认的
this都会失效,
this的值由
apply和
call的第一个参数决定
补充说明
如果函数或方法中没有
this的操作, 那么无论什么调用其实都一样.
如果是函数调用
foo(), 那么有点像
foo.apply( window ).
如果是方法调用
o.method(), 那么有点像
o.method.apply( o ).
参数问题
call和
apply在没有后面的参数的情况下(函数无参数, 方法无参数) 是完全一样的.
如下:
function foo() { console.log( this ); } foo.apply( obj ); foo.call( obj );
第一个参数的使用规则:
如果传入的是一个对象, 那么就相当于设置该函数中的 this 为参数
如果不传入参数, 或传入 null. undefiend 等, 那么相当于 this 默认为 window
foo(); foo.apply(); foo.apply( null ); foo.call( undefined );
如果传入的是基本类型, 那么 this 就是基本类型对应的包装类型的引用
number -> Number
boolean -> Boolean
string -> String
第二个参数的使用规则
在使用上下文调用的时候, 原函数(方法)可能会带有参数, 那么这个参数在上下文调用中使用第二个( 第 n 个 )参数来表示
function foo( num ) { console.log( num ); } foo.apply( null, [ 123 ] ); // 等价于 foo( 123 );
绑定函数bind
bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。常见的错误就像上面的例子一样,将方法从对象中拿出来,然后调用,并且希望this指向原来的对象。如果不做特殊处理,一般会丢失原来的对象。使用bind()方法能够很漂亮的解决这个问题://实现bind Function.prototype._bind = function(thisObj) { var fun = this; var args = [].slice.call(arguments, 1); //bind函数的参数 return function() { [].push.apply(args,arguments); //bind函数参数+调用时函数参数 return fun.apply(thisObj, args); } } //应用案例 this.num = 9; var module = { num: 81, getNum: function(a) { console.log(this.num,a,arguments); } }; module.getNum(1); // 81 var getNum = module.getNum; getNum(2); // 9, 因为在这个例子中,"this"指向全局对象 // 创建一个'this'绑定到module的函数 var boundGetNum = getNum._bind(module,4); //bind时给函数设置预定参数,下面调用函数时,可以再追加参数 boundGetNum(3); // 81,4,[4,3]
场景:setTimeout函数里面this指向全局,使用bind改变this指向
var name="12"; var obj = { name: 'wei', getName: function() { setTimeout(function() { console.log(this.name); }, 1000); }, bindGetname: function(){ setTimeout(function() { console.log(this.name); }.bind(this), 1000); } } obj.getName();//12 obj.bindGetname(); //wei
上下文调用模式的应用
上下文调用只是能修改this, 但是使用的最多的地方上是函数借用.
1. 将伪数组转换为数组
伪数组转为数组: /*方法一:var arr = [].slice.call(arguments);*/ /*方法二:var arr = [].concat.apply([],arguments);*/ /*方法三*/ var arr = []; arr.push.apply(arr,arguments); console.log(arr instanceof Array); //true console.log(arr);
2. 求数组中的最大值
传统的做法var max = arr[ 0 ]; for ( var i = 1; i < arr.length; i++ ) { if ( arr[ i ] > max ) { ... } }
在 js 中的
Math对象中提供了很多数学函数
Math.max( 1,2,3 )
还是利用 apply 可以展开数组的特性
var arr = [ 123456,12345,1234,345345,234,5 ]; Math.max.apply( null, arr );
3.借用构造函数继承
function Person ( name, age, gender ) { this.name = name; this.age = age; this.gender = gender; } // 需要提供一个 Student 的构造函数创建学生对象 // 学生也应该有 name, age, gender, 同时还需要有 course 课程 function Student ( name, age, gender, course ) { Person.call( this, name, age, gender ); this.course = course; }
函数调用模式-知识点Test
函数调用模式有 函数调用、方法调用、构造函数调用,上下文调用//1 var age = 38; var obj = { age: 18, getAge: function() { console.log(this.age); } }; var a = obj.getAge(); var getAge = obj.getAge; getAge(); //18 38 //2 var age = 38; var obj = { age: 18, getAge: function() { console.log(this.age); //18,方法调用模式 function foo() { console.log(this.age); //38,函数调用模式,this指向window } foo(); } }; obj.getAge(); //3 var length = 10; function fn(){ console.log(this.length); } var obj = { length: 5, method: function (fn) { fn(); // 10 ,函数调用模式 fn.call(obj); //5, this指向obj arguments[0](); //4 ,arguments[0]是fn,属于arguments对象,方法调用 } }; obj.method(fn, 123, 456, 789);
function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; var getName = function () { alert (4);}; function getName() { alert (5);} Foo().getName(); new Foo().getName();
第一个是调用函数,修改了一开始定义的window.getName函数,Foo().getName()相当于window.getName,所以是1. new Foo()是实例对象,本身对象没有getName(),所以去调用原型的getName(),所以是3。
严格模式下的函数调用模式–this指向问题
'use strict' var a=20; function fn(){console.log(this.a)} fn(); //非严格模式下,this指向window,结果为20 //严格模式下,this指向undefined,结果报错,Uncaught TypeError: Cannot read property 'a' of undefined console.log("----------------"); var a=20; function fn(){ function foo(){ console.log(this.a); } foo(); } fn(); //非严格模式下,this指向window,结果为20 //严格模式下,this指向undefined,结果报错,Uncaught TypeError: Cannot read property 'a' of undefined
总结:在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象(方法调用)。如果函数独立调用,那么该函数内部的this,则指向undefined(函数调用)。但是在非严格模式中,当this指向undefined时,它会被自动指向全局对象。
// 为了能够准确判断,我们在函数内部使用严格模式,因为非严格模式会自动指向全局 function fn() { 'use strict'; console.log(this); } fn(); // fn是调用者,独立调用(内部this指向undefined) window.fn(); // fn是调用者,被window所拥有(内部this指向window)
但注意,
// demo03 'use strict' var a = 20; var obj = { a: 10, c: this.a + 20, fn: function () { return this.a; } } console.log(obj.c); //40 console.log(obj.fn()); //10
对象obj中的c属性使用this.a + 20来计算,而他的调用者obj.c并非是一个函数。因此他不适用于上面的规则,我们要对这种方式单独下一个结论。
当obj在全局声明时,无论obj.c在什么地方调用,这里的this都指向全局对象,而当obj在函数环境中声明时,这个this指向undefined,在非严格模式下,会自动转向全局对象。可运行下面的例子查看区别。
'use strict'; var a = 20; function foo () { var a = 1; var obj = { a: 10, c: this.a + 20, fn: function () { return this.a; } } return obj.c; } console.log(foo()); // 运行会报错:Uncaught TypeError: Cannot read property 'a' of undefined
补充练习:
function foo() { console.log(this.a) } function active(fn) { fn(); // 真实调用者,为独立调用 } var a = 20; var obj = { a: 10, getA: foo } active(obj.getA);
非严格模式下,结果为: 20,
严格模式下:结果为:Uncaught TypeError: Cannot read property ‘a’ of undefined
相关文章推荐
- 4种函数调用方式
- js中call和apply(函数的上下文调用模式)详解
- lazarus中不同模式下自定义函数的调用方式区别
- 关于函数调用方式__stdcall和__cdecl详解
- 函数调用4种声明方式
- ES6中箭头函数的定义与调用方式详解
- 函数调用约定 : _stdcall _cdecl fastcall 调用方式详解
- javascript 函数的4种调用模式
- js中的4种函数调用模式:函数调用、方法调用、构造器调用、间接调用
- js中call和apply(函数的上下文调用模式)详解
- C++中函数调用时的三种参数传递方式详解
- javascript 函数的4种调用方式与 this(上下文)的指向
- 函数调用方式详解
- javascript四种调用方式——方法调用模式、函数调用模式、构造器调用模式和Apply或Call调用模式
- C函数调用-不使用函数返回值,而用参数实现输入/输出的4种模式
- C++学习之路(31)---函数调用时的三种参数传递方式详解
- Linux系统调用--fstat/stat/lstat函数详解
- 【代码真相】之 函数调用方式 __cdecl & __stdcall
- 函数调用方式 08.11.2
- .NET工程中以 C 和 C++ 两种方式编译时,函数调用注意事项