1.0 了解js的调用模式
在 js 中,无论是函数, 还是方法, 还是事件, 还是构造器…这些东西的本质都是函数,其中的区别只是所处的位置不同。根据函数内部this的指向不同,可以将 函数的调用模式 分成4种:函数模式、方法模式、构造器模式和上下文模式等四种不同的调用模式。
2.0 了解this指向问题
2.0.1 ----分析this指向问题:
- 任何函数都有属于自己的this
- this的指向和函数的调用模式相关,意味着this的指向在函数声明的时候确定不了
2.0.2—分析this指向的思路
- 这个this属于哪一个函数
- 这个函数的调用模式是哪一种
2.0.3—举个例子
var name = '测试名称'
var age = 18
function test() {
console.log( '我是测试者,我叫'+this.name+',今年'+this.age+'岁了')
}
var obj = {
name: '小峰',
age: 22,
myIntroduce: function() {
test();
console.log('我是'+this.name+',今年'+this.age+'岁了')
}
}
// 执行调用函数
obj.myIntroduce();
/**
* 1.0 输出结果为 我是测试者,我叫测试名称,今年18岁了 我是小峰,今年20岁了
* 2.0 分析结果:
* 为什么两个函数的执行结果不一样呢?
* 步骤一: 分析 test() 的函数调用模式为函数模式(简单的函数调用,函数名前面没有任何引导内容)
* 函数里面的this 的含义: 在 函数中 this 表示全局对象, 在浏览器中this表示window,也可以换种方式
* 理解: test() 函数调用模式为上下文调用模式,等价于 test.call(),call中的context(上下文)未填,
* 在浏览器环境中默认为 window 对象。obj.myIntroduce()也可以理解为上下文调用(其实是方法调用模式)
* 即等同于obj.myIntrodece.call(obj),方法中myIntrodece中的this为obj
*/
3.0 四种调用模式的概念以及理解
3.0.1—函数模式
特征:简单的函数调用,函数名前面没有任何引导内容。
function fn() {}
var fn2 = function() {}
fn(); // 简单的函数调用,函数名前没有任何引导内容
fn2();
(function(){})(); // 函数自调用,也是函数模式
this 的含义: 在 函数中 this 表示全局对象, 在浏览器中this表示window。 值得注意的是任何自调用函数都是函数模式
3.0.2—方法模式
特征:方法一定是依附于一个对象,将函数赋值给对象的一个属性,那么就成为了方法。
var obj = {
name: '小峰',
age: 22,
myFn: function() {
console.log(this.name)
}
}
obj.myFn(); // this指向为obj
var arr = [3,1,3]
arr.slice(1) // slice方法中的this指向为arr
this的含义:这个依附的对象,注:arguments 这种伪数组, 或者 [] 数组这样的对象中, 调用函数也是方法模式,
this 指向这个对象
3.0.3—构造器模式
特征:
a. 使用new关键字实例化(创建)一个对象
b.将构造函数中的this 指向 刚创建的对象
c.在构造函数中会默认的 return this
function Animal(type,name) {
this.type = type
this.name = name
console.log(this)
}
var dog = new Animal('中华田园犬','阿汪') // 把this指向交给dog, 执行结果为 Animal {type: "中华田园犬", name: "阿汪"}
console.log(dog) // Animal {type: "中华田园犬", name: "阿汪"}, 说明返回了this
console.log(dog.name) // 阿汪
console.log(dog.type) // 中华田园犬
3.0.4—上下文模式
特征:上下文调用模式也叫方法借用模式,分为apply与call,上下文 就是环境, 就是自定义设置this的含义
语法:
函数名.apply(对象,[参数]); 值得注意的是方法也是函数
函数名.call(对象,参数);
描述:
函数名就是表示的函数本身, 使用函数进行调用的时候默认 this 是全局变量 ,fn() 等同于 fn.call(context) ,context在浏览器环境中默认为 window
函数名也可以是方法提供, 使用方法调用的时候, this 是指当前对象. obj.fn() 等同于 obj.fn.call(obj)
使用apply或者call进行调用后, 无论是函数,还是方法都无效了。我们的 this, 由apply或者call的第一个参数决定
var name = '小峰'
var obj = {
name: '小峰2'
}
function fn1() {
console.log(this.name)
}
fn1(); // 小峰
fn1.call(obj ) // 小峰2, 使用了call方法调用后,fn函数模式调用被call改为上下文模式调用,修改了this指向
扩展: 伪数组借用数组的方法
var arrF = {
0:"嘻嘻",
1:"哈哈",
2:"呵呵",
length:3
}
Array.prototype.push.call(arrF, "哼");
Array.prototype.join.call(arrF, "哈");
扩展: this的默认绑定
默认绑定
默认绑定是函数针对的独立调用的时候,不带任何修饰的函数引用进行调用,非严格模式下 this 指向全局对象(浏览器下指向 Window,Node.js 环境是 Global ),严格模式下,this 绑定到 undefined ,严格模式不允许this指向全局对象。
扩展: 小测试 ≧◔◡◔≦
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function (fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);
// 输出结果是 10,1
/**
* 分析如下:
* obj.method(fn,1) 执行到 fn() 时,fn() 的函数调用模式是函数模式。this指向在浏览器中默认为window,即函数上下文为 window,所以fn() 输出的值为 10
* 执行到 arguments[0]() 时, 需要注意的是 arguments是伪数组(也是对象类型),即函数的执行方式为方法模式
* 即argument.0(),所以 0 方法中的this指向为arguments对象 ,arguments对象的值为 {0:fn, 1: 1, length: 2}
* 所以 arguments[0]() 输出 2
*
*/
总结: 关于函数的this指向,取决于函数的调用模式,函数模式调用,函数中的this指向在浏览器中默认为window。方法调用模式,函数中的this指向为依附的对象, 构造器调用模式,构造函数中的this指向实例化对象, 一旦使用上下文模式,前面提到的模式中的this指向都取决于上下文指定的this指向