函数也有上下文与call与apply的区别
原来一直以为call和apply只是传递参数的形式不同:call使用参数列表,apply使用参数数组。但在跨窗口使用时,发现函数其中在 new 时,会传递上下文到函数中。于是函数实例也便有了上下文。
在我的这个测试中,也发现了 call 和 apply 的区别:call可以跨窗口调用传参调用函数,apply跨窗口调用有参数函数时出错。下面是测试,打开父窗口时,使用window.open打开一个子窗口,然后在子窗口中调用父窗口的函数以及对象:
父窗口:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Untitled</title>
<script type="text/javascript">
function Person(name)
{
this.name = name;
this.getName = function()
{
return this.name;
}
var sex = '男';
this.getSex = function()
{
return sex;
}
this.say = function(what)
{
return '[' + window.$room + '/' + room + ']' + '是' + this.getName() + ',' + this.getSex() + ' ' + what;
}
}
</script>
</head>
<body>
<script type="text/javascript">
//全局变量
var room = '房间';
window.$room = '房间';
var person = new window.Person('父窗口');
alert(person.say);
window.open('test2.html', 'test2');
</script>
</body>
</html>
<html>
<head>
<title>Untitled</title>
<script type="text/javascript">
function Person(name)
{
this.name = name;
this.getName = function()
{
return this.name;
}
var sex = '男';
this.getSex = function()
{
return sex;
}
this.say = function(what)
{
return '[' + window.$room + '/' + room + ']' + '是' + this.getName() + ',' + this.getSex() + ' ' + what;
}
}
</script>
</head>
<body>
<script type="text/javascript">
//全局变量
var room = '房间';
window.$room = '房间';
var person = new window.Person('父窗口');
alert(person.say);
window.open('test2.html', 'test2');
</script>
</body>
</html>
子窗口:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
</HEAD>
<body>
<script type="text/javascript">
window.alert = function(msg)
{
document.getElementById('log').innerHTML += msg + "<br/>";
}
function invoke()
{
//得到父窗口中的对象
var obj = window.opener.person;
//得到对象函数
var sayHandle = obj.say;
alert(window.opener.person.say('直接调用,成功'));
alert(sayHandle.call(window.opener.person, '直接使用全路径引用,使用 call 传参调用,成功'));
alert(sayHandle.call(obj, '使用对象引用,使用 call 传参调用,成功'));
try
{
alert(sayHandle.apply(window.opener.person, ['这里使用 apply 失败']));
}
catch(e)
{
alert(e);
}
try
{
alert(sayHandle.apply(obj, ['这里使用 apply 失败']));
}
catch(e)
{
alert(e);
}
}
//全局变量
var room = "子房间";
window.$room = '子房间';
function invokeSelf()
{
//得到父窗口中的函数定义
eval(window.opener.Person.toString());
//在全局中新建对象
window.person = new Person('子窗口');
//得到对象引用
var obj = window.person;
//得到函数引用
var sayHandle = obj.say;
alert(window.person.say('直接调用成功'));
alert(sayHandle.call(window.person, '直接使用全路径引用,使用 call 传参调用,成功'));
alert(sayHandle.call(obj, '使用对象引用,使用 call 传参调用,成功'));
alert(sayHandle.apply(window.person, ['直接使用全路径引用,使用 apply 传参调用,成功']));
//使用对象引用,使用 apply 传参调用,成功
alert(sayHandle.apply(obj, ['使用对象引用,使用 apply 传参调用,成功']));
//使用父窗口的函数, 使用本窗口数据
var sayHandle = window.opener.person.say;
alert(sayHandle.call(window.person, '直接使用全路径引用,使用 call 传参调用 父窗口的函数 ,成功但结果错'));
alert(sayHandle.call(obj, '使用对象引用,使用 call 传参调用 父窗口的函数 ,成功但结果错'));
try
{
alert(sayHandle.apply(window.person, ['直接使用全路径引用,使用 apply 传参调用 父窗口的函数,失败']));
}
catch(e)
{
alert(e);
}
try
{
alert(sayHandle.apply(obj, ['使用对象引用,使用 apply 传参调用 父窗口的函数 ,失败']));
}
catch(e)
{
alert(e);
}
}
</script>
<a href="javascript:invoke();invokeSelf()">调用父窗口函数</a>
<div id="log"></div>
</body>
</html>
<HTML>
<HEAD>
</HEAD>
<body>
<script type="text/javascript">
window.alert = function(msg)
{
document.getElementById('log').innerHTML += msg + "<br/>";
}
function invoke()
{
//得到父窗口中的对象
var obj = window.opener.person;
//得到对象函数
var sayHandle = obj.say;
alert(window.opener.person.say('直接调用,成功'));
alert(sayHandle.call(window.opener.person, '直接使用全路径引用,使用 call 传参调用,成功'));
alert(sayHandle.call(obj, '使用对象引用,使用 call 传参调用,成功'));
try
{
alert(sayHandle.apply(window.opener.person, ['这里使用 apply 失败']));
}
catch(e)
{
alert(e);
}
try
{
alert(sayHandle.apply(obj, ['这里使用 apply 失败']));
}
catch(e)
{
alert(e);
}
}
//全局变量
var room = "子房间";
window.$room = '子房间';
function invokeSelf()
{
//得到父窗口中的函数定义
eval(window.opener.Person.toString());
//在全局中新建对象
window.person = new Person('子窗口');
//得到对象引用
var obj = window.person;
//得到函数引用
var sayHandle = obj.say;
alert(window.person.say('直接调用成功'));
alert(sayHandle.call(window.person, '直接使用全路径引用,使用 call 传参调用,成功'));
alert(sayHandle.call(obj, '使用对象引用,使用 call 传参调用,成功'));
alert(sayHandle.apply(window.person, ['直接使用全路径引用,使用 apply 传参调用,成功']));
//使用对象引用,使用 apply 传参调用,成功
alert(sayHandle.apply(obj, ['使用对象引用,使用 apply 传参调用,成功']));
//使用父窗口的函数, 使用本窗口数据
var sayHandle = window.opener.person.say;
alert(sayHandle.call(window.person, '直接使用全路径引用,使用 call 传参调用 父窗口的函数 ,成功但结果错'));
alert(sayHandle.call(obj, '使用对象引用,使用 call 传参调用 父窗口的函数 ,成功但结果错'));
try
{
alert(sayHandle.apply(window.person, ['直接使用全路径引用,使用 apply 传参调用 父窗口的函数,失败']));
}
catch(e)
{
alert(e);
}
try
{
alert(sayHandle.apply(obj, ['使用对象引用,使用 apply 传参调用 父窗口的函数 ,失败']));
}
catch(e)
{
alert(e);
}
}
</script>
<a href="javascript:invoke();invokeSelf()">调用父窗口函数</a>
<div id="log"></div>
</body>
</html>
下面是运行结果:
Code
QQ:273352165
evlon#126.com
转载请注明出处。