JavaScript OOP(二):this关键字以及call、apply、bind
JavaScript的this关键字非常灵活!
var o1={
name:'apple',
age:100,
msg:function(){
return '显示name和age信息:'+'name: '+this.name+', age: '+this.age;
}
};
//针对msg中的this进行研究:
console.log(o1.msg());//this 指向当前对象o1
var o2={
name:'blue',
age:1000
};
o2.msg=o1.msg;
console.log(o2.msg());//this 指向当前对象o2
当o1.msg()时,this指向o1;而o2.msg()时,this指向o2。也就是this指向的是“当前”环境运行时所在的对象。
运行结果:

将函数提出来,更形象的表示:
console.log('---');
function f(){
console.log(this.name1);
}
var o3={
name1:'alice',
info:f
};
var o4={
name1:'boy',
info:f
};
f();//undefined
o3.info();//alice
o4.info();//boy
f():this指向顶层对象window;o3.info():this指向的是o3;o4.info():this指向的是o4。即this总是指向“当前”运行时所在的对象。
运行结果:

如果我们在全局环境中,将对象中的方法赋值给变量。以本文最上面代码o1.msg示例:
var name='abc';
var age=1;
var test1=o1.msg;
console.log(test1());//此时this指向顶层对象window
此时test1():this指向的是window
运行结果:

由上面的这些例子,我们可以“粗略”的认为:每个函数中都存在着this,它总是指向当前运行环境的对象。
全局环境下的this:指向顶层对象window
function test2(){
if(this === window){
console.log('此时this 指向顶层对象window');
}
}
test2();
运行结果:

function Test3(num){
this.num=num;
}
var t3=new Test3(100);
console.log(t3.num);//this 指向t3
Test3.prototype.m=function (){//所有由Test3构造函数生成的实例化对象都共享m方法
return this.num;
};
console.log(t3.m());//this 指向t3
运行结果:

注意下面这种情况:
var o5={
name:'application',
send:function(){
console.log(this
);
}
};
o5.send();//o5
(o5.send=o5.send)();//window
/**
* 相当于
* (o5.send=function(){
* console.log(this);
* })
*/
(false||o5.send)();//window
/**
* 相当于
* (false || function(){
* console.log(this);
* })
*/
(1,o5.send)();//window
/**
* 相当于
* (1,function(){
* console.log(this);
* })
*/
即:除非直接使用o5.send(),结果返回当前对象;否则均返回顶层对象window
运行结果:

如果方法位于多层对象的内部,那么this指向当前对象层,不会继承更上面的层:
var o6={
name:'cat',
f:{
f1:function (){
console.log(this.name);
console.log(this==o6.f);//其实this指向的是o6.f
}
}
};
o6.f.f1();//undefined
//因为此时this指向的是f
上面代码中o6对象中f属性对应的值,是一个对象。该对象里面又存在着一个函数,此时函数里面的this指向o6.f,而不是o6
运行结果:

如果想达到预期的效果:
var o6={
name:'cat',
f:{
f1:function(){
console.log(this.name);
},
name:'cat'
}
}
o6.f.f1();//cat
继续进行变通:
//将o6.f.f1赋值给变量
var v=o6.f.f1;
/**
* 相当于
* var v=function (){
* console.log(this.name);
* }
*/
v();//this指向的对象又指向了顶层对象window
//将o6.f赋值给变量
var v1=o6.f;
v1.f1();//此时返回的结果为'cat'
/**
* 相当于
* var v1={
* f1:function(){
* console.log(this.name);},
* name:'cat'
* };
*/
同时应尽量避免在函数中使用多层this:
//尽量避免在函数中使用多层this
var o7={
name:'apple',
f:function(){
console.log(this);//this指向当前运行环境对象,即o7
var f1=function(){
console.log(this);//this指向顶层对象,即window
}();//IIFE;这是立即调用的函数表达式
}
};
o7.f();
运行结果:

为了让f1中的this也指向该对象:添加一个临时变量作为辅助:固定this。
var o8={
name:'apple',
f:function(){
console.log(this);//this指向o8
var that=this;//使用变量固定this
var f1=function(){
console.log(that);//此时that指向o8
}();
}
};
o8.f();
运行结果:

当然如果采用严格模式,那么函数内部this不能指向顶层对象window!
call():调用函数,指定this指向的对象;第一个参数是this指向的对象,第二个、第三个等是函数调用的参数
var o9={
name:'orange'
};
function test4(){
console.log(this);
}
test4();
test4.call(o9);//指定this的指向
//call方法中如果参数为空、null\undefined,那么默认指向全局对象window
test4(null);
test4(undefined);
//call方法第一个参数是this指向的对象,后面的参数是函数调用时用到的参数
运行结果:

call的一个应用:调用对象原生方法,即使该方法被覆盖
var o10={};
console.log(o10.hasOwnProperty('toString'));
o10.hasOwnProperty=function(){
return true;
};
console.log(o10.hasOwnProperty('toString'));
//this指向o10,这样方法被覆盖,依然能够调用对象的原生方法
console.log(Object.prototype.hasOwnProperty.call(o10,'toString'));
运行结果:

apply():作用与call()类似,第一个参数也是this指向的对象;不同的是函数调用的参数以数组形式传入
//apply与call作用类似,只是apply传入的参数是以数组形式传入
//同理,第一个参数是this指向的对象,空或null或undefined,默认是全局对象window
function test6(a,b){
console.log(a+b);
}
test6.call(null,1,10);//test6(1,10)
test6.apply(null,[10,100]);//test6(10,100)
var arr=[1,2,3,4,5];
console.log(Math.max.apply(null,arr));//this指向window,arr调用Math.max方法
console.log(Array.prototype.slice.apply({0:1,1:100,length:2}));//类似数组的对象调用方法变为数组
运行结果:

