介绍
每一个函数在运行的时候都会创建一个独有的活动对象
- 在活动对象中包含函数的参数,以及函数函数的调用模式内部的声明数据
- 除了定义参数与声明的变量与函数外,在这个活动对象上还存在一个叫做上下文(context)的东西
- 函数的七种调用模式
在js中this的意义:
- 记住 this在什么情况下表示什么东西
- 通过对代码分析,我们可以定位是哪一种情况,能分析出是哪种意义
- 总结: 函数内部的this,是由函数调用的时候来确定其指向的
函数的七种调用模式
- 函数模式:this表示全局对象(浏览器中是window,在node中是global)
- 构造器(constuctor)模式:this表示刚刚创建出的对象
- 方法(method)模式:this表示引导方法调用的对象
- 上下文(context)模式:this可以使用参数来动态的描述,每次调用可以传入不同的对象作为this(动态绑定)
- bind模式:this与上下文模式类似,也是通过参数来确定,一开始就绑定,然后在使用的时候就不需要绑定,每次使用的时候都是最开始绑定的那个this(静态绑定)
- 作为事件的处理函数: 触发该事件的对象
- 作为定时器的参数: 指向window
举例
- 函数模式
- 特点:独立的运行,调用语法格式前没有任何引导数据
function foo(){
console.log("函数模式")
}
foo()
- 构造器模式
- 语法 new 构造函数()
- 先使用 new 运算符 分配内存空间,在js中就是创建对象(一个空的对象,一个具有原型结构的对象)
- 空对象表示没有自己的任何成员
- 具有原型结构,该对象的原型(__ prop__)是Person.prototype
- 调用构造函数
- 创建活动文对象
- this创建的对象的引用会作为活动对象中的上下文对象被引用
- 预解析
- 解释执行等等
function Person(){}
var p = new Person()
- 方法调用模式
- 一个函数作为对象的一个成员,由对象引导调用,这个调用就是方法调用
- 表现就是调用前有一个引导数据:满足通过xxx访问到方法名调用
- demo4 需要特别注意下
//demo1
var obj1 = {
say:function(){console.log(this)}
};
obj1.say();
//demo2
function foo(){
console.log("这是什么调用",this)
}
var obj2 = {name:obj2};
obj2.fn = foo;
obj2.fn(); //方法调用,通过obj2引导的函数再调用
foo();//函数
//obj.fn 与 foo是什么关系呢?
//他们是完全一样的东西,但执行结果不同,即this不同
demo3
var arr = [];
arr.push(foo);
var fn = arr[0];
fn();//是什么调用呢? 函数调用模式
arr[0]()//这又是什么调用呢? **方法调用模式** arr的引导
//demo4
var obj3 = {
name:"deno4",
say:function(){console.log("这是什么调用",this)}
};
obj3.say();//方法
var fn = obj3.say;
fn();//函数
//特别
var f;
(f = obj3.say)();//面试题遇到过 函数模式
(obj3.say)()//方法
//词法分析 运行原理
//赋值运算 分为:
//1. 将 等号 右边的值取出来(求出),取出的东西与原本的东西并不相同
//2.将取出的数据 存储到 等号 左边 的变量表示的容器中
//赋值表达式的值就是取出的那个值
//所以此时就是在调用取出的那个东西
- 上下文模式
- 函数名.call(上下文,参数1,参数2,...) 可以任意个参数
- 函数名.apply(上下文,[参数1,参数2,...]) 最多二个参数
- 无论是函数正常调用,还是call调用,还是apply调用其实都是在调用函数
- 函数执行的时候会创建活动对象,活动对象中会存在一个上下文 就是函数中的this
- call和apply方法的第一个参数就是决定上下文的东西也就是this
- 如果传入的是 引用类型,除了null外就是表示this
- 如果传入的是基本类型(数字,布尔,字符串),它们会自动转为包装类型
- 如果传入的是空(null,undefined),那么上下文就是全局对象
- 如果call与apply不传入任何参数,就相当于函数调用
- 如果如果call与apply只传入一个参数,那么相当于方法调用
- call与apply除了第一个参数外,其他的所有参数都是与原函数参数相对应的,只是形式不同
- call从第二个参数开始,描述的就是正常函数调用时需要提供的参数
- apply的第二个参数是数组的形式,用数组的形式描述正常函数的参数
- 运用:主要是借用与展开
- 比如Array.prototype.slice.call(伪数组)就能够借助数组的slice方法给伪数组使用等
- 比如借用Math.max()求数组的最大值 Math.max.apply(Math,arr)
function foo(){
console.log("这是什么调用",this)
}
foo(); //this-->window
foo.call(); //this --> window
foo.call({name:'obj1'});//this --> {name:'obj1'}
foo.apply();//this-->window
foo.apply({name:'obj2'});//this --> {name:'obj2'}
//
- bind模式
- func.bind(context, arg1, arg2, ...)//返回的是已经绑定this的新函数
document.querySelectorAll('a')
var $selectAll = document.querySelectorAll.bind(document);
$selectAll('a')