JavaScript中with/this用法

1.with用法

为一个或一组语句指定默认对象。不过,with用法并不推荐!

用法:with (<对象>) <语句>;
with 语句通常用来缩短特定情形下必须写的代码量。在下面的例子中,请注意 Math 的重复使用:


x = Math.cos(3 * Math.PI) + Math.sin(Math.LN10);

y = Math.tan(14 * Math.E);

当使用 with 语句时,代码变得更短且更易读:

with (Math) {
   x = cos(3 * PI) + sin(LN10);
   y = tan(14 * E);

}


  • TAGS 
  • FILES
Use of the  with statement is not recommended, as it may be the source of confusing bugs and compatibility issues. See the "Ambiguity Con" paragraph in the "Description" section below for details.

Summary

Extends the scope chain for a statement.

Statement
Implemented inJavaScript 1.0
ECMAScript EditionECMA-262

Syntax

with (object) {
  statement
}

Parameters

object
Adds the given object to the scope chain used when evaluating the statement. The parentheses around object are required.
statement
Any statement. To execute multiple statements, use a  block statement ({ ... }) to group those statements.

Description

JavaScript looks up an unqualified name by searching a scope chain associated with the execution context of the script or function containing that unqualified name. The 'with' statement adds the given object to the head of this scope chain during the evaluation of its statement body. If an unqualified name used in the body matches a property in the scope chain, then the name is bound to the property and the object containing the property. Otherwise a 'ReferenceError' is thrown.

Using  with is not recommended, and is forbidden in ECMAScript 5  strict mode. The recommended alternative is to assign the object whose properties you want to access to a temporary variable.
(On a historical note, Firefox 1.5 used to generate a warning when the 'with' statement was used: "deprecated with statement usage". This has been removed in Firefox 1.5.0.1 ( bug 322430).)

Performance Pro & Con

  • Pro: 'with' can help reduce file size by reducing the need to repeat a lengthy object reference without performance penalty. The scope chain change required by 'with' is not computationally expensive. Use of 'with' will relieve the interpreter of parsing repeated object references. Note, however, that in many cases this benefit can be achieved by using a temporary variable to store a reference to the desired object.
  • Con: 'with' forces the specified object to be searched first for all name lookups. Therefore all identifiers that aren't members of the specified object will be found more slowly in a 'with' block. Where performance is important, 'with' should only be used to encompass code blocks that access members of the specified object.

Ambiguity Con

  • Con: 'with' makes it hard for a human reader or JavaScript compiler to decide whether an unqualified name will be found along the scope chain, and if so, in which object. So given this example:
    function f(x, o) {
      with (o) 
        print(x);
    }

    only when f is called is x either found or not, and if found, either in o or (if no such property exists) in f's activation object, where x names the first formal argument. If you forget to define x in the object you pass as the second argument, or if there's some similar bug or confusion, you won't get an error -- just unexpected results.

  • Con: Code using with may not be forward compatible, especially when used with something else than a plain object. Consider this example:
    function f(foo, values) {
        with (foo) {
            console.log(values)
        }
    }
         
         

    If you call f([1,2,3], obj) in an ECMAScript 5 environment, then the values reference inside the with statement will resolve to obj. However, ECMAScript 6 introduces a values property on Array.prototype (so that it will be available on every array). So, in a JavaScript environment that supports ECMAScript 6, the valuesreference inside the with statement will resolve to [1,2,3].values.

Example: Using with

The following with statement specifies that the Math object is the default object. The statements following the with statement refer to the PI property and the cos andsin methods, without specifying an object. JavaScript assumes the Math object for these references.

var a, x, y;
var r = 10;

with (Math) {
  a = PI * r * r;
  x = r * cos(PI);
  y = r * sin(PI / 2);
}

2.this 对象 

返回“当前”对象。在不同的地方,this 代表不同的对象。如果在 JavaScript 的“主程序”中(不在任何 function 中,不在任何事件处理程序中)使用 this,它就代表 window 对象;如果在 with 语句块中使用 this,它就代表 with 所指定的对象;如果在事件处理程序中使用 this,它就代表发生事件的对象。
一个常用的 this 用法:
<script>
...
function check(formObj) {
   ...
}
...
</script>
<body ...>
...
<form ...>
...
<input type="text" ... οnchange="check(this.form)">
...
</form>
...
</body>
这个用法常用于立刻检测表单输入的有效性。

Introduction

A function's this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.

In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it can be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called.

Global context

In the global execution context (outside of any function), this refers to the global object, whether in strict mode or not.

console.log(this.document === document); // true

// In web browsers, the window object is also the global object:
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37
   
   

Function context

Inside a function, the value of this depends on how the function is called.

Simple call

function f1(){
  return this;
}

f1() === window; // global object
  
  

