this指向 - 浏览器环境
1.全局上下文中的 this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>this 指向</title>
</head>
<body>
<script type="text/javascript">
/*
1.全局上下文中的 this 浏览器环境下: 严格模式下: Window 非严格模式下: Window
*/ 'use strict'; // 严格模式
// demo 1:
console.log(this); // demo 2:
var a = this;
console.log(a); // demo 3:
b = this; // 注意:严格模式下,变量必须得声明;非严格模式,可以省略声明符
console.log(b); /*
分析:
浏览器环境下: 在整个 执行上下文 创建过程,都是在 全局执行环境下进行的,而这种由全局执行环境创建的执行上下文,又叫 “全局执行上下文”; 而在 Web浏览器中,全局执行环境被认为是 window对象; 结果 输出了 Window对象,也就说 this 指向了“执行上下文的环境对象”; 所以,结论 “this 指向其执行上下文的环境对象”,通过; */
</script>
</body>
</html>
2.函数上下文的 this
严格模式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>this 指向</title>
</head>
<body>
<script type="text/javascript">
/*
2.函数上下文中的 this 浏览器环境下: 严格模式下
*/
// demo :
'use strict'; // 严格模式
var a = 1;
// demo 1:
function test1(){
console.log(this);
}
test1(); // strict-->undefined nostrict-->Window /*
首先,要了解一点,函数的 this指向,有些特殊; 它与全局环境中的 this 不一样,因为全局中的 this 已经明显指出了它的执行上下文环境就是 全局环境,那么它的 this 一定指向全局对象 Window; 根据 《JavasScript 高级程序设计》中提到的,关于 javascript严格模式,this 指向的说明:“严格模式下,函数的 this值始终是 指定的值,无论这个指定的值是什么”; 那么,我们一直是在求证我们的“this指向 其执行上下文的环境对象”,那么我们就开始试着把这个 “指定的值”理解为我们所说的 环境对象;看看在之后的论述中是否说的通; 然后我们做一个这样的总结,也就是说,在严格模式下,function的环境对象是指定的; 结合上面 demo在严格模式下运行的结果为 undefined来看,应该是说的通了, 分析: 因为 test1() 在执行的时候,并没有给它指定环境对象,所以 得出结果是 undefined;
*/ /*
下面,我们给 test1() 指定 一个环境变量后再看一下输出;
*/
test1.call(window); //strict-->Window nostrict-->Window /*
也许有人会问,window可以直接调用 test1(),并且输出 this值为 Window, 这是为什么呢? 如下:
*/
window.test1(); // Window
/*
这是因为,function test1 在全局作用域下声明的,而全局作用域下声明的变量都是 window对象的方法,所以可以用这样的 对象.方法() 的形式 执行函数; 而,函数作为对象方法被使用的时候,函数的执行上下文环境对象就为 这个拥有它的对象;
*/ /*
我们再给 test1() 指定其它的环境对象,看看情况是什么样的;
*/
var obj = {name: 'obj'};
test1.call(obj) // {name: 'obj'}
test1.call(null) // null
test1.call(undefined) // undefined
/*
还真是 指定啥就是啥啊!
*/ /*
以上的论述 最终思想,是证明了,严格模式下,函数的 this 指向是指定的对象,即使,指定的是 null 和 undefined, this的指向也是 null 和 undefined; 如果没有指定 会返回 undefined; 而我们 把这个被指定的对象,来作为 test()执行上下文的环境对象,那么 我们的结论 是说的通的; 概括一下: 浏览器环境 严格模式下: 函数作为单独函数 执行: 1.函数执行上下文的环境对象 是指定的,指定什么就是什么;this指向这个指定的环境对象; 函数作为对象方法 执行: 2.这个函数执行上下文的环境对象就是这个拥有它的对象;this指向这个拥有它的对象;
*/
</script>
</body>
</html>
非严格模式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>this 指向</title>
</head>
<body>
<script type="text/javascript">
/*
2.函数上下文中的 this 浏览器环境下: 非严格模式下
*/ /*
好了,严格模式下,我们已经得出结论了; 我们再来看看非严格模式下 输出结果会是什么样;
*/
// demo 1: 作为单独函数 执行
// "use strict" function test1(){
console.log(this);
}
test1(); // Window test1.call(window); // Window window.test1(); // Window var obj = {name: 'obj'}; test1.call(obj) // {name: 'obj'} test1.call(null) // Window test1.call(undefined) // Window // demo 2: 作为对象方法 执行
var obj2 = {
a:1,
sayThis: function(){
console.log(this);
}
}
obj2.sayThis(); // obj2 /*
我们发现,原来 没有被指定执行上下文环境对象 或 指定了执行上下文环境变量为 undefined 和 null 的,它的 this 值都指向了 Window 对象; 非严格模式下,我们应该可以这样下个结论, "非严格模式下,如果函数在执行时 没有指定执行上下文环境对象 或者 指定执行上下文环境对象为 null 或 undefined, 那么它的执行上下文环境对象 会默认为 全局对象", 也就是 this 会指向 全局对象; 概括一下: 浏览器环境 非严格模式下: 函数作为单独函数 执行: 1.函数执行上下文的环境对象 是指定的,指定什么就是什么;this指向这个指定的环境对象; 函数作为对象方法 执行: 2.这个函数执行上下文的环境对象就是这个拥有它的对象;this指向这个拥有它的对象;
*/
</script>
</body>
</html>
复杂测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>this 指向</title>
</head>
<body>
<script type="text/javascript">
/*
2.函数上下文中的 this 浏览器环境下:
*/
/*
有人会说啊,你这都是在全局环境下运行的例子并且例子太简单了,然后就下结论了,这太不具备说服力了: 个人一直认为,分析原理性的东西,越是从简单入手,才能越是切中要害,掌握单个知识点的精髓,复杂的分析 只是由 n多个小知识点 组合而成而已; 我下面来个复杂点的,验证我们的结论;
*/
// demo 3:
"use strict" var name = "sss";
var obj = {
name: "jjj",
sayName: function(){
console.log(this); innerFunction();
function innerFunction(){
console.log(this);
} return function(){
console.log(this);
}
}
} // scene 1:
obj.sayName(); // strict -->obj undefined no strict -->obj window
/*
分析:
sayName()作为 obj对象方法来执行,它的环境对象是 obj对象; innerFunction() 没有指定执行上下文的环境对象, 所以,执行上下文的环境对象,严格模式下,为 undefined; 非严格模式下,为 Window对象; */ // scene 2:
obj.sayName()(); // strict -->obj undefined undefined no strict-->obj window window
/*
--> 上式的执行 相当于 下面两句表达式
*/
var test = obj.sayName(); // strict -->obj undefined no strict-->obj window
test(); // strict -->undefined no strict-->window
/*
分析:
先执行 obj.sayName(), 输出结果的原因,已在 scene 1中做了说明,不再重复; 执行 test(),由于 test代表 obj.sayName()执行后,返回的匿名函数,当这个匿名函数 执行时,由于没有给它指定 执行上下文的环境对象, 所以,它的执行上下文环境对象,严格模式下 是 undefined; 非严格模式下 是 Window对象; 输出结果,与结论相稳合;
*/ // scene 3:
test.call(obj); // strict -->obj no strict-->obj
/*
分析:
接着 scene 2的解释,test代表 obj.sayName()执行后,返回的匿名函数,然后又给这个函数指定了执行上下文的环境对象 obj; 从输出结果来看,这符合给出的结论;
*/ /*
综上,浏览器环境下,我们的对 函数的执行上下文环境对象的结论概括 是成立的; */
</script>
</body>
</html>
3.对象属性中的 this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>this 指向问题</title>
</head>
<body> <script type="text/javascript">
/*
3.对象属性中的 this 注意:这里指的是如下的形式,不要把它和 对象方法中的 this搞混;对象方法中的 this,要规划到 函数上下文的 this中; 浏览器环境下: 严格模式下:Window 非严格模式下: Window
*/
'use strict'
var obj = {
a: 1,
b: 2,
c: this,
sayHi: function(){
console.log('Hi');
}
} console.log(obj.c); // Window /*
分析: 其实,这样的对象字面量的形式,可能看起来会有些困惑,我们可以变形来分析;因为对象字面量的形式,实际上是由如下的形式简化而来的写法; var obj = new Object();
obj.a =1;
obj.b = 2;
obj.c = this;
obj.sayHi = function(){
console.log('Hi');
} 这样看来就清晰很多了,上边这段代码执行的时候,不就是把全局执行上下文的环境对象赋给 obj.c 属性吗,关于全局上下文的 this,我们已经介绍过了; 而且结果,也正符合我们此时所得出的结果; 所以,这样作为对象中的 this,可以规到全局执行上下文中的 this 一类中,this 指向全局对象 window;
*/
/*
一个例子,可能没有什么说服力,我们再来个嵌套形式的 来证实我们的结论, 如下:
*/
var o1 = {
a: 1,
b: this,
o2: {
a: 1,
b: this
}
} console.log(o1.o2.b); // Window
/*
结果依然是 Window, 其实 如上的形式,可以变形为: var o1 = new Object();
o1.a = 1,
o1.b = this;
o1.o2 = new Object();
o1.o2.a = 1;
o1.o2.b = this; 上面这段代码 在执行时,它的执行上下文的环境对象依然是 Window对象;所以说 this依然指向 Window对象; */ /*
概括:对象属性中的 this指向 全局对象 Window对象;
*/
</script>
</body>
</html>
4.构造函数 和 原型方法中的 this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
/*
4.构造函数 和 原型方法中的 this 浏览器环境下: 严格模式下:以构造函数名命名的新对象 非严格模式下: 以构造函数名命名的新对象
*/
// "use strict"
function Person(){ console.log(this); // Person {} this.name = 'jack'; console.log(this); // Person {name: "jack"}
} Person.prototype.sayThis = function(){
console.log(this);
} Person.prototype.sayThis(); // {sayThis: ƒ, constructor: ƒ} new Person(); // Person {} --> // Person {name: "jack"} /*
分析 1: 构造函数与普通函数的最重要的不同之处,就是构造函数可通过 new操作符,创造实例; 那么在利用构造函数创造实例的过程到底发生了什么呢? 其实呢,是要经历以下几个过程的: 1.创造一个 新对象,作为执行上下文的环境对象;(注意:这里为什么说成是新对象,而不说成是空对象呢,因为 function默认是有 prototype属性存在的,它指向原型对象) 2.构造函数开始执行,它的执行上下文环境对象就为这个新对象,也就是说 this指向这个新对象; 3.利用 this来给这个新对象赋值; 4.返回这个被赋值之后的 新对象; 通过上面 new Person() 执行后输出的结果来看,确实是这样的一个过程;没有没给 this赋值前输出的是 Person{}, 赋值后,输出的 Person{name:'jack'}; 概括: 构造函数中的执行上下文的环境对象为,以构造函数名命名的新对象; 分析 2: 至于原型方法中 this, 其实,在我们了解了 “函数上下文的 this” 之后,应该很清楚了,它指向给它指定的环境对象,也就是确定了的 构造函数的原型对象; 所以,Person.prototype.sayThis() 执行后,输出的结果是 Person构造函数的原型对象 --> Person.prototype 对象;
*/
</script>
</body>
</html>
5.应用 call、apply、bind 方法后的 this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>this 指向</title>
</head>
<body>
<script type="text/javascript">
/*
5.应用 call、apply、bind 方法后的 this 了解:call、apply、bind 这三个方法是 Function对象才有的方法;它们的作用,主要是指定函数中 this中的指向,只是用法稍有不同; 浏览器环境下: 严格模式下:this指向 这三个方法所指定的这个值,无论是什么,即使是 null、undefined, this 也指向它们; 非严格模式下:this指向 这三个方法所指定的这个值,null 和 undefined 值会被转换为全局对象 window;
*/
// demo 1:
var o1 = {
a: 11,
b: 12,
sayA: function(){
console.log(this.a);
}
} var o2 = {
a: 21,
b: 22
} o1.sayA.call(o2); // 21 // demo 2:
function sayB(){
console.log(this.b);
} sayB.call(o2); // 22
sayB.apply(o2); // 22 var bSayB = sayB.bind(o2);
bSayB(); // 22 /*
其实这块不应该单提出来一个作总结分析的,完全可以规划到“函数上下文的 this”中去,只是在我们平时 coding的时候, 这三个方法是经常要用到的 所以单拿出来,以作记忆吧;
*/
</script>
</body>
</html>
原创:转载注明出处,谢谢 :)
this指向 - 浏览器环境的更多相关文章
- Javascript的二进制数据处理学习 ——nodejs环境和浏览器环境分别分析
以前用JavaScript主要是处理常规的数字.字符串.数组对象等数据,基本没有试过用JavaScript处理二进制数据块,最近的项目中涉及到这方面的东西,就花一段时间学了下这方面的API,在此总结一 ...
- this指向 - Node环境
1.全局上下文中 this /* 1.全局上下文中的 this node环境下: 严格模式下: {} {} 报错 非严格模式下:{} {} {} */ 'use strict'; // 严格模式 // ...
- atitit.js浏览器环境下的全局异常捕获
atitit.js浏览器环境下的全局异常捕获 window.onerror = function(errorMessage, scriptURI, lineNumber) { var s= JSON. ...
- 浏览器环境下Javascript脚本加载与执行探析之DOMContentLoaded
在”浏览器环境下Javascript脚本加载与执行探析“系列文章的前几篇,分别针对浏览器环境下JavaScript加载与执行相关的知识点或者属性进行了探究,感兴趣的同学可以先行阅读前几篇文章,了解相关 ...
- 浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
在<浏览器环境下JavaScript脚本加载与执行探析之defer与async特性>中,我们研究了延迟脚本(defer)和异步脚本(async)的执行时机.浏览器支持情况.浏览器bug以及 ...
- 浏览器环境下JavaScript脚本加载与执行探析之defer与async特性
defer和async特性相信是很多JavaScript开发者"熟悉而又不熟悉"的两个特性,从字面上来看,二者的功能很好理解,分别是"延迟脚本"和"异 ...
- 判断浏览器环境(QQ,微信,安卓设备,IOS设备,PC微信环境,移动设备)
判断浏览器环境(QQ,微信,安卓设备,IOS设备,PC微信环境,移动设备) // ===== 判断浏览器环境 ===== // // 判断是否是QQ环境 function isQQ() { retur ...
- Node.js event loop 和 JS 浏览器环境下的事件循环的区别
Node.js event loop 和 JS 浏览器环境下的事件循环的区别: 1.线程与进程: JS 是单线程执行的,指的是一个进程里只有一个主线程,那到底什么是线程?什么是进程? 进程是 CPU ...
- Babel 在浏览器环境使用方法
Babel 也可以用于浏览器环境.但是,从 Babel 6.0 开始,不再直接提供浏览器版本,而是要用构建工具构建出来.如果你没有或不想使用构建工具 1.通过安装5.x版本的babel-core模块获 ...
随机推荐
- MongoDB 用户角色
Read:允许用户读取指定数据库 readWrite:允许用户读写指定数据库 dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建.删除,查看统计或访问system.profile user ...
- 也谈谈Unity的transform使用
一.Transform和transform 我们来详谈Unity的transform使用,这里所说的tansform不是类UnityEngine命名空间下的Transform,而是transform. ...
- 复习前面一个月的学习C#感觉道路好艰难啊
今天是复习前面学习的内容,感觉这一个月来真的学习了很多,但是掌握的不好,好多都是在老师讲完课后做起来练习感觉这知识用起来蛮轻松地,但是经过昨天和今天的复习发现好多还是给忘记啦,甚是失落啊,刚开始就知道 ...
- 在create-react-app的脚手架里面使用scss
之前用vue-cli脚手架的时候,只需要引进sass需要的依赖包便可以引入scss,但是在create-react-app的时候,发现除了需要引入sass依赖,还需要进行配置: 不管用什么方法进行sa ...
- Linux下Redis集群环境的搭建
一.安装redis(使用redis3.0版本) 1.需要gcc环境,如果没有执行命令安装gcc yum install gcc-c++ 2.下载redis3.0的源码包并上传至服务器 3.解压源码包 ...
- 【BZOJ3156】防御准备 斜率优化
[BZOJ3156]防御准备 Description Input 第一行为一个整数N表示战线的总长度. 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai. Output 共一个整数,表示最小 ...
- redis数据持久化(快照/日志):
1.RDB快照的配置选项: save // 900内,有1条写入,则产生快照 save // 如果300秒内有1000次写入,则产生快照 save // 如果60秒内有10000次写入,则产生快照 ( ...
- 模拟退火算法(run away poj1379)
http://poj.org/problem?id=1379 Run Away Time Limit: 3000MS Memory Limit: 65536K Total Submissions: ...
- java实现创建临时文件然后在程序退出时自动删除文件(转)
这篇文章主要介绍了java实现创建临时文件然后在程序退出时自动删除文件,从个人项目中提取出来的,小伙伴们可以直接拿走使用. 通过java的File类创建临时文件,然后在程序退出时自动删除临时文件.下面 ...
- 写出gradle风格的groovy代码
写出gradle风格的groovy代码 我们先来看一段gradle中的代码: buildscript { repositories { jcenter() } dependencies { class ...