javascript 引用传递

在 Javascript 中,我们使用函数并且传递参数来调用函数。但是 Javascript 到底是如果传递你所传递的参数呢?当你开始面向对象的开发时,你可能会陷入有时可以访问你的对象有时又不能访问困惑。

在传递字符串或数字的这样的基本类型变量时,情况是按值传递的。这意味着,在函数中对该变量所做的任何更改都不会影响到外部的传递竟来的变量。让我们来看看下面的例子:


function myfunction(x) {
	// x 等于 4
	x = 5;
	// x 现在是 5
}

var x = 4;
console.log(x); // x 等于 4
myfunction(x);
console.log(x); // x 依然是 4

然而,在传递对象的时候是通过引用传递的。在这种情况下,该对象任何属性在函数中都是可以被改变的,让我们来看看另一个例子:


function myClass() {
	this.value = 5;
}

var obj = new myClass();
console.log(obj.value); // obj.value = 5

function fun(f) {
	f.value = 6;
}

fun(obj); // 函数中改变对象的值
console.log(obj.value); // obj.value 现在等于 6

所以,当你传递对象的时候会发生什么?大多数人会觉得(或者至少我觉得),它会通过引用传递可以访问它属性的方法。不幸的是,事实并非如此。看看这个例子:


function myClass() {
	this.value = 5;
}

myClass.prototype.add = function() {
	this.value++;
}

var o = new myClass();
console.log(o.value); // o.value = 5

o.add();
console.log(o.value); // o.value = 6

function fun(f) {
	f(); // 运行传递进来的函数
}

fun(o.add); // 调用对象的函数
console.log(o.value); // sorry, 依旧是 6

这里的问题是使用“this” 关键字。这是一个指向当前对象的上下文便捷引用。虽然我们将函数作为参数传递了进去,但是我们并没有把当前对象(当前的“this”)也一同传递进去,所以执行改函数的时候对象上下文丢失。更准确地说,this现在指向新函数调用的上下文而不是我们刚刚传递进来的对象的函数的上下文。对于一个独立的函数二样, this 可能是 window 对象的上下文,对于时间调用的函数二样, this 可能是一个 event object。简单的证明示例:

// node.js 默认全局变量是 global
if (typeof window !== 'undefined') {
	// 客户端 js 默认是 window
	global = window;
}

function fun() {
	console.log('this === global: ' + (this === global)); // true
}

fun();

function myClass() {

}

myClass.prototype.test = function() {
	console.log('this === global: ' + (this === global));
	console.log('this instanceof myClass: ' + (this instanceof myClass));
};

var c = new myClass();
c.test();

结果

this === global: true
this === global: false
this instanceof myClass: true

解决方案:

1.当你知道方法名的时候


function objectchanger(obj) {
	obj.add(); // 将对象传递进来,通过对象调用函数
}
objectchanger(o);
alert(o.value); // 值为 7

2.当你不知道方法名的时候


function objectchanger(fnc, obj) {
	fnc.call(obj); // 通过 call 来调用函数,并指定其 this 指向。
}
objectchanger(o.add, o);
alert(o.value); // 值为 7

英文原文:http://snook.ca/archives/javascript/javascript_pass

很久以前看的文章存在草稿箱今天顺便拿出来翻译了。其实有挺多想总结的但是一下子憋不出来,就不多引申了。

Advertisements

C++ Lambda表达式基本用法

创建一个匿名函数并执行。Objective-C采用的是上尖号^,而C++ 11采用的是配对的方括号[]。实例如下:

#include <iostream>
using namespace std;

int main()
{
	[]{
		cout << "Hello,Worldn"; 
	}();
}

我们也可以方便的将这个创建的匿名函数赋值出来调用:

#include <iostream>
using namespace std;

int main()
{
	int i = 1024;
	auto func = [](int i) { // (int i) 是指传入改匿名函数的参数
		cout << i;
	};
	func(i);
}

