函数进阶
定义函数的三种方式
- 函数声明
fn();//函数声明可以先调用,在声明
function fn(){
console.log("这是函数声明")
}
- 函数表达式
var fn = function() {
console.log("这是函数表达式");
}
fn();//函数表达式必须先声明,再调用
- 构造函数Function
//函数也是对象,可以使用Function构造函数new出来
//相当于var fn = function(){}
var fn = new Function();
//语法:new Function(arg1,arg2,arg3..,body);
// 1\. 所有的参数都是字符串类型。
// 2\. 前面可以定义任意多个形参,最后一个参数是代码体。
var fn = new Function("alert(1111)");
fn();
var fn1 = new Function("a1", "a2", "alert(a1+a2)");
fn1(1,2);
函数也是对象
- 函数是由new Function创建出来的,因此函数也是一个对象,所有函数都是new Function的实例
Function.prototype常用成员
- call:调用函数,重新指向this
- apply:调用函数,重新指向this
- bind:重新指向this,返回一个新的函数,不调用
完整版原型链
- 所有函数都是new Function创建出来的,因此 所有函数.proto都是Function.prototype
- 所有对象都是new Object创建出来的,因此 所有对象.proto都是Object.prototype
作用域
- 变量起作用的区域,变量定义后,可以在哪个范围内使用
- 在js中只有全局作用域和函数作用域
- 函数作用域在函数定义的时候作用域就定下来了,和函数在哪调用无关
作用域链
- 只要是函数,就会形成一个作用域,如果这个函数被嵌套在其他函数中,那么外部函数也有自己的作用域,这个一直往上到全局作用域,就形成了一个作用域链
变量搜索原则
- 从当前的作用域开始查找,存在即返回
- 不存在,就往上一层找,存在即返回
- 一直查询到全局作用域,存在即返回。没有就报错
函数调用的四种模式
- 根据函数内部的this指向不同,可以将函数的调用模式分为4类
- 函数调用模式
如果一个函数不是一个对象的属性时,就是被当作一个函数来进行调用,此时this指向window
function fn(){
console.log(this);//指向window
}
fn();
-
方法调用模式
当一个函数被保存为对象的一个属性时,我们称之为方法。当一个方法被调用时,this被绑定到当前对象
var obj = {
sayHi:function(){
console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
}
}
obj.sayHi();
-
构造函数调用模式
如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上
function Person(){
console.log(this);
}
Person();//this指向什么?
var p = new Person();//this指向什么?
-
上下文调用模式
a. 函数.call():可以调用一个函数,并且可以指定这个函数的this指向
b. 函数.apply():和call()的作用类型,此方法接收的参数是一个包含多个参数的数值
c. 函数.bind():创建一个新的函数,可以绑定新的函数的this指向
//所有的函数都可以使用call进行调用
//参数1:指定函数的this,如果不传,则this指向window
//其余参数:和函数的参数列表一模一样。
//说白了,call方法也可以和()一样,进行函数调用,call方法的第一个参数可以指定函数内部的this指向。
fn.call(thisArg, arg1, arg2, arg2);
// 返回值:新的函数
// 参数:新函数的this指向,当绑定了新函数的this指向后,无论使用何种调用模式,this都不会改变。
var newFn = fn.bind(window);
补充
-
几种特殊的this指向
- 定时器的this指向window,因为定时器的function最终由window来调用
- 事件中的this指向的是当前的元素,在事件触发的时候,浏览器让当前元素调用了function
-
伪数组与数组
- 伪数组其实就是一个对象,但是和数组一样有length属性,也有0,1,2,3等属性
- 伪数组没有数组的方法,不能使用push等方法
- 伪数组可以跟数组一样进行遍历,通过下标操作
- 常见的伪数组:arguments,document,getElementByTagName的返回值,jQuery对象
我们可以让伪数组借用数组方法
var arrayLike = {
0:"张三",
1:"李四",
2:"王五",
length:3
}
//伪数组可以和数组一样进行遍历
Array.prototype.push.call(arrLike, "赵六");