“this”到底是什么?
在Vanilla JavaScript中,是一个让新手很困扰的问题。

特别是对于我们这些没有编程背景的初学者。

我曾经从事会计工作,对于JIB、AP、AR这些专业词很熟悉。因为词典会给它们一个清晰的定义。

但是,“this”的定义却一点都不清晰。

我记得第一次学习对象的时候,”this“在构造函数中被使用,但是从来没有清楚地解释。

到底什么是this?

这里是我个人给出的非官方的定义:

“this”是JavaScript的一个关键字,它具体的含义依赖于使用的环境。

至于在学习JavaScript的时候,”this”如此让人迷惑就是因为它的环境又基于你如何使用它。

你甚至可以把它理解成为一个动态的关键字。

我很喜欢Ryan Morr在 Understanding Scope and Context in JavaScript中的一句话:

Context is always the value of the this keyword which is a reference to the object that “owns” the currently executing code.

但是,“this”的环境不一定和它的执行环境相同。

因此,当我们使用“this”关键字的时候,我们实际上用来指向一个对象,那么到底是哪个对象?

我们来看一些示例

  1. “this”指向Window对象
  2. 对象的方法
    1. this作用于对象
    2. this作用于嵌套的对象
    3. this作用于对象,但是用了箭头(arrow function)函数
  1. 函数环境
  2. new关键字

1. “this”指向Window对象

如果你尝试在函数外使用“this”,它会指向全局,也就是Window对象。

在全局的函数中使用的this也指向Window对象。

你可以自己试一试:

console.log(this);// returns the Window object
// Window { postMessage: ƒ,
// blur: ƒ,
// focus: ƒ,
// close: ƒ,
// frames: Window, …}function myFunction() {console.log(this);
}// Call the function
myFunction(); // returns the Window object!
// Window { postMessage: ƒ,
// blur: ƒ,
// focus: ƒ,
// close: ƒ,
// frames: Window, …}

2. 对象方法

当“this”在对象内部,那么指向对象本身。

如下所示,创建一个对象,intro函数中使用了this,那么this指向dog对象。

var dog = {name: 'Chester',breed: 'beagle',intro: function(){console.log(this);}
};dog.intro();// returns the dog object and all of it's properties and methods
// {name: "Chester", breed: "beagle", intro: ƒ}
//    breed:"beagle"
//    intro:ƒ ()
//    name:"Chester"
//    __proto__:Object

对象嵌套

如果使用了对象嵌套,那么this的值如何确定就变得错综复杂了。

任何时候,如果你在对象中嵌套对象,那么”this”的使用取决于函数基于哪个对象定义。

例子:

var obj1 = {hello: function() {console.log('Hello world');return this;},obj2: {breed: 'dog',speak: function(){console.log('woof!');return this;}}
};console.log(obj1);
console.log(obj1.hello());  // logs 'Hello world' and returns obj1
console.log(obj1.obj2);
console.log(obj1.obj2.speak());  // logs 'woof!' and returns obj2

但是,要注意箭头函数并不遵守规则

在箭头函数中,“this”指向Window或则全局对象!

你可以试试下面的代码:

var objReg = {hello: function() {return this;}
};var objArrow = {hello: () => this
};objReg.hello(); // returns the objReg object that we expect
objArrow.hello(); // returns the Window object!

根据MDN的定义:箭头函数有更加简洁的语法,并且没有自己的this绑定。

所以,不要在定义对象方法的事或使用它。

3. “this”用于一般函数情况

函数在全局定义,那么this指向全局对象,即window。

function test() {console.log('hello world');console.log(this);
}test();// hello world
// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

但是,如果在严格模式下,“this”会返回undefined。因为严格模式下,不允许默认绑定。就算是window对象也不行。

function test() {'use strict';return this;
}console.log( test() );
// returns undefined, not the Window object … interesting

当在对象外调用函数,而函数中使用了this

