最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JS中this的几种情况

    正文概述 掘金(CV菜菜子)   2021-03-12   402

    this的几种情况

    this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

    1. 情况1: 给元素的某个事件行为绑定方法,事件触发,方法执行,此时方法中的this一般指向当前元素本身

     function fn() {	
    	 	console.log(this);
    	 }
     btn.onclick = fn.bind(window);
    	 //=>fn.bind(window)首先会返回一个匿名函数(AM),把AM绑定给事件;点击触发执行AM,AM中的THIS是元素,但是会在AM中执行FN,FN中的THIS是预先指定的WINDOW
    

    DOM0

    1. DOM0:DOM0就是直接通过 onclick写在html里面的事件.
    2. DOM0的事件具有极好的跨浏览器优势, 会以最快的速度绑定, 如果你通过DOM2绑定要等到JS运行, DOM0不用, 因为DOM0是写在元素上面的哇;
    btn.onclick = function anonymous() {
    		 	console.log(this); //=>元素
    		 };
    

    DOM2

    1. DOM2是通过addEventListener绑定的事件, 还有IE下的DOM2事件通过attachEvent绑定;
    btn.addEventListener('click', function anonymous() {
    		 	console.log(this);  //=>元素
    		 }, false);
     btn.attachEvent('onclick',function anonymous(){
    		//  <= IE8浏览器中的DOM2事件绑定
    		 	console.log(this); //=>window
    		 });
    
    

    2. 情况2:普通函数执行,它里面的THIS是谁,取决于方法执行前面是否有“点”,有的话,“点”前面是谁THIS就是谁,没有THIS指向WINDOW(严格模式下是UNDEFINED)

    function fn() {
    			console.log(this);
    		}
    let obj = {
    			name: 'OBJ',
    			fn: fn
    		}; 
    
    fn(); //window
    obj.fn(); //obj
    console.log(obj.hasOwnProperty('name')); //=>hasOwnProperty方法中的this:obj  TRUE
    console.log(obj.__proto__.hasOwnProperty('name')); //=>hasOwnProperty方法中的this:obj.__proto__(Object.prototype)  FALSE
    console.log(Object.prototype.hasOwnProperty.call(obj, 'name')); //<=> obj.hasOwnProperty('name') true
    
    
    1. hasOwnProperty:用来检测某个属性名是否属于当前对象的私有属性
    2. in是用来检测是否为其属性(不论私有还是公有)
     console.log(obj.hasOwnProperty('name')); //=>true
     console.log(obj.hasOwnProperty('toString')); //=>false
     console.log('toString' in obj); //=>true
    
    1. 匿名函数执行,this一般都是window

    3. 情况3:构造函数执行(new xxx),函数中的this是当前类的实例

    function Fn() {
    			console.log(this);
    			//=>this.xxx=xxx 是给当前实例设置私有属性
    		}
    let f = new Fn;
    

    4. 情况4:箭头函数

    1. 箭头函数中没有自身的THIS,所用到 的THIS都是其上下文中的THIS
    2. 箭头函数没有的东西很多:
    • 他没有prototype(也就是没有构造器),所以不能被new执行
    • 他没有arguments实参集合(可以基于...args剩余运算符获取)
    1. 对比
     let obj = {
    			name: 'OBJ',
    			fn: function () {
    				 console.log(this); //=>obj
    				let _this = this;
    				return function () {
    					 console.log(this); //=>window
    					_this.name = "小明";
    				};
    			}
    		};
    		let ff = obj.fn();
    		ff(); 
    
    // 箭头函数的情况
    let obj = {
    			name: 'OBJ',
    			fn: function () {
    				 console.log(this); //=>obj
    				return () => {
    				 console.log(this); //=>箭头函数,所在上下文的this,obj
    				};
    			},
    			f1: ()=>{
    			    console.log(this) //window
    			}
    		};
    let ff = obj.fn();
    ff(); 
    let ff1=obj.f1()
    
    1. setTimeout的this:
    • 它的第一个参数是一个方法,传入的这个方法内部的this会被改写指向window
    let obj = {
    			name: 'OBJ',
    			fn: function () {
    				setTimeout(function () {
    					console.log(this) //this==window
    					this.name = "小明";
    				}, 1000);
    			}
    		};
    		obj.fn();
    

    setTimeout中的函数改用箭头函数

    		
    	
    		let obj = {
    			name: 'OBJ',
    			fn: function () {
    				setTimeout(_ => {
    					console.log(this) // this ==obj
    					this.name = "小明";
    				}, 1000);
    			}
    		};
    		obj.fn();
    

    5. 情况5:基于call/apply/bind可以改变函数中this的指向(强行改变)

    1. call/apply
    • 第一个参数就是改变的THIS指向,写谁就是谁(特殊:非严格模式下,传递null/undefined指向的也是window)
    • 唯一区别:执行函数,传递的参数方式有区别,call是一个个的传递,apply是把需要传递的参数放到数组中整体传递
       func.call([context],10,20) 
       func.apply([context],[10,20])
    
    1. bind
    • call/apply都是改变this的同时直接把函数执行了,而bind==不是立即执行函数==,属于预先改变this和传递一些内容 =>"柯理化"
    • 并且,绑定的时候可以额外传参数,执行的时候也可以额外传参数。
    1. 改变方法
     Function.prototype={
    			call
    			apply
    			bind
    		};
    

    之后会单独出一篇手写call,apply,bind的文章。

    bind源码分析

    • 输入:接受一个或者多个参数,第一个是要绑定的上下文,额外参数当作绑定函数的前置参数。
    • 输出:返回原函数的拷贝,即返回一个函数,这个函数具备原函数的功能
    ~ function anonymous(proto) {
    	 function bind(context) {
    		//context may be null or undefined
    		if (context == undefined) {
    			context = window;
    		}
    		if (typeof this !== 'function') {
               return;
            }
    		//获取传递的实参集合
    		// arguments {0:context,1:10,2:20,length:3} 传进来的arguments是一个类数组.不是真正的数组,所以不能用数组的slice方法
    		var args = [].slice.call(arguments, 1);//相当于arguments.slice,获取传递的实参集合.将arguments对象转为真正的数组并截取从第二项开始的参数.
    		//需要最终执行的函数。将执行bind()方法的这个函数保存在一个变量中,在下面改变函数执行作用域以及原型继承的时候会使用到:
    		var _this = this;
    		return function anonymous(ev) { //ev事件对象
    			var amArg = [].slice.call(arguments, 0);// // 获取_bind方法返回的函数的参数
    			_this.apply(context, args.concat(amArg));
    		};
    	} 
    	
    		//经过测试:apply的性能不如call
    		// es6的写法
    	function bind(context = window, ...args) {
    			return (...amArg) => this.call(context, ...args.concat(amArg));
     	}
    
     }(Function.prototype);
    

    call

    1.核心思路是:

    • 为传入的context扩展一个属性,将原函数指向这个属性
    • 将context之外的所有参数全部传递给这个新属性,并将运行结果返回。
    function add(c, d) {
      return this.a + this.b + c + d;
    }
    const obj = { a: 1, b: 2 };
    
    function es6call(context = window, ...args) {
    		//=>必须保证context是引用类型
    	context.$fn = this;// this:需要执行的函数  , add
    	let result = context.$fn(...args); //执行context.$fn(),就是要执行的函数add,并且把参数传进来,此时 this指向context
    	delete context.$fn;
    	return result;
    		} 
    		
    console.log(add.es6call(obj, 3, 4)); // 10
    

    apply

    • 要知道apply()与call()方法的区别在于第二位参数,apply()方法第二位参数也是传递给函数的参数,但是它是一个数组类型的
    function apply(context = window, args) {
    			context.$fn = this;
    			let result = context.$fn(...args);
    			delete context.$fn;
    			return result;
    		}
    

    起源地下载网 » JS中this的几种情况

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元