Home > Web Front-end > JS Tutorial > Elegant use of This in js

Elegant use of This in js

php中世界最好的语言
Release: 2018-06-04 10:48:55
Original
1460 people have browsed it

This time I will bring you the elegant use of This in js. What are the precautions for the elegant use of This in js? The following is a practical case, let's take a look.

When a function is called, an activity record (execution context) is created.


This record will contain information such as where the function was called (call stack), the calling method of the function, the parameters passed in, etc.

This is one of the attributes recorded and will be used during function execution.

This points neither to the function itself nor to the scope of the function.

This is actually the binding that occurs when the function is called, and what it points to depends entirely on where the function is called.

In strict mode, this points to undefined when a general function is called.

1. Why use this

This provides a more elegant way to implicitly "pass" a reference to an object, so the API can be designed to be more concise and easy to reproduce. use.

eg:

var me = {  
    name: "fenfei"  };  
  
//不使用this,调用  function speak(name){  
    console.log("Hello, I'm "+ name);  
}  
speak(me.name);     //Hello, I'm fenfei  
  //使用this,调用  function speak(){  
    console.log("Hello, I'm "+ this.name);  
}  
speak.call(me);     //Hello, I'm fenfei
Copy after login


2. Two misunderstandings about this

(1) this points to the function itself;

(2) this Points to the scope of the function.

Scope cannot be accessed through JavaScript code, it exists inside the JavaScript engine. Whenever you mix this with lexically scoped lookups, be sure to remind yourself that this is impossible!

This is bound at runtime, not at writing time. Its context depends on various conditions when the function is called. The binding of this has nothing to do with the location of the function declaration, it only depends on the calling location of the function (that is, how the function is called)!

3. Binding rules

1) Default binding

The most commonly used function call type: independent function call. Think of this rule as the default rule when no other rules can be applied.

eg:

function foo() {  console.log(this.a);
}var a = 2;
foo(); // 2
Copy after login

2) Implicit rules

The rule of implicit binding is whether there is a context object at the calling location, or whether it is owned or included by an object.

function foo() {  console.log(this.a);
}var obj = {    a: 2,    foo: foo
};
obj.foo(); // 2
Copy after login

. When foo() is called, this is bound to obj, so this.a and obj.a are the same.

But sometimes implicit loss occurs.

function foo() {  console.log(this.a);
}var obj = {    a: 2,    foo: foo
};var bar = obj.foo; // 函数  var a = "oops, global"; //bar(); // "oops, global"
Copy after login

. Although bar is a reference to obj.foo, it actually refers to the foo function itself.

So bar() at this time is actually a function call without any modification, and the default binding is applied.
3) Display binding

call and apply

. In JavaScript, call and apply are like this's parents. They must live wherever this lives, and they have to obey! When there are no parameters, the current object is window
eg:

var name="全局";var xpg={    name:"局部"};function getName(){
    alert(this.name);
}
getName(xpg);//全局getName.call(xpg);//局部getName.call();//全局
Copy after login

. Among them, this is in the function getName. No matter where this is, you must find the location when the function is running. At this time, the position of the function getName when it is running, for

(1) getName(xpg); //Global
Obviously, the object where the function getName is located is window, so the home of this must be in the window, that is, pointing to
window object, then this.name returned by getName is actually window.name, so the alert comes out as "global"! (2)getName.call(xpg);//Partial
. Among them, call specifies that the home of this is the xpg object, because this is forced to settle only in xpg, then this points to the xpg object at this time, this.name is actually xpg.name, so the alert comes out as "local" !

bind()

. The bind method is provided starting from es5, so ie9 only supports
eg:

function f(){  
   return this.a;  
} 
var g = f.bind({a : "test"});   
//想把某个对象作为this的时候,就把它传进去,得到一个新对象gconsole.log(g()); // test      
 //重复调用的时候,this已经指向bind参数。
 //这对于我们绑定一次需要重复调用依然实现绑定的话,会比apply和call更加高效(看下面这个例子)var o = {a : 37, f : f, g : g};
Copy after login

console.log(o.f(), o.g()); // 37, test //o.f() passes the object Attribute call, this points to object o; //What is special is that even if we call the newly bound method as an attribute of the object, //o.g() will still follow the previous binding, so the answer is test is not g


4) new binding

new’s this binding cannot be modified!

New calling function will automatically perform the following operations:

(1) Create (or construct) a brand new object;
(2) This new object will be connected by executing [[Prototype]] ;
(3) This new object will be bound to this of the function call;
(4) If the function does not return other objects, then the function call in the new expression will automatically return this new object.
eg:

function Person(name,age) {  this.name = name  this.age = age  console.log("我也只不过是个普通函数")
}
Person("zxt",22) // "我也只不过是个普通函数"console.log(name) // "zxt"console.log(age) // 22var zxt = new Person("zxt",22) // "我也只不过是个普通函数"console.log(zxt.name) // "zxt"console.log(zxt.age) // 22
Copy after login

In the above example, a Person function is first defined, which can be called either normally or in the form of a

constructor. . When called normally, it will be executed as a normal function and a string will be output.
. If it is passed through a new operator, a new object is constructed.
. When making a normal call, as mentioned before, the default binding rules are applied and this is bound to the global object. At this time, two attributes, name and age, will be added to the global object.
. When called through the new operator, the function will return an object. From the output result, it can be seen that the this object is bound to the returned object.

Therefore, the so-called new binding means that when a function is called through the new operator, a new object will be generated, and this in the constructor will be bound to this object.

4. Priority