bind():将this绑定到某个对象,返回一个新函数(相较于call,apply的函数立即执行)
//bind将this绑定到某个对象,并返回一个函数
var o10={
fruit:'apple',
f:function(){
console.log(this.fruit);
}
};
o10.f();//正常取值
console.log('---');
var a=o10;
a.f();//这样也能正确取值
var b=o10.f;
b();//这样取值就不行了;undefined
/**
* 此时this指向全局对象window,上面相当于
* var b=function (){
* console.log(this.fruit);//this指向window
* }
*/ //绑定this指向o10
var c=o10.f.bind(o10);
c();//此时能够正确取值
运行结果:

bind还能绑定函数的参数:
//bind还可以绑定函数的参数
var o10={
name:'apple',
age:100
};
function test7(x,y){
console.log(x,this.name,y,this.age) ;
}
var t5= test7.bind(o10,'姓名信息: ');//绑定第一个参数,返回t5这个新函数
t5(' 年龄信息: ');
运行结果:

JavaScript OOP(二):this关键字以及call、apply、bind的更多相关文章
- JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--前戏
new关键字,call/apply/bind方法都和this的绑定有关,在学习之前,首先要理解this. 一起来学习一下this吧 首先.this是一个对象. 对象很好理解,引用类型值,可以实现如th ...
- JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--实现
先学习下new操作符吧 new关键字调用函数的心路历程: 1.创建一个新对象 2.将函数的作用域赋给新对象(this就指向这个对象) 3.执行函数中的代码 4.返回这个对象 根据这个的思路,来实现一个 ...
- javascript oop深入学习笔记(二)--javascript的函数
一.概述: 函数是进行模块化程序设计的基础, javascript重的的函数不同于其他语言,每个函数都作为一个对象被维护和运行.通过函数对象的性质,可以很方便的将一个函数赋值给一个变量或则讲函数作为参 ...
- 转载 深入理解JavaScript中的this关键字
转载原地址: http://www.cnblogs.com/rainman/archive/2009/05/03/1448392.html 深入理解JavaScript中的this关键字 1. 一 ...
- JavaScript中的this关键字的用法和注意点
JavaScript中的this关键字的用法和注意点 一.this关键字的用法 this一般用于指向对象(绑定对象); 01.在普通函数调用中,其内部的this指向全局对象(window); func ...
- 如何理解JavaScript中的this关键字
前言 王福朋老师的 JavaScript原型和闭包系列 文章看了不下三遍了,最为一个初学者,每次看的时候都会有一种 "大彻大悟" 的感觉,而看完之后却总是一脸懵逼.原型与闭包 可以 ...
- 玩转JavaScript OOP[4]——实现继承的12种套路
概述 在之前的文章中,我们借助构造函数实现了"类",然后结合原型对象实现了"继承",并了解了JavaScript中原型链的概念. 理解这些内容,有助于我们更深入 ...
- 深入理解OOP(二):多态和继承(继承)
本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时 ...
- Javascript oop深入学习笔记(三)--javascript中类的实现
一.类的实现机制 在javascript中可以使用function关键字来定义一个类.在函数内通过this指针引用的变量或则方法都会成为类的成员. function classDemo(){ var ...
随机推荐
- Zookeeper 笔记-watch
ZooKeeper对Watch提供了什么保障 对于watch,ZooKeeper提供了这些保障: Watch与其他事件.其他watch以及异步回复都是有序的. ZooKeeper客户端库保证所有事件都 ...
- poi入门之读写excel
Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能.该篇是介绍poi基本的 ...
- Appium python自动化测试系列之页面滑动原理讲解(十)
10.1.1 页面滑动原理分析 在页面滑动查找章节我们就讲了滑动的知识点,只是不知道大家是否有认真练习以及去理解,如果你认真练习.理解了那么我相信这一章节的东西不用看也能够完成,下面我们还是简单分析一 ...
- 聊聊 Material Design 里,阴影的那些事儿!
当你的设计师要求你在某个 View 上增加阴影效果,那你只需要认真阅读本文,阴影的问题就不再是问题. 一.前言 设计师的世界,与常人不同,有时候想要扁平化的风格,有时候又想要拟物化的风格.而在 Mat ...
- TreeView简单的动态加载数据
简单的小记录,省得去看控件属性详情了,基本常用的属于就几个 先是判断根节点是否存在控件中,如果不存在则创建,之前要添加了节点同样的方法 把根节点传到子节点的方法中,再判断是否在根节点里存在子节点,如果 ...
- web前端工程师全套教程免费分享
这是我自己早前听课时整理的前端全套知识点,适用于初学者,也可以适用于中级的程序员,你们可以下载下来.我自认为还是比较系统全面的,可以抵得上市场上90%的学习资料.讨厌那些随便乱写的资料还有拿出来卖钱的 ...
- 使用jQuery中trigger()方法自动触发事件
一.常用事件 在页面加载完成时 自动触发input的点击事件,在移动端可以实现自动弹出输入法,获得焦点 $("input").trigger("click") ...
- C++ new 解析重载
C++ new 解析重载 new的三种形式: (1)operator new(运算符new) (2)new operator(new 操作) (3)placement new(特殊的new操作)(不分 ...
- HDU 4291 A Short problem(矩阵+循环节)
A Short problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- Android 开发笔记___Activity的生命周期
一个activity就是一个页面,入口函数是oncreate(). onCreate:创建页面,把页面上各个元素加载到内存 onStart:开始页面,把页面显示在屏幕 onResume:恢复页面,让页 ...