In this case, the value of this is not set by the call. Since the code is not in strict mode, the value of this must always be an object so it defaults to the global object.

function f2(){
  "use strict"; // see strict mode
  return this;
}

f2() === undefined;
  
  

In strict mode, the value of this remains at whatever it's set to when entering the execution context. If it's not defined, it remains undefined. It can also be set to any value, such as null or 42 or "I am not this".

Note: In the second example,  this should be  undefined, because  f2 was called without providing any base (e.g.  window.f2()). This feature wasn't implemented in some browsers when they first started to support  strict mode. As a result, they incorrectly returned the  window object.

As an object method

When a function is called as a method of an object, its this is set to the object the method is called on.

In the following example, when o.f() is invoked, inside the function this is bound to the o object.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37
  
  

Note that this behavior is not at all affected by how or where the function was defined. In the previous example, we defined the function inline as the f member during the definition of o.  However, we could have just as easily defined the function first and later attached it to o.f. Doing so results in the same behavior:

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37
  
  

This demonstrates that it matters only that the function was invoked from the f member of o.

Similarly, the this binding is only affected by the most immediate member reference. In the following example, when we invoke the function, we call it as a method g of the object o.b. This time during execution, this inside the function will refer to o.b. The fact that the object is itself a member of o has no consequence; the most immediate reference is all that matters.

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42
  
  
... on the prototype chain

The same notion holds true for methods defined somewhere on the object's prototype chain. If the method is on an object's prototype chain, this refers to the object the method was called on, as if the method was on the object.

var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5
  
  

In this example, the object assigned to the variable p doesn't have its own f property, it inherits it from its prototype. But it doesn't matter that the lookup for f eventually finds a member with that name on o; the lookup began as a reference to p.f, so this inside the function takes the value of the object referred to as p. That is, since f is called as a method of p, its this refers to p. This is an interesting feature of JavaScript's prototype inheritance.

... or as a getter or setter

Again, the same notion holds true when a function is invoked from a getter or a setter. A function used as getter or setter has its this bound to the object from which the property is being set or gotten.

function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var o = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(o, 'modulus', {get: modulus, enumerable:true, configurable:true});

console.log(o.phase, o.modulus); // logs -0.78 1.4142
  
  

As a constructor

When a function is used as a constructor (with the new keyword), its this is bound to new object being constructed.

Note: while the default for a constructor is to return the object referenced by this, it can instead return some other object (if the return value  isn't an object, then thethis object is returned).

/*
 * Constructors work like this:
 *
 * function MyConstructor(){
 *   // Actual function body code goes here.  Create properties on |this| as
 *   // desired by assigning to them.  E.g.,
 *   this.fum = "nom";
 *   // et cetera...
 *
 *   // If the function has a return statement that returns an object, that
 *   // object will be the result of the |new| expression.  Otherwise, the
 *   // result of the expression is the object currently bound to |this|
 *   // (i.e., the common case most usually seen).
 * }
 */

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38
  
  

In the last example (C2), because an object was returned during construction, the new object that this was bound to simply gets discarded. (This essentially makes the statement "this.a = 37;" dead code. It's not exactly dead, because it gets executed, but it can be eliminated with no outside effects.)

call and apply

Where a function uses the this keyword in its body, its value can be bound to a particular object in the call using the call or apply methods that all functions inherit from Function.prototype.

function add(c, d){
  return this.a + this.b + c + d;
}

var o = {a:1, b:3};

// The first parameter is the object to use as 'this', subsequent parameters are passed as 
// arguments in the function call
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// The first parameter is the object to use as 'this', the second is an array whose
// members are used as the arguments in the function call
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
  
  

The bind method

ECMAScript 5 introduced Function.prototype.bind. Calling f.bind(someObject) creates a new function with the same body and scope as f, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used.

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty
  
  

As a DOM event handler

When a function is used as an event handler, its this is set to the element the event fired from (some browsers do not follow this convention for listeners added dynamically with methods other than addEventListener).

// When called as a listener, turns the related element blue
function bluify(e){
  console.log(this === e.currentTarget); // Always true
  console.log(this === e.target);        // true when currentTarget and target are the same object
  this.style.backgroundColor = '#A5D9F3';
}

// Get a list of every element in the document
var elements = document.getElementsByTagName('*');

// Add bluify as a click listener so when the element is clicked on,
// it turns blue
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}
  
  

In an in–line event handler

When code is called from an in–line handler, its this is set to the DOM element on which the listener is placed:

<button onclick="alert(this.tagName.toLowerCase());">Show this</button>
  
  

The above alert shows button. Note however that only the outer code has its this set this way:

<button onclick="alert((function(){return this}}()));">Show inner this</button>
  
  

In this case, the inner function's this isn't set so it returns the global/window object (i.e. the default object in non–strict mode where this isn't set by the call).


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值