dog对象在定义的时候没有定义方法,知道我创建dog.foo,将chase函数绑定给它。

调用foo函数,那么chase函数中的this会指向dog对象。如果没有将chase函数和某个对象绑定,那么会报错或则返回未定义。

var dog = {breed: 'Beagles',lovesToChase: 'rabbits'
};function chase() {console.log(this.breed + ' loves chasing ' + this.lovesToChase + '.');
//   console.log(this);
}dog.foo = chase;
dog.foo(); // returns Beagles loves chasing rabbits.chase(); // returns undefined because when run in the global context, window object does not have these properties defined

直接调用chase函数,返回未定义,因为在全局环境下,this指向window对象。

4. “new”关键字

function Dog(breed, name, friends){this.breed = breed;this.name = name;this.friends = friends;    this.intro = function() {console.log(`Hi, my name is ${this.name} and I’m a ${this.breed}`);return this;};
}

注意,在定义Dog函数的时候,其this没有特定的值。

每一次使用new关键字创建一个新的Dog实例,this就会指向该对象。

原则上和下面的语法是一致的:

var str = new String('Hello world');
/*******
You could do the above, but it's best to avoid it (instead do like the variable str2 below)
(because JavaScript knows that anything inside single or double quotes has the type of String)
Same goes for other primitives. This is for example purposes only.
NOTE: To clarify -- the only time I ever use the new keyword in practice is when I use a function constructor and create my own object type.
*******/var str2 = 'Hello world';
// both have the prototype of String and inherit all the String methods and properties
// Using the Dog prototype, create a new instance
var chester = new Dog('beagle', 'Chester', ['Gracie', 'Josey', 'Barkley']);
chester.intro();        // returns Hi, my name is Chester and I'm a beagle
console.log(chester);   // returns Dog {breed: "beagle", name: "Chester", friends: Array(3), intro: ƒ}// Here's another example:
var City = function(city, state) {this.city = city || "Phoenix";this.state = state || "AZ";this.sentence = function() {console.log(`I live in ${this.city}, ${this.state}.`);};
};var phoenix = new City(); // use the default parameters
console.log(phoenix); // returns the phoenix object (an instance of the City prototype)
phoenix.sentence(); // returns "I live in Phoenix, AZ."var spokane = new City('Spokane', 'WA');
console.log(spokane); // returns the spokane object (another instance of the City prototype)
spokane.sentence(); // returns "I live in Spokane, WA."

new关键字很重要

它可以将this指向到新定义的对象实例。这样的好处在于,我们可以有一个定义,来声明多个实例。

想象一下你的社交账号,我们可以定义每一个社交账号叫“Friend”,每一次创建一个新的账户,它们都会继承所有的属性和方法,但是传入个性化的名字,密码,兴趣,工作等数据。

// Constructor Function
var Friend = function(name, password, interests, job){this.fullName = name;this.password = password;this.interests = interests;this.job = job;
};function sayHello(){// uncomment the console.log to see the object that 'this' points to//  console.log(this); return `Hi, my name is ${this.fullName} and I'm a ${this.job}. Let's be friends!`;
}// Create one or multiple instances of the Friend prototype with the keyword 'new'
var john = new Friend('John Smith', 'badpassword', ['hiking', 'biking', 'skiing'], 'teacher'); console.log(john); // Assign the function to the greeting key on the john object
john.greeting = sayHello; // Call the the new method
console.log( john.greeting() ); // Remember, you can't call sayHello() as a function; it will return "Hi, my name is undefined and I'm a undefined. Let's be friends!"
// Because the function's context is global and the window object does NOT have the keys that belong to the Friend prototype
console.log( sayHello() ) ;

结论

还有一种方式可以传递this值,那就是call,apply,和bind函数。
不过本文不再赘述。

