前端js中this指向及改变this指向的方法
js中this指向是一个难点,花了很长时间来整理和学习相关的知识点。
一、 this
this是JS中的关键字, 它始终指向了一个对象, this是一个指针;
参考博文:
二、 this显示绑定和隐式绑定
1. this显示绑定
含义: 当一个函数没有明确的调用对象的时候, 也就是单纯作为独立函数调用的时候, 将对函数的this使用默认绑定: 绑定到全局的window对象
在显式绑定下: 函数将取得在“ 包含对象“ 里的永久居住权, 一直都会” 住在这里“
1.1 全局函数
function fire() {
console.log(this === window); //fire此时是全局的方法,this指向window
}
fire(); // 输出true
1.2 函数内嵌套函数
function fire() {
// 我是被定义在函数内部的函数哦!
function innerFire() {
console.log(this === window); //未明确调用对象,this指向window
}
innerFire(); // 独立函数调用
}
fire(); // 输出true
innerFire();
示例:
var a = 1;
console.log(this.a); //1 因为此时this指向了window,因而调用1
function fire() {
var a = 2;
console.log(this.a); //1 因为此时this指向了window,因而调用1
function innerFire() {
var a = 3;
console.log(this.a); //1 因为此时this指向了window,因而调用1
}
innerFire();
}
fire(); //输出1
与作用域的区别: 全局作用域和局部作用域, 去掉this可发现区别
var a = 1;
console.log(a); //1 a在全局作用域
function fire() {
var a = 2;
console.log(a); // 2 fire函数作用域
function innerFire() {
var a = 3;
console.log(a); //3 此时打印输出a,a在innerFIre作用域。从自身作用域查找变量,未找到才网上查找
}
innerFire();
}
fire();
1.3 对象内层函数内部函数
var obj = {
fire: function () { //此时的fire函数其实用到了隐式绑定
function innerFire() {
console.log(this === window); //未明确调用对象,this指向window
}
innerFire();
}
}
obj.fire(); //输出 true
示例:
var a = 1;
console.log(this.a); //1 this指向全局变量window
var obj = {
a: 2,
fire: function () {
var a = 3;
console.log(this.a); //2 因为是obj.fire(),调用了fire函数,因为this指向了obj,输出了obj下的a=2
function innerFire() {
var a = 4;
console.log(this.a); //1 未明确调用对象,this指向window
}
innerFire(); //没有明确调用的对象
console.log(this.a); //2 this指向obj
}
}
obj.fire();
2、 this隐式绑定
a.隐式绑定
当函数被一个对象“ 包含” 的时候, 我们称函数的this被隐式绑定到这个对象里面, 这时候, 通过this可以直接访问所绑定的对象里面的其他属性, 比如下面的a属性
在隐式绑定下: 函数和只是暂时住在“ 包含对象“ 的旅馆里面, 可能过几天就又到另一家旅馆住了
var obj = {
a: 1,
fire: function () { //此时函数的this被隐式绑定到了对象obj
console.log(this == obj); // obj中有fire函数,因而默认this指向obj
console.log(this.a); // 1 this.a 相当于obj.a =1
}
}
obj.fire(); // 输出1
相同的方法:
fire函数并不会因为它被定义在obj对象的内部和外部而有任何区别,
function fire() {
console.log(this.a)
}
var obj = {
a: 1,
fire: fire
}
obj.fire(); // 输出1
b.动态绑定:
this实在代码运行期绑定而不是在书写期
var obj = {
a: 1, // a是定义在对象obj中的属性 1
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 2
obj.fire(); //1 此时fire的指向时obj
var fireInGrobal = obj.fire; //因为fireInGrobal是全局变量,this对于obj的绑定丢失,绑定到了全局window
fireInGrobal(); // 输出 2 输出全局变量啊
var a = 2;
var obj = {
a: 1, // a是定义在对象obj中的属性
fire: function () {
console.log(this.a)
}
}
function otherFire(fn) { //全局函数,this绑定window
fn();
}
otherFire(obj.fire); // 输出2 this对于obj的绑定丢失,绑定到了全局this上面
var obj = {
a: 1,
obj2: {
a: 2,
obj3: {
a: 3,
getA: function () { //obj3.getA() this绑定到了obj3当中
console.log(this.a)
}
}
}
}
obj.obj2.obj3.getA(); // 输出3
三、 this指向
this的指向不是由定义this决定的, 而是随脚本解析自动赋值的。
1. 全局环境作用域: this在全局环境始终指向window
变量形式
console.log(this === window) // true
console.log(window.alert === this.alert) // true
console.log(this.parseInt("021", 10)) // 21
var fruit = "banana"; // 定义一个全局变量,等同于window.fruit = "banana"
2. 函数环境 作用域: 函数由谁调用, this就指向谁
2.1 非严格模式
function fn() {
console.log(this); //window
}
fn() === window; // true;window.fn(),此处默认省略window
2.2 严格模式
a 全局环境下, this指向window
"use strict";
this.b = "MDN";
console.log(this == window) // "MDN"
console.log(b) // "MDN"
b 函数环境下, this为undefined
function fn() {
"use strict"; // 这里是严格模式
console.log(this); //window
}
fn() === undefined //true
3 对象中的方法函数调用: 指向 该方法所属的对象
隐式调用
var obj = {
a: 1,
fn: function () {
return this;
}
}
console.log(obj.fn() == obj); //true 函数被obj调用,指向obj
this动态绑定
var obj = {
a: 1,
fn: function () {
return this;
}
}
console.log(obj.fn()); //1 函数被obj调用,指向obj,输出obj的a=1
var a = 2;
var newfun = obj.fn; //此时更改this指向为全局变量newfun
newfun(); //2 ,this访问全局变量a=2
4 在构造函数中: this始终指向新对象
function Person(age, name) {
this.age = age;
this.name = name
console.log(this) // 此处 this 分别指向 Person 的实例对象 p1 p2
}
var p1 = new Person(18, 'zs')
var p2 = new Person(18, 'ww')
5 通过事件绑定的方法: this 指向 绑定事件的对象
oBtn.onclick = function () {
console.log(this); // btn
}
<
button id = "btn" > hh < /button>
6 定时器函数: 因为是异步操作, this 指向 window
延时函数内部的回调函数的this指向全局对象window( 当然我们可以通过bind方法改变其内部函数的this指向)
我们常见的window属性和方法有alter, document, parseInt, setTimeout, setInterval, location等等, 这些在默认的情况下是省略了window前缀的。( window.alter = alter)。
6.1 普通定时器
setInterval(function () {
console.log(this); // window
}, 1000);
6.2 定时器嵌套
function Person() {
this.age = 0;
setTimeout(function () {
console.log(this);
}, 3000);
}
var p = new Person(); //3秒后返回 window 对象
6.3 可以改变this指向 - 想见三方法
function Person() {
this.age = 0;
setTimeout((function () {
console.log(this);
}).bind(this), 3000);
}
var p = new Person(); //3秒后返回构造函数新生成的对象 Person{...}
7 自执行函数(匿名函数): 指向全局变量window
(function inner() {
console.log(this); //this ==> window
})();
8 箭头函数
要点:
a. 箭头函数的this是在定义函数时绑定的, 不是在执行过程中绑定的
b. 箭头函数中的this始终指向父级对象
c. 所有 call() / apply() / bind() 方法对于箭头函数来说只是传入参数, 对它的 this 毫无影响。
var obj = {
a: 1,
fn: () => {
//箭头函数中的this始终指向定义时的环境
//箭头函数中的this始终指向父级对象
console.log(this); //对象内的this调用时一般指向obj,而箭头函数在创建时就指向了obj的父级对象window
}
}
obj.fn(); //window
四、 更改this指向
每个Function构造函数的原型prototype, 都有方法
call(), apply(), bind()
总结:
a call(), apply()
在特定作用域调用函数
b bind()
会创建一个函数的实例, this会被绑定到bind() 函数
bing() 绑定this, bind()() 调用函数
1. call() 方法
var Person = {
name: "zhangsan",
age: 19
}
function aa(x, y) {
console.log(x + "," + y);
console.log(this);
console.log(this.name);
}
aa(4, 5); //this指向window--4,5 window 空
aa.call(Person, 4, 5); //this指向Person--4,5 Person{}对象 zhangsan
2. apply() 方法
apply() 与call() 非常相似, 不同之处在于提供参数的方式, apply() 使用参数数组, 而不是参数列表
var Person = {
name: "zhangsan",
age: 19
}
function aa(x, y) {
console.log(x + "," + y);
console.log(this);
console.log(this.name);
}
aa.apply(Person, [4, 5]); //this指向Person--4,5 Person{}对象 zhangsan
3. bind() 方法
bind() 创建的是一个新的函数( 称为绑定函数), 与被调用函数有相同的函数体, 当目标函数被调用时this的值绑定到 bind() 的第一个参数上
var Person = {
name: "zhangsan",
age: 19
}
function aa(x, y) {
console.log(x + "," + y);
console.log(this);
console.log(this.name);
}
aa.bind(Person, 4, 5); //只是更改了this指向,没有输出
aa.bind(Person, 4, 5)(); //this指向Person--4,5 Person{}对象 zhangsan
4. 存储this指向到变量中
var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
var _this = this; //将this储存在变量中,而且不改变定时器的指向
setTimeout(function () {
console.log(_this); //注意这里是_this,而不是this-- <div id="div1">点击</div>
console.log(this); //定时器的指向没有被改变--仍然是window
}, 1000)
}
五、 改变this指向综合案例**
1、 为更改this指向
var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
setTimeout(function () {
console.log(this); //点击时输出 window对象
}, 1000)
}
<
div id = "div1" > 点击 < /div>
2、 更改this指向 - bing, call, apply
在定时器外, 在绑定事件中的this肯定指向绑定事件的对象div啊, 用call和apply都行
var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
setTimeout(function () {
console.log(this); // 更改this指向为 <div id="div1">点击</div>
}.bind(this), 1000)
}
3、 存储this指向到变量中
var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
var _this = this; //将this储存在变量中,而且不改变定时器的指向
setTimeout(function () {
console.log(_this); //注意这里是_this,而不是this-- <div id="div1">点击</div>
console.log(this); //定时器的指向没有被改变--仍然是window
}, 1000)
}
前端js中this指向及改变this指向的方法的更多相关文章
- 关于javaBean中boolean类型变量的set和get注入后传到前端JS中的问题
set和get方法如下: public boolean isLine() { return isLine; } public void setLine(boolean isLine ...
- js中页面刷新和页面跳转的方法总结
.js中cookie的基本用法简介 2009-12-15 js中页面刷新和页面跳转的方法总结 文章分类:Web前端 关键字: javascript js中页面刷新和页面跳转的方法总结 1.histor ...
- js中页面刷新和页面跳转的方法总结 [ 转自欢醉同学 ]
.js中cookie的基本用法简介 2009-12-15 js中页面刷新和页面跳转的方法总结 文章分类:Web前端 关键字: javascript js中页面刷新和页面跳转的方法总结 1.histor ...
- js中的回调函数的理解和使用方法
js中的回调函数的理解和使用方法 一. 回调函数的作用 js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数. 二. 回调函数的解释 因为 ...
- 前端 ---JS中的面向对象
JS中的面向对象 创建对象的几种常用方式 1.使用Object或对象字面量创建对象 2.工厂模式创建对象 3.构造函数模式创建对象 4.原型模式创建对象 1.使用Object或对象字面量创建对象 ...
- JS中关于闭包和this的指向
闭包个人理解 函数内部还有一个函数,其作用就是可以访问上一层函数中的变量 下面的案例中函数内部有函数,this的指向就变为window了 结果闭包中this指向的两种方法 1.call对象冒充可以 ...
- [前端] js中call方法的理解和思考
最近接手前端的工作,对当前项目中自制的js框架下,js的使用产生了非常多的困惑.尤其是js的类,对象,函数,this等等相互之间的关系和转换,以前学过也忘得差不多了,现在基本相当于重新看. js中的函 ...
- 解读前端js中签名算法伪造H5游戏加分
信息安全在我们日常开发中息息相关,稍有忽视则容易产生安全事故.对安全测试也提出更高要求.以下是笔者亲自实践过程: 一. 打开某个数钱游戏HTML5页面,在浏览器 F12 开发工具中,查看的js,如下, ...
- js中slice(),splice(),split(),substring(),substr()的使用方法和区别
1.slice(): Array和String对象都有 在Array中 slice(i,[j]) i为开始截取的索引值,负数代表从末尾算起的索引值,-1为倒数第一个元素j为结束的索引值,缺省时则获取 ...
随机推荐
- 使用HANDLECOLLISIONS的几个场景
使用HANDLECOLLISIONS的几个场景: 1.target丢失delete记录(missing delete),忽略该问题并不记录到discardfile 2.target丢失update记录 ...
- git 和github 关联
创建本地仓库: 查看本地仓库配置信息: 如果没有配置,则进行配置: git config --global user.name "这里换上你的用户名" git config --g ...
- [HNOI2008]水平可见直线 单调栈
题目描述:在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.例如,对于直线:L1:y=x; L2:y=- ...
- nginx的Rewrite重写
location /{ if ($remote_addr=192.168.1.100){ //禁止此 ip 访问 ...
- POJ1201Intervals(差分约束)
题意 给出数轴上的n个区间[ai,bi],每个区间都是连续的int区间. 现在要在数轴上任意取一堆元素,构成一个元素集合V 要求每个区间[ai,bi]和元素集合V的交集至少有ci不同的元素 求集合V最 ...
- 【Hibernate步步为营】--多对多映射具体解释
上篇文章具体讨论了一对多映射,在一对多映射中单向的关联映射会有非常多问题,所以不建议使用假设非要採用一对多的映射的话能够考虑使用双向关联来优化之间的关系,一对多的映射事实上质上是在一的一端使用< ...
- 当我们谈论Erlang Maps时,我们谈论什么 Part 1
Erlang 添加 Maps数据类型并非非常突然,由于这个提议已经进行了2~3年之久,仅仅只是Joe Armstrong老爷子近期一篇文章Big changes to Erlang掀起不小了 ...
- IDEA中的maven web 项目中如何设置自己的本地仓库
我们在创建maven项目的时候如何不使用系统指定的本地仓库,而使用自己设置的仓库呢,这里小女子就来进行讲解一下吧! 讲解一:你要想找到settings.xml你就要自己我去官网上去下载apache-m ...
- 解决Android Studio 2.2.3中添加.cpp .h文件在Project->Android无法显示,无法正常编译问题。
搭配使用 Android Studio 2.2 或更高版本与 Android Plugin for Gradle 版本 2.2.0 或更高版本时,您可以将 C 和 C++ 代码编译到 Gradle 与 ...
- 如何组织CSS?
前端工程师在开发一个单页面或者小网站的时候有可能不会在意CSS的组织问题,但如果要开发一个中大型的网站,就要好好的组织CSS文件,不然会增加维护成本,整个网站的结构也没条理性. 如何组织CSS?一般常 ...