new binding>call\apply, etc. Display binding>Implicit binding>Default binding.

了解了函数调用中this绑定的四条规则,需要做的就是找到函数的调用位置并判断对应哪条规则。

(1)函数是否是new绑定?如果是,this绑定的是新创建的对象。
var bar = new Foo();
(2)函数是否通过call、apply显示绑定或硬绑定?如果是,this绑定的是指定的对象。
var bar = foo.call(obj);
(3)函数是否在某个上下文对象中隐式调用?如果是,this绑定的是那个上下文对象。
var bar = obj.foo();
(4)上述全不是,则使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局window对象。
var bar = foo();

new绑定和call、apply无法一起使用,因此不能使用new foo.call(obj).

五、this绑定例外

1)被忽略的绑定

如果你把null或者undefined作为this的绑定对象传入call、apply或者bind。
这些值在调用时会被忽略,实际应用的是默认绑定规则。
eg:

function foo() {  console.log(this.a);
}var a = 2;
foo.call(null); // 2
Copy after login

2)间接引用
eg:

function foo() {  console.log(this.a);
}var a = 2; 
var o = { a: 3, foo: foo }; 
var p = { a: 4 }; 
o.foo(); // 3(p.foo = o.foo)(); // 2
Copy after login

赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo()。
3)当前对象不明确时的this

当没有明确的执行时的当前对象时,this指向全局对象window。
例如对于全局变量引用的函数上我们有:

var name = "Tom";var Bob = {    name: "Bob",    show: function(){
        alert(this.name);
    }
}var show = Bob.show;
show();  //Tom
Copy after login

。你可能也能理解成show是window对象下的方法,所以执行时的当前对象时window。但局部变量引用的函数上,却无法这么解释:

var name = "window";var Bob = {    name: "Bob",    showName: function(){
        alert(this.name);
    }
};var Tom = {    name: "Tom",    showName: function(){        var fun = Bob.showName;
        fun();
    }
};
Tom.showName();  //window
Copy after login

4)在浏览器中setTimeout、setInterval和匿名函数执行时的当前对象是全局对象window:

var name = "Bob";  
var nameObj ={  
      name : "Tom",  
      showName : function(){  
          alert(this.name);  
      },  
      waitShowName : function(){  
          setTimeout(this.showName, 1000);  
      }  
 };  
 nameObj.waitShowName();
Copy after login

5)软绑定
eg:

var count=2;var obj={    count:0,    cool:function coolFn(){        console.log(this.count);//0
         var self=this;        if(self.count<1){
            setTimeout(function timer(){
                self.count++;                console.log("awesome?");                console.log(self.count);//1
                console.log(this.count);//2
            },100);
        }
    }
};
obj.cool();
Copy after login

6)dom事件中的this

(1)直接在dom元素中使用

分析:对于dom元素的一个onclick(或其他如onblur等)属性,它为所属的html元素所拥有,直接在它触发的函数里写this,this应该指向该html元素。

(2)给dom元素注册js函数

a、不正确的方式

<script type="text/javascript">
  function thisTest(){
  alert(this.value); // 弹出undefined, this在这里指向??}</script><input id="btnTest" type="button" value="提交" onclick="thisTest()" />
Copy after login

。分析:onclick事件直接调用thisTest函数,程序就会弹出undefined。
因为thisTest函数是在window对象中定义的, 所以thisTest的拥有者(作用域)是window,thisTest的this也是window。而window是没有value属性的,所以就报错了。

b、正确的方式

<input id="btnTest" type="button" value="提交" /><script type="text/javascript">
  function thisTest(){
  alert(this.value); 
}document.getElementById("btnTest").onclick=thisTest; 
//给button的onclick事件注册一个函数</script>
Copy after login

。分析:在前面的示例中,thisTest函数定义在全局作用域(这里就是window对象),所以this指代的是当前的window对象。
而通过document.getElementById(“btnTest”).onclick=thisTest;这样的形式,其实是将btnTest的onclick属性设置为thisTest函数的一个副本,在btnTest的onclick属性的函数作用域内,this归btnTest所有,this也就指向了btnTest。

因为多个不同的HTML元素虽然创建了不同的函数副本,但每个副本的拥有者都是相对应的HTML元素,各自的this也都指向它们的拥有者,不会造成混乱。
eg:

<input id="btnTest1" type="button" value="提交1" onclick="thisTest()" /><input id="btnTest2" type="button" value="提交2" /><script type="text/javascript">function thisTest(){this.value="提交中";
}var btn=document.getElementById("btnTest1");
alert(btn.onclick); //第一个按钮函数var btnOther=document.getElementById("btnTest2");
btnOther.onclick=thisTest;
alert(btnOther.onclick); //第二个按钮函数</script>
Copy after login

其弹出的结果是:

//第一个按钮function onclick(){
  thisTest()
}//第二个按钮function thisTest(){  this.value="提交中";
}
Copy after login

7)this词法(ES6:箭头函数)

箭头函数不使用function关键字定义,而是使用“胖箭头”的操作符=>定义;箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。
eg:

function foo(){    return (a)=>{        //this继承自foo
        console.log(this.a);
    };
}var obj1={    a:2}var obj2={    a:3}var bar=foo.call(obj1);
bar.call(obj2);//2不是3!
Copy after login

foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this被绑定到obj1,bar(引用箭头函数)的this也被绑定到obj1,而箭头函数的绑定无法修改。(new的也不能!)

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样利用JS做出引用传递与值传递

使用JS实做出加密解密操作

The above is the detailed content of Elegant use of This in js. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template