// 默认绑定
// 在没有其他规则使用时的默认绑定
// function foo(){
// console.log(this.a);
// }
// var a = 2;
// foo();
// 隐含绑定
// 调用点是否为一个环境对象,也叫作拥有者或者容器
// function foo(){
// console.log( this.a );
// };
// var obj = {
// a: 2,
// b: 3,
// fooo: foo,
// };
// obj.fooo();
// foo()被声明后作为引用属性添加到obj上,被obj拥有或者包含,所以this指代的是obj
// 隐含的丢失
// 隐含绑定丢失了他的绑定,这就意味着它要退回到默认绑定
// function foo() {
// console.log(this.a);
// };
// var obj = {
// a: 2,
// fooo: foo,
// };
// var bar = obj.fooo;
// var a = 3;
// bar();
// 接下来我们考虑一下传递一个回调函数
// function foo(){
// console.log(this.a);
// };
// function doFoo(fn){
// fn();
// };
// var obj = {
// a: 2,
// fooo: foo,
// };
// var a = 3;
// doFoo(obj.fooo);
// 明确绑定
// 隐含绑定: 我们不得不改变目标对象使它自身包含一个对函数的引用,而后使用这个函数引用属性来间接的,将this绑定到这个对象上。
// 明确绑定: 我们强制一个函数调用使用某个特定的对象作为this绑定
// function foo(){
// console.log(this.a);
// };
// var obj = {
// a: 2,
// };
// foo.call( obj );
// 当然我们也可以传递原始的类型值(string boolean number),这个类型值会被包装在他的对象类型中,new String() new Number()...
// function sum(){
// // console.log(this+2); chai boxing
// console.log(this); //boxing
// };
// sum.call(5);
// 硬绑定
// 有时候,单独依靠明确绑定仍然不能为我们先前提到的问题提供解决方案,也就是函数丢失原本的this绑定,或者被第三方框架覆盖,等问题。
// function foo(){
// console.log(this.a);
// };
// var obj = {
// a: 2,
// };
// var bar = function(){
// foo.call( obj );
// };
// var a = 3;
// bar();
// bar.call(window);//不会被覆盖
// 用硬绑定将一个函数包装起来的最典型的方法,是为所有传入的参数和传出的返回值创建一个通道
// function foo(something){
// console.log(this.a , something);
// return this.a + something;
// };
// var obj = {
// a: 2,
// };
// var bar = function(){
// return foo.apply( obj,arguments );
// };
// var b = bar( 3 );
// console.log( b );
// 由于硬绑定是一个非常常用的模式,它已作为ES5中的內建工具提供:
// Function.prototype.bind
// 如下使用
// function foo(something){
// console.log(this.a,something);
// return this.a + something;
// };
// var obj = {
// a: 2,
// };
// var bar = foo.bind(obj);
// var b = bar( 3 );
// console.log( b );
// new 绑定
// js中构造器的定义:构造器仅仅是一个函数,它们偶然的被前置的new操作符调用,它们不依附于类,它们也不初始化类,它们本质上只是一般的函数,在被使用new来调用时改变了行为。
// 当在函数前面被加入new调用时,也就是构造器调用时,下面这些事情会自动完成
// 1.一个全新的对象会凭空创建
// 2.这个新构建的对象会被接入原型链(prototype-linked)
// 3.这个新构建的对象被设置为函数调用的this绑定
// 4.除非函数返回一个它自己的其他对象,这个被new调用的函数将自动返回这个新构建的对象。
// 绑定的顺序
// 函数中的this绑定规则的优先级
// function foo() {
// console.log( this.a );
// }
// var obj1 = {
// a: 2,
// foo: foo
// };
// var obj2 = {
// a: 3,
// foo: foo
// };
// obj1.foo(); // 2
// obj2.foo(); // 3
// obj1.foo.call( obj2 ); // 3
// obj2.foo.call( obj1 ); // 2
// =====得出结论===>明确绑定 的优先权要高于 隐含绑定
// function foo(something) {
// this.a = something;
// }
// var obj1 = {
// foo: foo
// };
// var obj2 = {};
// obj1.foo( 2 );
// console.log( obj1.a ); // 2
// obj1.foo.call( obj2, 3 );
// console.log( obj2.a ); // 3
// var bar = new obj1.foo( 4 );
// console.log( obj1.a ); // 2
// console.log( bar.a ); // 4
// =====得出结论===>new绑定 的优先级要高于 隐含绑定
// 总结this
// 现在,我们可以按照优先顺序来总结一下this的规则。
// 1.new 绑定
// 2.硬绑定
// 3.明确绑定
// 4.隐含绑定
// 5.默认绑定
// 以上,就是理解对于普通的函数调用来说的this绑定规则所需的全部。
// 当然还有一些特殊的特例
// 如果你传递null或undefined作为call,apply或bind的this绑定参数,那么这些值会被忽略掉,取而代之的是 默认绑定 规则将适用于这个调用。
// function foo() {
// console.log( this.a );
// console.log( this );
// }
// var a = 2;
// foo.call( null );
// 扩展
// 词法this 简单来说就是用一个变量保存this
// 我们刚刚涵盖了一般函数遵守的4种规则。但是ES6引入了一种不适用于这些规则特殊的函数:箭头函数(arrow-function)。
// 最后,复习一下
// 为执行中的函数判定this绑定需要找到这个函数的直接调用点。找到之后,4种规则将会以 这个 优先顺序施用于调用点:
/*
1、被new调用?使用新构建的对象。
2、被call或apply(或 bind)调用?使用指定的对象。
3、被持有调用的环境对象调用?使用那个环境对象。
4、默认:strict mode下是undefined,否则就是全局对象。
*/
网友评论