欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js进阶知识—函数

程序员文章站 2024-03-26 10:06:11
...

2020-8-10~8-16 函数部分遗漏的知识将在今后学习之中慢慢总结。

函数:

1-1声明式(Function Declaration):

function fn() {
         console.log('我是函数声明式');
     }
    //  fn();两种调用方法
    fn.call();

1-2表达式(Function Expression):

var fn = function(aru) {
        console.log(aru);
    };
	//aru是形参
    fn('我是函数表达式');

fn是变量名,不是函数名,里面存的是一个函数。所以也称为匿名函数。函数的表达式需要在语句的结尾加上分号,表示语句结束。

1-3 new Function()定义:

var fn = new Function(‘参数1’, ‘参数2’, …, ‘函数体’) 所有函数都是Function的实例(对象)。

var sum = new Function('a', 'b', 'console.log(a + b)');
sum(1, 2);
//所有函数都是Function的实例(对象)
//函数也属于对象
console.log(sum instanceof object);

//等同于:
function sum(a, b) {
    console.log(a + b);
}
sum(1, 2);

可以传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。Function里面的参数必须是字符串的格式。这种声明函数的方式非常不直观,较少使用。

2-1立即执行函数IIFE:

(function(a, b){     //匿名函数自调用
    console.log(a + b);
})(1, 2);//函数定义完,立即被调用,立即执行函数往往只会执行一次

2-2回调函数:

定义后没有调用,但函数自己执行了。

①dom事件回调函数:

<button>点击</button>
var btn = document.querySelector('button');
btn.onclick = function() {
	alert(this.innerHTML);
}

②定时器回调函数:

setTimeout(function(){
	alert('2秒钟到了');
}, 2000)

2-3箭头函数:

箭头函数里面没有this, arguments不能使用

var sum = function(x, y) {
	return x + y;
};   //匿名函数
var sum2 = (x, y) => {
	return x + y;
}; //箭头函数,由于函数体只有一行代码,可以简写如下
var sum2 = (x, y) => x + y; //如果只有一个参数,小括号也可以省略  var sum2 = x => {}

<button>点击按钮变成红色</button> 
const btn = document.querySelector('button');
btn.addeventListener('click', function() {
	this.style.backgroundColor = 'red';  
});  //此时点击按钮后,样式会变成红色,但改为如下所示的箭头函数后会显示backgroundColor未定义
<button>点击按钮变成红色</button> 
const btn = document.querySelector('button');
btn.addeventListener('click', () => {
    console.log(this === window);     //true
	//this.style.backgroundColor = 'red';  将function()改为箭头函数后,为btn设置样式会显     //示未定义的报错,原因就是箭头函数里面没有this
});  //

3-1变量:

对于顶层函数来说,函数外部声明的变量就是全局变量(global variable),它可以在函数内部读取。全局变量在网页关闭后删除。在函数内部定义的变量(使用var),称为局部变量(local variable),外部无法读取。当函数执行完毕,本作用域内的局部变量会销毁。

3-2const

声明常量,常量就是值(内存地址)不能变化的量。

①不允许重复使用 ②不属于顶层对象window ③不存在变量提升 ④暂时性死区 ⑤块级作用域

const arr = [100, 200];  //复杂数据类型,数据内容可以更改,但数据值本身不可更改
arr[0] = 'a';
arr[1] = 'b';
console.log(arr);  //['a', 'b'] 并没有更改arr常量在内存中的存储地址
arr = ['a', 'b']; //,而此种赋值操作则更改了arr在内存中的存储地址
const PI = 3.14;
PI = 100; //报错,因为常量声明后,值(简单数据类型)不可更改

3-3作用域(scope):

指的是变量存在的范围。在 ES5 的规范中,JavaScript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。ES6 又新增了块级作用域。

③块级作用域:一对{}就产生了块级作用域,在块级作用域中声明的变量只能在{}里访问,如es6中的let声明的变量和const声明的常量。

if(true) {
	const str = 'es6';
	let a = 10;    	 //此时const和let声明的变量只在{}里面有用
}
console.log(str);
console.log(a);   //会报错,如果将const 和 let改为var,则不会报错。

3-4暂时性死区:

比如在es6中,如下面代码所示的{}作用域中在num被声明之前就使用了num,会报错。

var num = 10;
if(true) {
	console.log(num);
	const num = 20; //或者let num = 20;
} //会报错,因为由const和let在{}里面声明的num和整个块级作用域绑在一起了,在声明之前就使用会报错,    //而且不能访问{}外面的同名变量num

