读书笔记-JavaScript设计模式-02-this指向、call和apply

116 阅读3分钟

此篇依然是读书笔记,内容自然是关于老生常谈的this指向问题,以及callapply;

1.this的指向问题小结:

JavaScriptthis总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的this总是指向全局对象。在浏览器的JavaScript里,这个全局对象是window对象。

通常说来分为一下几种情况:

  • ECMAScript 5strict模式下:

    • 这种情况下的this已经被规定为不会指向全局对象,而是undefined
  • 当用new运算符调用函数时:

    • 该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象
  • 如果构造器显式地返回了一个object类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的this

  • 当用另外一个变量getName2来引用obj.getName,并且调用getName2时,根据提到的规律,此时是普通函数调用方式this是指向全局window的,所以程序的执行结果是undefined 示例如下:

    	var obj = {
    		myName: 'kobe',
    		getName: function(){
    			return this.myName;
    		}
    	};
    
    	console.log( obj.getName() ); // 输出:'kobe'
    
    	var getName2 = obj.getName;
    	console.log( getName2() ); // 输出:undefined
    

2.call和apply:

2.1 apply:

callapply更多的作用像是一个金手指外挂,可以窃取自身不具有的能力。

apply接受2个参数,第1个参数指定了函数体内this对象的指向,第2个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组

如果我们传入的第1个参数为null,函数体内的this会指向默认的宿主对象,在浏览器中则是window

	//当使用call 或者apply 的时候,如果我们传入的第一个参数为null,函数体内的this 会指向默认的宿主对象,在浏览器中则是window:
	var func = function( a, b, c ){
    
		alert ( this === window ); // 输出true
	};

	func.apply( null, [ 1, 2, 3 ] );

Function.prototype.bind:用来指定函数内部的this指向,即使没有原生的Function.prototype.bind实现,我们来模拟一个也不是难事,代码如下:

	Function.prototype.bind = function(){
    
		var self = this, // 保存原函数
        
		context = [].shift.call( arguments ), // 需要绑定的this 上下文
        
		args = [].slice.call( arguments ); // 剩余的参数转成数组
    
		return function(){ // 返回一个新的函数
      
			return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) );
      
				// 执行新的函数的时候,会把之前传入的context 当作新函数体内的this
      
				// 并且组合两次分别传入的参数,作为新函数的参数
		}
    
	};

可以借用Array.prototype.push方法的对象还要满足以下两个条件:

  • 对象本身要可以存取属性
  • 对象的length属性可读写

一个number类型的数据不可能借用到Array.prototype. push方法:

var a = 1;

Array.prototype.push.call(a,'first');

alert(a.length);// undefined

一个函数当作this传入Array.prototype.push方法时:

var func = function(){};

Array.prototype.push.call( func, 'first' );

alert(func.lenght)//cannot assign to read only property ‘length' of function(){}

call的话,这里就不想过多的讲解了,除了和apply传参不一样,其他基本没差别。