zoukankan      html  css  js  c++  java
  • JS

    this指向最后调用该函数的对象

    		// 示例一:
    		var name = "windowsName";
    		function a() {
    		    var name = "Cherry";
                console.log(this) // window
    		    console.log(this.name);          // windowsName
    		    console.log("inner:" + this);    // inner: Window
    		}
    		a(); // 相当于 window.a()
    		console.log("outer:" + this) // outer:Window
            
    		
            // 示例二:
    		var name = "windowsName";
    		var a = {
    		    name: "Cherry",
    		    fn : function () {
    		    	console.log(this) // a
    		        console.log(this.name);      // Cherry
    		    }
    		}
    		window.a.fn(); // 相当于 a.fn()
            
            
    		// 示例三:
    		var name = "windowsName";
    		var a = {
    		    name: "Cherry",
    		    fn : function () {
    		    	console.log(this) // window
    		        console.log(this.name);      // windowsName
    		    }
    		}
    		var f = a.fn;
    		f(); // 相当于 window.f()
            
    
    		// 示例四:
    		var name = "windowsName";
    		function fn() {
    		    var name = 'Cherry';
    		    console.log(this) // window
    		    console.log(this.name);      // windowsName
    		    innerFunction();
    		    
    		}
    		function innerFunction () {
    	        console.log(this.name);   // windowsName
    	    }
    		fn() // 相当于 window.fn()
    

    匿名函数的 this 永远指向 window
    注意,这里我们没有使用严格模式,如果使用严格模式的话,全局对象就是 undefined,会报错 Uncaught TypeError: Cannot read property 'name' of undefined。

    	var name = "windowsName";
        var a = {
        	name : "Cherry",
        	func1: function () {
        		console.log(this.name)     
        	},
        	func2: function () {
        		console.log(this) // a
        		setTimeout(function () {// 匿名函数的 this 永远指向 window
        			console.log(this) //window
        			this.func1()
        		},100);
        	}
        };
        a.func2()     // this.func1 is not a function
    

    改变 this 的指向的几种方法:

    1. 使用 ES6 的箭头函数
    2. 在函数内部使用 _this = this
    3. 使用 apply、call、bind
    4. new 实例化一个对象

    1.箭头函数的 this 始终指向函数定义时的 this,而非执行时
    箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined

    	var name = "windowsName";
    	var a = {
        	name : "Cherry",
        	func1: function () {
        		console.log(this.name)     
        	},
    		func2: function () {
    		    setTimeout( () => {
                	console.log(this) // a,  不是window
    		    	this.func1()
    		    },100);
    		}
    	};
    	a.func2()     // Cherry
    

    2.在函数内部使用 _this = this。先将调用这个函数的对象保存在变量 _this 中,然后在函数中都使用这个 _this,这样 _this 就不会改变

    var name = "windowsName";
    var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)     
        },
        func2: function () {
            var _this = this;
            setTimeout( function() {
                _this.func1()
            },100);
        }
    };
    a.func2()       // Cherry
    

    3.使用 apply、call、bind 函数也是可以改变 this 的指向。
    3.1 apply
    语法:fun.apply(thisArg[, argsArray])
    含义:该方法调用一个函数, 使用该函数(fun)的方法,同时改变函数中this的指向为thisArg。
    参数:具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数
    thisArg:在 fun 函数运行时指定的 this 值。注意:指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
    argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。

    var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.apply(a),100); // 此处省略第二个参数
        }
    };
    a.func2()            // Cherry
    

    3.2 call
    语法:fun.call(thisArg[, arg1, arg2,....])
    注:与apply用法类似,不同之处:第二个参数为参数列表,使用逗号分割

    var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.call(a),100); // 此处省略第二个参数
        }
    };
    a.func2()            // Cherry
    

    3.3 bind
     语法:fun.bind(thisArg[, arg1, arg2, ...])()
    含义:bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列

    // 示例一:
    var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.bind(a)(),100);
        }
    };
    a.func2()            // Cherry
    
    // 示例二:
    var a ={
        name : "Cherry",
        fn : function (a,b) {
            console.log( a + b)
        }
    }
    var b = a.fn;
    b.bind(a,1,2)()           // 3
    

    对于不支持 bind 的浏览器,兼容性写法:

    		Function.prototype.bind = Function.prototype.bind || function(context) {
    		  var self = this;
    		  // console.log(this, context)
    		  return function() {
    		    console.log(arguments); // console [3,4] if ie<6-8>
    		    return self.apply(context, arguments);
    		 
    		  }
    		}
            
            // 调用
            var obj = {
    		  a: 1,
    		  b: 2,
    		  getCount: function(c, d) {
    		    return this.a + this.b + c + d;
    		  }
    		};
    		window.a = window.b = 0;
    		var func = obj.getCount.bind(obj)(3, 4);
    		var apply = obj.getCount.apply(obj, [3, 4]);
    		var call = obj.getCount.call(obj, 3, 4);
    
    		console.log(func, apply, call) // 10
            
            
       // 或者:
       Function.prototype.bind =  Function.prototype.bind || function( context ){ 
      	 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
           // 并且组合两次分别传入的参数,作为新的函数的参数
         } 
    };
    	// 调用
        var obj = { 
          	name: 'sven'
        };
        var func = function( a, b, c, d ){
        	alert ( this.name ); //    sven
        	alert ( [ a, b, c, d ] ) //    [ 1, 2, 3, 4 ]
        }.bind( obj, 1, 2 );  // obj ==> context
    
        func( 3, 4 );
    

    4.构造函数Sum,如果我们直接调用这个构造函数Sum(),那么这个this代表window对象;但是我们对它进行实例化var obj = new Sum(),这样this.a上的this代表当前对象obj;

    function Sum(a, b){
    	console.log(this); // 1=>window; 2=>实例化对象obj
    	this.a = a;
        this.b = b;
        this.add = function(){
        	console.log(this) // obj.add()=>实例化对象obj
        	return this.a+this.b;
        }
    }
    
    // 1.直接调用:
    Sum(2, 3);
    console.log(a, b); // 2, 3
    // 2.实例化:
    var obj = new Sum(2, 3);
    var num = obj.add();
    console.log(num); // 5
    

    new 的过程:

    1. 创建一个空对象 obj;
    2. 将新创建的空对象的隐式原型指向其构造函数的显示原型。
    3. 使用 call 改变 this 的指向
    4. 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话,那么直接直接返回该对象。
      注:构造器显式地返回了一个 object 类型的对象,那么此次运算结果最终会返回这个对象;
      构造器不显式地返回任何数据,或者是返回一个非对象类型的数据才会返回这个构造器实例
    function Person(name,age){
      this.name = name
      this.age = age
      return [1,2,3]
    }
    
    var p = new Person('taurus_wood', 20) // [1, 2, 3] // 数组的类型是对象
    
    function Person2(name,age){
      this.name = name
      this.age = age
      return 1
    }
    
    var p2 = new Person2('taurus_wood', 20) // {name:'taurus_wood', age: 20}
    

    代码显示实例化过程

    var a = new myFunction("Li","Cherry");
    // 伪代码表示:
    new myFunction{
        var obj = {};
        obj.__proto__ = myFunction.prototype; //建立了obj对象的原型链:obj->Animal.prototype->Object.prototype->null
        var result = myFunction.call(obj,"Li","Cherry");
        return typeof result === 'obj'? result : obj;
    }
    
    // 或者:
    Function.method('new', function() {
        // this指向Function对象
        // that是构造器对象
        var that = Object.create(this.prototype);
        // other是调用构造器之后生成的对象,跟这行代码一个意思: var other = new Person()
        var other = this.apply(that, arguments);
        // 如果它返回的不一个对象,就返回该新对象
        return (typeof other === 'object' && other) || that; 
    })
    

    函数调用的方法:

    1. 作为普通函数调用
    2. 函数作为方法调用(作为对象的方法调用)
    3. 使用构造函数调用函数(作为构造器调用)
    4. 作为函数方法调用函数(call、apply)

    1.单纯的函数调用

    // 如上例:
    var name = "windowsName";
    function a() {
        var name = "Cherry";
        console.log(this.name);          // windowsName
        console.log("inner:" + this);    // inner: Window
    }
    a(); // 单纯的函数调用
    console.log("outer:" + this)         // outer: Window
    

    2.函数作为对象的方法调用‘

    // 如上例:
    var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.bind(a)(),100);
        }
    };
    a.func2()    // Cherry 作为a对象的方法调用
    

    3.使用构造函数调用函数
    如上例
    4.作为函数方法调用函数(call、apply)
    在 JavaScript 中, 函数是对象。
    JavaScript 函数有它的属性和方法。
    call() 和 apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身

  • 相关阅读:
    HTML DOM Document 对象
    浏览器对象模型 BOM
    JavaScript数组和字符串基础
    JavaScript基础一
    css属性hack
    浏览器兼容性问题
    css常见居中方法
    初析BFC
    学习Css的初级篇
    THML基础学习
  • 原文地址:https://www.cnblogs.com/136asdxxl/p/9783722.html
Copyright © 2011-2022 走看看