共计 2524 个字符,预计需要花费 7 分钟才能阅读完成。
this 的定义:示意以后执行代码的环境对象
因而可将 this 的分析分为“全局环境”和“函数环境”两种类型的环境对象
一、全局环境
console.log(this === window); // true
var a = 10;
console.log(this.a); // 10
二、函数环境
在函数外部,this 的取值取决于函数被调用时的运行环境。
这里波及到内存里的数据结构相干的知识点,当咱们定义以下字面量对象时会产生一系列的关联关系
var obj = {name: 'Tom'};
javascript 引擎会先在内存中生成 {name: ‘Tom’} 对象,接着再把这个对象的内存地址赋值给 obj 变量,所以 obj 变量保留的只是一个内存地址而已,如果要获取 obj.name,javascript 引擎会先从 obj 变量中拿到内存地址,而后从该地址中获取原始对象,再返回 name 属性。
而属性值为函数时,该函数会被保留在内存中,而后将该内存地址赋值给该属性,因而该地址赋值给不同环境执行时它的作用域是不一样的,而 this 对象就是指向函数以后的执行环境对象,执行环境是会在 Event Loop(事件循环)过程中变动的,因而 this 在函数环境下是属于运行时的。
var name = 'Tom';
var obj = {
name: 'Iceberg',
say: function() {console.log('my name is' + this.name);
},
sub: {say: function() {console.log('my name is' + this.name);
}
}
};
obj.say(); // my name is Iceberg
obj.sub.say() // my name is undefined;
var say = obj.say;
say(); // my name is Tom;
下面的例子阐明 obj.say() 执行环境为 obj 对象,而 obj.sub.say() 的执行环境却是 obj.sub 对象,而对于 obj.sub 来说并没有 name 属性,因而为 undefined;而 var say = obj.say; 则示意将 say 办法的内存地址赋值给全局变量,因而从全局变量 name 中取值。
使用场景
接下来从 this 在函数环境下的不同使用场景来分析
1. 事件回调函数
var handler = {
nickname: 'anonymous',
register: function() {console.log(this.nickname);
}
}
$('#registerBtn').on('click', handler.register); // undefined
以上逻辑点击触发后输入的是 undefined,因为函数被当做事件触发的回调函数执行时,this 是指向该触发事件对应的元素,如要 this 依然以 handler 对象为执行环境,则可应用函数的 bind 办法进行执行环境对象的绑定操作。
$('#registerBtn').on('click', handler.register.bind(handler)); // anonymous
2. 构造函数
要了解 this 在构造函数中的逻辑就要理分明构造函数在实例化过程中都产生了什么。
1. function A() {
2. this.name = 'Tom';
3. this.age = 20;
4. }
5. var a = new A();
应用 new 命令实例化构造函数 A 的过程中会产生以下流程:
1. 创立一个空对象,作为将要返回的对象实例
2. 将该空对象的原型指向构造函数的 prototype 属性
3. 将该空对象赋值给构造函数外部的 this 关键字
4. 执行构造函数外部代码
5. 默认返回 this 对象(如 return 的为非对象类型,如数字 123,会被疏忽进而默认 return this 对象)6. 由以上逻辑可晓得 this 关键字在构造函数中示意的是其实例对象。
bind
1. function A() {
2. this.nickname = 'Tom';
3. this.say = function() {4. console.log(this.nickname);
5. }
6. }
7. var b = {nickname: 'John'};
8. var a = new A();
9. var say = a.say;
10. var say1 = a.say.bind(a);
11. var say2 = a.say.bind(b);
12. say(); // undefined
13. say1(); // Tom
14. say2(); // John
call&apply
1. function A() {
2. this.name = 'Tom';
3. this.sayName = function(){4. console.log(this.name);
5. };
6. }
8. function B() {
9. this.name = 'John';
10. }
12. var a = new A();
13. a.sayName.call(new B()); // John
总结:
1. 在个别函数中应用 this 指全局对象 window
2. 作为对象办法应用时,this 指向该对象
3. 作为构造函数应用时,this 指向 new 出的实例
4.apply 或 call 应用时,此办法第一个参数为扭转后的调用函数的对象,函数里 this 指第一个参数。
5. 被当做事件触发的回调函数执行时,this 是指向该触发事件对应的元素
题外:手写一个 new 操作
// 新建一个类
function Otaku(name, age) {
this.name = name;
this.age = age;
// 本身的属性
this.habit = 'pk';
}
// 给类的原型上增加属性和办法
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function() {console.log('I am' + this.name);
}
// 实例化一个 person 对象
const person = new Otaku('cty', 5000);
person.sayYourName();
console.log(person);