为什么JavaScript中的this如此强大?相关推荐

  1. javascript编写_如何在JavaScript中使用解构来编写更简洁,功能更强大的代码

    javascript编写 by Ashay Mandwarya ?️?? 由Ashay Mandwarya提供吗? 如何在JavaScript中使用解构来编写更简洁,功能更强大的代码 (How to ...

  2. 在Javascript中使用面向对象的编程

    by Mike Koss March 26th, 2003 这是一篇,我个人认为最好的,Javascript面向对象编程的文章.翻译不好的地方,还望大家指正,谢谢. 如果您需要,可以访问下面的地址取得 ...

  3. 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门)

    by Preethi Kasireddy 通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门) (Why use stati ...

  4. JavaScript中的字符串操作(转)

    http://www.cnblogs.com/xuebin/articles/1296837.html 最近编一个javascript的翻译程序,发现无法正确比较两个字符串的相等,上网查了查,发现这篇 ...

  5. 理解JavaScript中的事件

    在很多语言的学习中,"事件"都是一个比较难理解,但是又是一个很重要的概念.JavaScript中的事件处理也是一样,正因为有了事件处理,才会出现Ajax拖动的效果.本文就讨论一下J ...

  6. JavaScript中的instanceof运算符是什么?

    本文翻译自:What is the instanceof operator in JavaScript? The instanceof keyword in JavaScript can be qui ...

  7. 停止JavaScript中的setInterval调用

    我正在使用setInterval(fname, 10000); 在JavaScript中每10秒调用一次函数. 是否可以在某个事件中停止调用它? 我希望用户能够停止重复刷新数据. #1楼 setInt ...

  8. 遍历JavaScript中的数组

    在Java中,可以使用for循环遍历数组中的对象,如下所示: String[] myStringArray = {"Hello", "World"}; for ...

  9. 在JavaScript中逐个遍历数组?

    如何使用JavaScript遍历数组中的所有条目? 我以为是这样的: forEach(instance in theArray) 其中theArray是我的数组,但这似乎是不正确的. #1楼 如果您不 ...

最新文章

  1. 在Eclipse中使用Maven构建Spring项目
  2. 论网站更新与seo优化的关系
  3. 信息系统项目管理师-沟通管理知识点
  4. 是用Entity.Save(),还是用DAL.Save(Entity e)
  5. 获取http请求标头_HTTP请求和标头参数的CDI拦截器–简单示例
  6. Color类提供的颜色
  7. 中国重汽微服务管理_干货 | 微服务架构下 Spring Cloud OAuth2 通用权限管理系统
  8. php++背景自适应屏幕宽度,背景图片+自适应屏幕
  9. React的学习曲线
  10. Oracle锁庞大大引见
  11. 双边滤波器和高斯滤波器
  12. matlab 稀疏编码,稀疏编码怎样进行图像的特征提取
  13. 守望先锋--颜色参数
  14. 使用JSONRPC操作附带token(secret)的aria2
  15. 分光器(光分路器)基础知识【快速入门】01
  16. 给ssh服务添加谷歌双重认证
  17. 一生至少原谅的三个人
  18. MacBook软件安装和更新与卸载
  19. Flutter升级空安全版本注意事项
  20. 复旦大学《数学分析》教学大纲,读后有感

热门文章

  1. Java 基础知识面试题(2021最新版)
  2. 东南大学计算机专业排名2018,2018东南大学排名多少位 东南大学优势专业排名
  3. 360软件管家下载微软VC++运行库集合解决“丢失api-ms-win-crt-runtimel1-1-0.dll的错误,提示要安装Visual C++ 2015”问题
  4. 使用 Flutter 加速应用开发
  5. 朗伯辐射强度模型MATLAB,朗伯体辐射出射度与辐亮度的关系.PPT
  6. 64位系统使用Access 数据库文件遇到的错误和解决办法
  7. 快钱提现 php,快钱账户提现付款操作手册
  8. RFID动物耳标识读器在科学养猪中的应用
  9. ADI-trinamic精确控制医疗设备(IVD体外诊断仪器)
  10. C语言面试题大汇总之华为面试题 Eddy整理