3-5闭包(closure)(GC):

指有权访问另一个函数作用域中变量的函数。(简单理解就是,一个作用域可以访问另外一个函数内部的局部变量)//闭包的主要作用:延伸了变量的作用范围。

function fn() {
	var num = 10;
    function fun() {
        console.log(num);
        //此时fun访问了fn作用域中的局部变量num
    }
    fun();
}
fn();

可以使以上代码中的内部函数fun在执行前,从外部函数返回。加一个return简化成以下代码

//fn外面的作用域也可以访问fn内部的局部变量。
function fn() {
    var num = 10;
    return function() {
        console.log(num);
    }
}
var f = fn();//此时在fn函数的外面也可以访问fn作用域里面的局部变量,局部变量也没有被销毁,因为在
f(); 		//fn函数的外面始终有一个f在等待着调用fn。
//类似于var f = function(){console.log(num);}

3-6 this:

①普通函数的this指向window

function fn() {
    console.log('普通函数的this' + this);
}
fn();
//但是在严格模式下全局作用域中函数中的this是undefined

②对象的方法:this指向的是该方法所属对象o

var o = {
 sayHi: function() {
 console,log('对象的方法this:' + this);
 }
}
o.sayHi();

③构造函数this指向实例对象tom,原型对象里面的this指向的也是实例对象tom

function Person() {};
Person.prototype.sing = function{};
var tom = new Person();

④绑定事件函数的this指向的是绑定事件对象btn

<button>点击</button>
var btn = document.querySelector('button');
btn.onclick = function() {
	console.log('绑定事件函数的this:' + this);
};

⑤定时器函数的this指向的是window

//应该在setTimeout前面加上window
setTimeout(function(){
	console.log('定时器的this:' + this)}1000);

⑥立即执行函数的this指向window

function(){
	console.log('立即执行函数的this' + this)})();

3-7改变函数内部this指向:

常用的有call(),apply(),bind()三种方法。

①call()方法调用一个对象。简单理解为调用函数的方式,同时它也可以改变函数的this指向。fun.call(thisArg, arg1, arg2…)

var o = {
	name: 'tom'
};
function fn(a, b) {
    console,log(this);
    console.log(a + b);
};
//call()里面不传参数o时this指向的是window,传了之后指向对象o,同时给定参数1,2进行计算
fn.call(o, 1, 2)//tom 3

call()的主要作用可以实现继承

function Father(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Son(name, age, sex) {
    //调用Father里面的属性,首先调用函数,然后修改this使其指向Son,同时传递参数
    Father.call(this, name, age, sex);
}
var son = new Son('tom', 18, '男');
console.log(son);

②apply()方法调用一个函数,简单理解为调用函数的方式,它可以改变函数的this指向。

fun.apply(thisArg, [argsArray]) thisArg:在fun函数运行时指定的this值, argsArray:传递的值,必须包含在数组里面。

var o = {
	name: 'tom'
};
function fn(arr) {
    console.log(this);
    console.log(arr);
};
fn.apply(o, ['参数必须是数组形式(伪数组)']);

**apply()的主要应用是:**与数组有关系,如可以利用apply借助于数学内置对象求最大值,最小值。

var arr = [1, 9, 3, 6, 5];
var max = Math.max.apply(Math, arr);
//指向函数max的调用者Math
var min = Math.min.apply(Math, arr);
console.log(max, min);//9

③bind()方法不会调用函数,但是能改变函数内部this指向。

fun.bind(thisArg, arg1, arg2, …) thisArg:在fun函数运行时指定的this值,arg1,arg2:传递的其他参数,返回由指定的this值和初始化参数改造的原函数拷贝

var o = {
    name: 'tom'
};
function fn(a, b) {
    console.log(this);
    console.log(a + b);
};
//不会调用原来的函数
var f = fn.bind(o, 1, 2);
//返回的是改变this之后产生的新函数
f();//返回o对象 和 3

有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向,此时用bind的方法最合适。

创建一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启
<button>点击</button>
var btn = document.querySelector('button');
btn.onclick = function() {
	this.disabled = true;//这个this指向的是btn
    setTimeout(function(){
        //不能直接写this.disabled = false;因为此时的this指向的是window。解决方法:
        //可以在setTimeout上面声明一个var that = this;然后在setTimeout里面将this改为
        //that.disabled,但是这种办法很麻烦要新开辟一块内存空间存放that。
        //最佳方法是在定时器函数的外面绑定bind()方法
        this.disabled = false;//加了bind方法之后this指向btn(点击对象)
    }.bind(this), 3000);
}