js函数声明及调用

函数定义

总共有三种函数定义的方式:函数声明语句、函数表达式、构造函数

  1. 函数声明语句:简单来说就是通过function关键字声明的函数体。function f() {};
  2. 函数表达式:通过一个变量来存取函数的返回值,它实际上是一个匿名函数(函数没有名称);var fn = function () {};
  3. 构造函数:通过new关键字来定义函数,函数的形参和函数体都放在实例对象里。
var test = new Function("a", "b", "return a * b");

var x = test(4, 3);
console.log(x); //12

参数和返回值都需要使用引号
这种定义函数较为少见。

函数调用

javascript一共有4种调用模式:函数调用模式、方法调用模式、构造器调用模式和间接调用模式。
1.函数调用模式:就是通过函数名();this指向window
2.方法调用模式:通过访问对象中的方法,对象名.函数名();this指向调用方法的对象
3.构造器调用模式:通过建立new构造函数和创建对象,调用函数用实例化对象.函数名();this指向构造函数的实例
4.间接调用模式:
也称之为“apply、call调用模式” 或 “上下文调用模式”。每个函数都包含两个非继承而来的方法:call()方法和 apply()方法,它们的作用都是一样的,改变函数的this指向
例如:

var obj = {};
var getSum = function(a, b){
	console.log(this); // 2次都会打印{}
	return a + b;
};
var sum1 = getSum().call(obj, 1, 2); 
console.log(sum1); //3
//形参通过数组方式传递
var sum2 = getSum().apply(obj, [10, 20]);
console.log(sum2); //30

function f1(){
   console.log(this);
}
f1.call(NaN);          //Number实例
f1.call(null); 			// Window
f1.call(undefined); 	// Window
f1.call(123);		   // Number的实例
f1.call("abc"); 	   // String的实例
f1.call(true); 		   // Boolean的实例
f1.call([1,2,3]); 	   // Array的实例

这里不得不提一个更为常见、尤为重要的另一个方法bind();
它也能改变函数的this指向,只不过它不会像前两种那样函数会自己马上调用执行,我们看一个例子来区分它们:

	var obj = {};
	var btn = document.querySelector('button');
    btn.onclick = function () {
        console.log(this); // 没点击不会输出{}
    }.bind(obj); 
    btn.onclick = function () {
        console.log(this); // 没点击也会输出{}
    }.call(obj); //或.apply(obj); 

这里说一下函数提升,使用表达式定义的函数无法提升,它是要优先于变量提升的。
例如:

console.log(a);//函数a函数体
var a = 100;
function a() {
	console.log(a);//报错
}
a(); 

第二个报错的原因是:变量a函数a都是window对象的,由于函数提升优于变量提升,也就是说,后来声明的a变量就覆盖了函数a,所以在最后我们调用的时候,是调用数字而不是函数a。

再来看一个例子:

var name = "zhangsan";
function a() {
	console.log(name);
}
function b() {
	var name = "lisi";
	a(); //zhangsan
}
b();
var name = "zhangsan";

function b() {
	var name = "lisi";
	function a() {
		console.log(name);
	}
	a(); //lisi
}
b();

注意这2个例子,涉及到了作用域,第一个由于是全局作用域下定义的函数,name会直接在全局作用域下查找,故输出zhangsan;而第二个由于是局部作用域下定义的函数,name首先会从自己的AO对象查找,没有发现,就会向上查找b函数的AO,发现了name,故输出lisi
这里对作用域链不清楚的可以去访问:
https://blog.csdn.net/qq_48784569/article/details/107405794
匿名自执行函数

  • 函数表达式可以 “自调用”。
  • 如果表达式后面紧跟 () ,则会自动调用。
  • 不能自调用声明的函数。
  • 对于函数自调用,必须通过在函数表达式外面添加括号(来说明它是一个函数表达式)再调用,否则会报错
(function () {
    var x = "Hello!!";      // 我将调用自己
})();

这里就有一个对照的题来解读:

var b = 10;
(function b() {
  b = 20;
  console.log(b); 
})();

这是一道面试题,它的结果是什么呢?
在这里插入图片描述
为什么打印这个b函数体呢,
1.函数提升优于变量提升
2.非匿名自执行函数中,函数变量为只读状态无法修改

注意:箭头函数不能适用call()apply()bind()方法哟!

var obj = {}
var a = () => { console.log(this) }
a.call(obj)//window
a.apply(obj)//window
a.bind(obj)
a()//window
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值