解析 Javascript - this
在函数中 this 到底取何值,是在函数真正被调用执行的时候确定下来的,函数定义的时候确定不了。
因为 this 的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。当你在代码中使用了 this,这个 this 的值就直接从执行的上下文中获取了,而不会从作用域链中搜寻。
关于 this 的取值,大体上可以分为以下七种情况:
情况一:全局 & 调用普通函数
在全局环境中,this 永远指向 window。
console.log(this === window); //true
普通函数在调用时候(注意不是构造函数,前面不加 new),其中的 this 也是指向 window。
var x = 10;
function foo(){
console.log(this); //Window
console.log(this.x); //10
}
foo();
情况二:构造函数
所谓的构造函数就是由一个函数 new 出来的对象,一般构造函数的函数名首字母大写,例如像 Object,Function,Array 这些都属于构造函数。
function Foo(){
this.x = 10;
console.log(this); //Foo {x:10}
}
var foo = new Foo();
console.log(foo.x); //10
上述代码,如果函数作为构造函数使用,那么其中的 this 就代表它即将 new 出来的对象。
但是如果直接调用 Foo 函数,而不是 new Foo(),那就变成情况1,这时候 Foo() 就变成普通函数。
function Foo(){
this.x = 10;
console.log(this); //Window
}
var foo = Foo();
console.log(foo.x); //undefined
情况三:对象方法
如果函数作为对象的方法时,方法中的 this 指向该对象。
var obj = {
x: 10,
foo: function () {
console.log(this); //Object
console.log(this.x); //10
}
};
obj.foo();
注意:若是在对象方法中定义函数,那么情况就不同了。
var obj = {
x: 10,
foo: function () {
function f(){
console.log(this); //Window
console.log(this.x); //undefined
}
f();
}
}
obj.foo();
可以这么理解:函数 f 虽然是在 obj.foo 内部定义的,但它仍然属于一个普通函数,this 仍指向 window。(这是个坑,要记牢)
在这里,如果想要调用上层作用域中的变量 obj.x,可以使用 self 缓存外部 this 变量。
var obj = {
x: 10,
foo: function () {
var self = this;
function f(){
console.log(self); //{x: 10}
console.log(self.x); //10
}
f();
}
}
obj.foo();
如果 foo 函数不作为对象方法被调用:
var obj = {
x: 10,
foo: function () {
console.log(this); //Window
console.log(this.x); //undefined
}
};
var fn = obj.foo;
fn();
obj.foo 被赋值给一个全局变量,并没有作为 obj 的一个属性被调用,那么此时 this 的值是 window。
情况四:构造函数 prototype 属性
function Foo(){
this.x = 10;
}
Foo.prototype.getX = function () {
console.log(this); //Foo {x: 10, getX: function}
console.log(this.x); //10
}
var foo = new Foo();
foo.getX();
在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前对象的值。
情况五:函数用 call、apply或者 bind 调用。
var obj = {
x: 10
}
function foo(){
console.log(this); //{x: 10}
console.log(this.x); //10
}
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();
当一个函数被 call、apply 或者 bind 调用时,this 的值就取传入的对象的值。
情况六:DOM event this
在一个 HTML DOM 事件处理程序里,this 始终指向这个处理程序所绑定的 HTML DOM 节点:
function Listener(){
document.getElementById('foo').addEventListener('click', this.handleClick); //这里的 this 指向 Listener 这个对象。不是强调的是这里的 this
}
Listener.prototype.handleClick = function (event) {
console.log(this); //<div id="foo"></div>
}
var listener = new Listener();
document.getElementById('foo').click();
这个很好理解,就相当于是给函数传参,使 handleClick 运行时上下文改变了,相当于下面这样的代码:
var obj = {
x: 10,
fn: function() {
console.log(this); //Window
console.log(this.x); //undefined
}
};
function foo(fn) {
fn();
}
foo(obj.fn);
你也可以用通过 bind 切换上下文:
function Listener(){
document.getElementById('foo').addEventListener('click',this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
console.log(this); //Listener {}
}
var listener = new Listener();
document.getElementById('foo').click();
前六种情况总结一句话为: this 指向调用该方法的对象。
情况七:箭头函数中的 this
当使用箭头函数的时候,情况就有所不同了:箭头函数内部的 this 是词法作用域,由上下文确定。
var obj = {
x: 10,
foo: function() {
var fn = () => {
return () => {
return () => {
console.log(this); //Object {x: 10}
console.log(this.x); //10
}
}
}
fn()()();
}
}
obj.foo();
现在,箭头函数完全修复了 this 的指向,this 总是指向词法作用域,也就是外层调用者 obj。
如果使用箭头函数,以前的这种 hack 写法:
var self = this;
就不再需要了。
var obj = {
x: 10,
foo: function() {
var fn = () => {
return () => {
return () => {
console.log(this); // Object {x: 10}
console.log(this.x); //10
}
}
}
fn.bind({x: 14})()()();
fn.call({x: 14})()();
}
}
obj.foo();
由于 this 在箭头函数中已经按照词法作用域绑定了,所以,用 call()或者 apply()调用箭头函数时,无法对 this 进行绑定,即传入的第一个参数被忽略。
补充说明:
- this 为保留字,你不能重写 this。
function test(){
var this = {}; //Uncaught SyntaxError: Unexpected token this
}
- 宿主对象:
- 一门语言在运行的时候,需要一个环境,叫做宿主环境。
- 对于JavaScript,宿主环境最常见的是 web 浏览器,浏览器提供了一个 JavaScript 运行的环境,这个环境里面,需要提供一些接口,好让 JavaScript 引擎能够和宿主环境对接。
- JavaScript 引擎才是真正执行 JavaScript 代码的地方,常见的引擎有 V8(目前最快 JavaScript 引擎、Google 生产)、JavaScript core。
- 在浏览器或者服务端( nodejs )都有自己的 JS 引擎,在浏览器中,全局对象为 window,而在 nodejs 中,全局对象为 global。
解析 Javascript - this的更多相关文章
- 解析Javascript事件冒泡机制
本资源引自: 解析Javascript事件冒泡机制 - 我的程序人生 - 博客频道 - CSDN.NET http://blog.csdn.net/luanlouis/article/details/ ...
- 深入解析Javascript中this关键字的使用
深入解析Javascript中面向对象编程中的this关键字 在Javascript中this关键字代表函数运行时,自动生成的一个内部对象,只能在函数内部使用.比如: function TestFun ...
- 深度解析javascript中的浅复制和深复制
原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...
- 浏览器解析JavaScript原理
1.浏览器解析JavaScript原理特点: 1.跨平台 2.弱类型 javascript 定义的时候不需要定义数据类型,数据类型是根据变量值来确定的. var a = 10; 数字类型 ...
- 全面解析JavaScript中“&&”和“||”操作符(总结篇)
1.||(逻辑或), 从字面上来说,只有前后都是false的时候才返回false,否则返回true. ? 1 2 3 4 alert(true||false); // true alert(false ...
- 解析javascript变量
//add by tim//提供解析javascript 脚本的变量集合 using System;using System.Collections.Generic;using System.Linq ...
- 深度解析javaScript常见数据类型检查校验
前言 在JavaScript中,数据类型分为两大类,一种是基础数据类型,另一种则是复杂数据类型,又叫引用数据类型 基础数据类型:数字Number 字符串String 布尔Boolean Null Un ...
- 深入解析Javascript闭包
首先给个例子: function PfnOuter(){ var num=999; function PfnInner(){ alert(num); } return PfnInner; } var ...
- 解析JavaScript中apply和call以及bind
函数调用方法 在谈论JavaScript中apply.call和bind这三兄弟之前,我想先说下,函数的调用方式有哪些: 作为函数 作为方法 作为构造函数 通过它们的call()和apply()方法间 ...
- 15条规则解析JavaScript对象布局(__proto__、prototype、constructor)
大家都说JavaScript的属性多,记不过来,各种结构复杂不易了解.确实JS是一门入门快提高难的语言,但是也有其他办法可以辅助记忆.下面就来讨论一下JS的一大难点-对象布局,究竟设计JS这门语言的人 ...
随机推荐
- git远程提交失败
同步仓库并解决403报错 这时候对本地仓库和github进行同步 # git push -u origin master error: The requested URL returned error ...
- 实用的HTML优化技巧
如何提升Web页面的性能,很多开发人员从多个方面来下手如JavaScript.图像优化.服务器配置,文件压缩或是调整CSS. 很显然HTML 已经达到了一个瓶颈,尽管它是Web开发 界面必备的核心语言 ...
- ASP.NET Core Web 支付功能接入 微信-扫码支付篇
这篇文章将介绍ASP.NET Core中使用 开源项目 Payment,实现接入微信-扫码支付及异步通知功能. 开发环境:Win 10 x64.VS2017 15.6.4..NET Core SDK ...
- 笔记:MyBatis 动态SQL
有时候,静态的SQL语句并不能满足应用程序的需求.我们可以根据一些条件,来动态地构建SQL语句.例如,在Web应用程序中,有可能有一些搜索界面,需要输入一个或多个选项,然后根据这些已选择的条件去执行检 ...
- Matlab绘图基础——图形修饰处理(入门)
引入--标题.色条.坐标轴.图例等 例一: set(groot,'defaultAxesLineStyleOrder','remove','defaultAxesColorOrder','remove ...
- 解决设置clickablespan后长按冲突的问题
解决设置ClickableSpan后长按冲突的问题 问题描述 3月份修改别人代码的时候想要屏蔽TextView的长按事件,发现TextView有重写OnTouchEvent方法,然后在其中加了长按事件 ...
- Node.js + gulp 合并静态页模版,文件更新自动热重载。浏览器可预览
github地址:https://github.com/Liaozhenting/template 使用的是ejs的语法.其实你用什么文件后缀都可以,都是按ejs来解析. 模板文件放在componen ...
- C语言程序设计(基础)- 第6周作业
一.PTA作业 完成PTA第六周作业中4个题目的思路列在博客中. 1.7-1 高速公路超速处罚 2.7-2 计算油费 3.7-3 比较大小 4.7-4 两个数的简单计算器 (必须使用switch结构实 ...
- 初谈Git(本机克隆项目远程仓库)
1. 码云注册与新建项目 注册并新建项目 2. Git安装并配置 安装 配置 3. clone项目 附:一些Git命令 git clone 拷贝并跟踪远程的master分支 git add 跟踪新文件 ...
- 推荐net开发cad入门阅读代码片段
转载自 Cad人生 的博客 链接:http://www.cnblogs.com/cadlife/articles/2668158.html 内容粘贴如下,小伙伴们可以看看哦. using Syst ...