捕获选项

  • [] Capture nothing (or, a scorched earth strategy?)
  • [&] Capture any referenced variable by reference
  • [=] Capture any referenced variable by making a copy
  • [=, &foo] Capture any referenced variable by making a copy, but capture variable foo by reference
  • [bar] Capture bar by making a copy; don’t copy anything else
  • [this] Capture the this pointer of the enclosing class

[] 不捕获任何变量

#include <iostream>
using namespace std;

int main()
{
	int i = 1024;
	auto func = [] { cout << i; };
	func();
}

vs 报错
error C3493: 无法隐式捕获“i”,因为尚未指定默认捕获模式
error C2064: 项不会计算为接受 0 个参数的函数

g++ 报错:
error: ‘i’ is not captured

要直接沿用外部的变量需要在 [] 中指名捕获。

[=] 拷贝捕获

#include <iostream>
using namespace std;

int main()
{
	int i = 1024;
	auto func = [=]{  // [=] 表明将外部的所有变量拷贝一份到该函数内部
		cout << i;
	};
	func();
}

结果:
1024

#include <iostream>
using namespace std;

int main()
{
	int i = 1024;
	auto fun1 = [=]{
		// fun1 内存在 i
		cout << i; // 1024
		auto fun2 = []{ // 未指名捕获, i 不存在
			cout << i;
		};
		fun2();
	};
	fun1();
}

[&] 引用捕获

#include <iostream>
using namespace std;

int main()
{
	int i = 1024;
	cout << &i << endl;
	auto fun1 = [&]{
		cout << &i << endl;
	};
	fun1();
}

结果:
0x28ff0c
0x28ff0c

[=, &] 拷贝与引用混合

#include <iostream>
using namespace std;

int main()
{
	int i = 1024, j = 2048;

	cout << "i:" << &i << endl;
	cout << "j:" << &j << endl;

	auto fun1 = [=, &i]{ // 默认拷贝外部所有变量,但引用变量 i
		cout << "i:" << &i << endl;
		cout << "j:" << &j << endl;
	};
	fun1();
}

结果
outside i:0x28ff0c
outside j:0x28ff08
inside i:0x28ff0c
inside j:0x28ff04

[bar] 指定引用或拷贝

#include <iostream>
using namespace std;

int main()
{
	int i = 1024, j = 2048;

	cout << "outside i value:" << i << " addr:" << &i << endl;

	auto fun1 = [i]{
		cout << "inside  i value:" << i << " addr:" << &i << endl;
		// cout << j << endl; // j 未捕获
	};
	fun1();
}

结果:
outside i value:1024 addr:0x28ff08
inside i value:1024 addr:0x28ff04

#include <iostream>
using namespace std;

int main()
{
	int i = 1024, j = 2048;

	cout << "outside i value:" << i << " addr:" << &i << endl;

	auto fun1 = [&i]{
		cout << "inside  i value:" << i << " addr:" << &i << endl;
		// cout << j << endl; // j 未捕获
	};
	fun1();
}

结果:
outside i value:1024 addr:0x28ff08
inside i value:1024 addr:0x28ff08

#include <iostream>
using namespace std;

int main()
{
	int i = 1024, j = 2048, k;

	cout << "outside i:" << &i << endl;
	cout << "outside j:" << &j << endl;

	auto fun1 = [i, &j]{
		cout << "inside  i:" << &i << endl;
		cout << "inside  j:" << &j << endl;
		// cout << k; // k 未捕获
	};
	fun1();
}

结果:
outside i:0x28ff0c
outside j:0x28ff08
inside i:0x28ff00
inside j:0x28ff08

[this] 捕获 this 指针

#include <iostream>
using namespace std;

class test
{
public:
	void hello() {
		cout << "test hello!n";
	};
	void lambda() {
		auto fun = [this]{ // 捕获了 this 指针
			this->hello(); // 这里 this 调用的就是 class test 的对象了
		};
		fun();
	}
};

int main()
{
	test t;
	t.lambda();
}