当作为函数参数提供时,有没有一种方法可以访问对象属性而不引用对象?

Som*_*ave 4 javascript

假设您有一个像var obj = {a:'foo',b:'bar'}您提供给函数的对象,function equal(x) { return x.a === x.b}; 是否有办法提供对象参数作为作用域,以像这样删除函数内的对象引用function equal(x) { return a === b};

旁注:语法最好与ECMAScript 5th Edition一起使用

Rationale: The idea behind the question is to cover cases where the object argument holds many properties {a:'foo',b:'bar',...,z:'baz'}, which would require repeating the object name quiet often.

Ful*_*Guy 6

In ES6 we can use the destructuring assignment to get the mapping of the key-values in variables:

var obj = {a:'foo',b:'bar'};

//Using ES6 Destructuring syntax
function equal({a, b}) { return a === b};
console.log(equal(obj));

obj = {a:'bar',b:'bar'};
console.log(equal(obj));
Run Code Online (Sandbox Code Playgroud)


VLA*_*LAZ 5

You can use with to change the scope:

function equal(x) {
  with(x) { //try to dereference any undeclared variable as a property of x
    return a === b; //an implied x.a === x.b
  }
}

console.log(equal({a: "foo", b: "bar"}));
console.log(equal({a: "baz", b: "baz"}));
Run Code Online (Sandbox Code Playgroud)

However, using with is not recommended, as it makes things less clear: consider the following examples:

window.a = 1; //a global


function test() {
  var a = 2; //a local variable that shadows the global
  var foo = {
    a: 3 //property of the object
  };

  with (foo) {
    console.log(a); //what is this?
  }
}

test();
Run Code Online (Sandbox Code Playgroud)

This example is actually fairly straight forward - the logged result is 3 as with (foo) changes the context and the first lookup would be foo itself. However, this can get very confusing, very quickly:

window.a = 1; //a global


function test() {
  var foo = {
    a: 3 //property of the object
  };

  with (foo) {
    var a = 2; //a local variable that shadows the global
    console.log(a); //what is this?
  }
  
  console.log(foo); //what about this?
}

test();
Run Code Online (Sandbox Code Playgroud)

Boom, you've now walked into one of the many traps that with has. I just moved one line down a bit and you'd expect that it still does the same. But it doesn't - with changes the scope a = 2 now refers to the property of the foo object. Yes, there is var in front of it but since you don't get a new functional scope inside with, that doesn't actually create a new binding but re-uses the one from the current scope. You are actually changing the foo object with this line, even if you didn't want to. Now, consider your example slightly modified:

window.a = "foo"; //some global defined somewhere

var b = "foo"; //variable that exists in the scope enclosing the function

function equal(x) {
  with(x) {
    return a === b; // actually might resolve as x.a or a or window.a === x.b or b or window.b;
  }
}

var incompleteInput = {a: "foo"};
var emptyInput = {};
console.log(equal(incompleteInput));
console.log(equal(emptyInput));
Run Code Online (Sandbox Code Playgroud)

If you pass in input that doesn't have one of the properties you use inside with. It becomes very hard to figure out what you're actually checking when you're not explicit.

So, while with technically fulfils your requirement, it's a bad idea to use it. There are many pitfalls about using it and those can very well lead to subtle bugs that could be hard to track down and fix. This is why the usage of the with statement is not recommended.