this与对象原型

一、this 是什么 ?

this是一个在每个函数作用域中自动定义的特殊标识符关键字。
this不是编写时绑定,而是运行时绑定,它依赖于函数调用的上下文条件。 this 绑定于函数声明的位置没有任何关系,而与函数被调用的方式紧密相连。
当一个函数被调用时,会建立一个称为执行环境的活动记录。这个记录包含函数式从何处(调用栈)被调用的,函数是如何被调用的,传递了什么参数等信息。这个记录的属性之一,就是在函数执行期间被使用的this 引用。
调用点(call-site):函数在代码中被调用的位置(不是被声明的位置)。

二、如何决定this指向哪里?

1、默认绑定

 独立函数调用,可以认为这种this规则是在没有其他规则适用时的默认规则。
function foo() {
	console.log( this.a );  //  this.a 解析为全局变量
	//在改情况下,对此方法调用的this实施了默认绑定,所以this 指向全局对象
}
var a = 2;
foo(); // 2

注意:在严格模式(strict mode)中对于默认绑定来说全局对象是不合法的,this 将会被设置为undefined

2、隐含绑定

调用点是否有一个环境对象,也称为 拥有者容器对象。我们不得不改变目标对象使它自身包含一个对函数的引用,而后使用这个函数引用属性来间接地(隐含地)将 this 绑定到这个对象上。

function foo() {
	console.log( this.a );
}

var obj = {
	a: 2,
	foo: foo
};

obj.foo(); // 2

调用点 使用 obj 环境来 引用 函数,所以你 可以说 obj 对象在函数被调用的时间点上“拥有”或“包含”这个 函数引用
在 foo() 被调用的位置上,它被冠以一个指向 obj 的对象引用。当一个方法引用存在一个环境对象时,隐含绑定 规则会说:是这个对象应当被用于这个函数调用的 this 绑定。

隐含丢失

当一个 隐式绑定丢失了它的绑定,这通常意味着它会退回大默认绑定,根据strict mode状态,其结果不是全局对象就是 undefined。

function foo() {
	console.log( this.a );
}

var obj = {
	a: 2,
	foo: foo
};

var bar = obj.foo; // 函数引用!

var a = "oops, global"; // `a` 也是一个全局对象的属性

bar(); // "oops, global"

3、明确绑定

call()和apply()它们接收的第一个参数都是一个用于 this 的对象,之后使用这个指定的 this 来调用函数。因为你已经直接指明你想让 this 是什么,所以我们称这种方式为 明确绑定。

function foo() {
	console.log( this.a );
}

var obj = {
	a: 2
};

foo.call( obj ); // 2   通过foo.call(obj)明确绑定,强制函数的this 指向 obj。

 注意:就this的绑定角度讲,call()和apply()是完全一样的,但是在处理其他参数的方式上有所不同
硬绑定
function foo() {
	console.log( this.a );
}

var obj = {
	a: 2
};

var bar = function() {
	foo.call( obj );
};

bar(); // 2
setTimeout( bar, 100 ); // 2

// `bar` 将 `foo` 的 `this` 硬绑定到 `obj`
// 所以它不可以被覆盖
bar.call( window ); // 2

我们来看看这个变种是如何工作的。我们创建了一个函数 bar(),在它的内部手动调用 foo.call(obj),由此强制 this 绑定到 obj 并调用 foo。无论你过后怎样调用函数 bar,它总是手动使用 obj 调用 foo。这种绑定即明确又坚定,所以我们称之为 硬绑定(hard binding)。

4、new 绑定

在传统的面向类语言中,“构造器”是附着在类上的一种特殊方法,当使用 new 操作符来初始化一个类时,这个类的构造器就会被调用。

在JS中,构造器 仅仅是一个函数,它们偶然地与前置的 new 操作符一起调用。它们不依附于类,它们也不初始化一个类。它们甚至不是一种特殊的函数类型。它们本质上只是一般的函数,在被使用 new 来调用时改变了行为。

当在函数前面被加入 new 调用时,也就是构造器调用时,下面这些事情会自动完成:

1)一个全新的对象会凭空创建(就是被构建)
2)这个新构建的对象会被接入原形链([[Prototype]]-linked)
3)这个新构建的对象被设置为函数调用的 this 绑定
4)除非函数返回一个它自己的其他 对象,否则这个被 new 调用的函数将 自动 返回这个新构建的对象。

5、绑定规则优先级

明确绑定优先级高于隐含绑定,new绑定的优先级高于隐含绑定;硬绑定优先级高于 new 绑定。

注意: new 和 call/apply 不能同时使用,也就是不能直接对比测试 new 绑定 和 明确绑定。但是我们依然可以使用 硬绑定 来测试这两个规则的优先级。

总结

为执行中的函数判定 this 绑定需要找到这个函数的直接调用点。找到之后,四种规则将会以这种优先顺序施用于调用点:

1、通过 new 调用?使用新构建的对象。
2、通过 call 或 apply(或 bind)调用?使用指定的对象。
3、通过持有调用的环境对象调用?使用那个环境对象。
4、默认:strict mode 下是 undefined,否则就是全局对象。

  • 26
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值