函数也有上下文与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>

子窗口:

<!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>
        
<href="javascript:invoke();invokeSelf()">调用父窗口函数</a>
        
        
<div id="log"></div>
    
</body>
</html>

下面是运行结果:

Code
原文地址:https://www.cnblogs.com/evlon/p/1592078.html