面向对象程序设计(番外篇)
前面的章节里面,我们已经学习过面向对象的基础,知道怎么去创建对象,以及对对象的属性的遍历 。同时还知道了一个新的关键字叫this
。这个关键字使用的频率非常高,后面只要是接触对象或者是方法都会使用到这一个关键字
this关键字
this
是一个任人打扮的小姑娘
this
它是一个关键字,也是一个指针,具体指的是什么则要看这个关键字指向了谁,它指向了谁就指的是谁,现阶段而言我们可以把this看成是一个指针
对象中的this
我们之前在创建对象的的时候是使用了this的,现在就来具体的年一下这个this
在对象中的应用
var name = "标哥哥"; //全局变量
var stu1 = {
name:"杨兰芳",
sayHello:function(){
console.log("大家好,我叫"+this.name);
}
};
在上面的代码里面,我们可以看到sayHello
这个方法里有一个关键字this
,那么这个里面的this
指向的是谁呢??
我们之前很笼统的给同学们说一点就是this指向当前对象。关键问题又来了,这个当前对象是谁呢
- 在全局环境下面,
this
指向是window
这个对象
- 在自定义对象里面
this
指向当前调用这个方法的对象
当前这个sayHello()
的方法是被对象stu1
在调用,所以this
指的就是stu1
根据上面的第一个特点,全局环境的this是指向window这个特点,我要补充以下几个知识
之前在讲解变量的时候,我们告诉同学,全局变量使用
var
关键字来进行定义。其实全局变量还可以用另外一种方式去理解(就是使用面向对象的方式去理解)在JavaScript里面,一切皆对象,所以我们可以这么理解,window就是浏览器的最高对象,所以的东西都在这个window下面,我们如果在全局环境下面定义变量,其实就是在window这个对象下面给它添加了一个属性
var userName = "标哥哥";
上面的代码是定义了一个全局变量,其实全局变量本质上面是经过下面的这个过程
window.userName = "标哥哥";
这就是为什么我可以通过
this.name
去拿到定义的全局变量name
,因为在全局环境下面this
是指向了window 的,所以this.name
指的也就是window.name
,而window.name
就是全局变量name
?思考 :现在根据上面的特点,我们来思考下面的代码的结果是什么??
var name = "标哥哥"; //全局变量
var stu1 = {
name:"杨兰芳",
sayHello:function(){
console.log("大家好,我叫"+this.name);
}
};
stu1.sayHello(); //输出什么? //杨兰芳
var s = stu1.sayHello; //将这个方法赋值给另一个变量
s(); //再去调用s这个方法 //标哥哥
首先要经过分析
var s = stu1.sayHello
其实就相当于window.s = stu1.sayHello
。接下开始调用
s()
其实就相当于window.s()
根据我们之前的原则 ,对象方法里面的
this
是指向调用这个方法的对象的,现在这个方法是被window
在调用,所以里面的this
应该要指向window
构造函数里面的this
函数也叫方法,在面向对象的观点里在,函数就是方法
之前的时候,我们学过构造函数去创建对象,在构造函数里面也有this
。它的this
又指向了谁呢?
var userName = "标哥哥";
//这是一个全局的方法,所以相当于window.Person
/*
window.Person = function(){
}
var Person = function(){
}
*/
function Person() {
console.log(this);
}
构造函数本质上面与普通是没有区别的,关键是看它的调用方式,如果使用new的关键字调用,则是构造方法调用
Person(); //本质上面就是window.Person()这种方式调用
//现在是window在调用Person方法,所以这个方法内部的this就指向了window
new Person(); //构造函数在调用,构造函数里面的this指向当前创建的这个对象
经过上面的两个章节以后,我们都this
其实是可以发生改变的。现在我们就来看一下方法里面的this
的转移问题
方法以不同的形式去调用,this
的指向也就不一样。(上面已经讲了一个构造方法,现在还有没有其它的方法呢)
函数的不同调用形式决定this指向【重点】
刚刚我们通过构造函数改变了this的指向,其实还有函数还有另外的几种方式也可以调用
我们之前已经讲过很多种函数的调用方式了,现在回顾一下
- 方法名+()调用
- var 方法名 = function(){}() 立即调用
- +function(){}()立即调用
- new function(){} 构造函数调用
除了上面的四种方式以外,我还有另外的三种方式调用方法。这三种方式都可以改变this的指向
通过call来调用方法
通过方法名.call(this指向,...原来方法里在的参数)
var userName = "标哥哥全局变量";
function sayHello(str) {
console.log(str);
console.log(this.userName);
}
var stu1 = {
userName: "杨兰芳"
};
var stu2 = {
userName: "赵聪"
};
sayHello("普通调用"); //标哥哥 window.sayHello(); this指向window\
sayHello.call(window,"我在通过call去调用");
sayHello.call(stu1,"我现在也在通过call去调用");
sayHello.call(stu2,"我是stu2在调用sayHello的方法");
第一种现象 | 第二种现象 |
---|---|
通过call
的这种形式,我们可以手动的把这个方法this
改变掉
通过apply来调用方法
这一种调用方式跟call
的调用方式是一模一样的,唯一不同的区别就在于原来方法里面的参数
var userName = "标哥哥";
function sayHello(str1, str2) {
console.log(str1);
console.log(str2);
console.log(this.userName);
}
var stu1 = {
userName:"杨兰芳"
};
// sayHello("第一个参数","第二个参数") 以常规的方式去调用
// sayHello.call(stu1,"第一个参数","第二个参数");
//通过apply调用
sayHello.apply(stu1,["第一个参数","第二个参数"])
下面是call调用的图
下面是apply调用的图
call
与apply
唯一的区别点就是在这个地方apply的参数要变成要变成一个数组
通过bind
来调用函数
bind
方法与上面的call
和apply
的作用是一样的,都是用于调用方法的时候改变方法的this,但要是要注意,bind
方法在调用的时候,它不会立即执行原来的方法,而是会返回一个新的方法名,通过新方法名再去调原来的方法
语法格式:Function.bind(thisArg:object,...原来函数的参数)
var userName = "张三";
function abc() {
console.log(this.userName);
}
var stu = {
userName: "蒋晓菁"
}
abc(); //张三
var def = abc.bind(stu); //bind会返回一个新的方法,新的方法的this才是你bind的这个对象
def(); //这个def是通过abc.bind(stu)得到的,所以def里面的this指向的是stu
def方法是通过
abc.bind(stu)
得到的,所以def
方法里面的this指向的是stu
这个对象
刚刚上面执行的bind是一个没有参数的方法,如果这个方法有参数呢,那应该怎么写呢?
var userName = "张三";
function abc(x, y) {
console.log(arguments);
console.log(this.userName, x, y);
}
var stu = {
userName:"李四"
}
abc(10, 11);
var d = abc.bind(stu,99,100);
d();
var e = abc.bind(stu,200);
e(300);
var f = abc.bind(stu);
f(500,501);
var g = abc.bind(stu,600,601);
g(602,603); //最终的arguments会接收到4个参数
评论区