• 首页
  • javascript
  • javascript 下 匿名函数到底有没有原型链,是否能继承?

javascript 下 匿名函数到底有没有原型链,是否能继承?


javascript中函数成为一等公民后,导致很多其他语言函数所没有的功能,也正是这些特性让javascript更加灵活.

函数可以是一个变量,可以是一个参数,可以是一个返回值,可以是一个类,可以是一个方法.....够灵活吧.


其中高阶函数是javascript中闭包的实现基础,而闭包又是javascript高度灵活的体现.今天和大家分享的是一种特殊的函数,匿名函数.


如其名一样,就是没有名字的函数,这种匿名函数用到的地方很多,比如jquery 的大部分实现都用了匿名函数.


为什么要这样用? 因为javascript语言本身的缺陷使得它是一门没有私有作用域的语言,它不像一些高级语言一样,有命名空间或者包名,有私有变量等.但是javascript中的函数却有私有作用域.

var blog='一介布衣';

(function(blogName){
    var blog=blogName;
    (function(){
        var blog='笔记';
        console.log(blog);
    })();
    console.log(blog);
})('网络日志');
console.log(blog);

上面代码嵌套了2层匿名自启动函数.

结果如下:

从内到外依次打印出来.

我们看下函数内部的是不是可以访问函数外部的变量,我们保留最外边的.

var blog='一介布衣';

(function(blogName){
    //var blog=blogName;
    (function(){
        //var blog='笔记';
        console.log(blog);
    })();
    console.log(blog);
})('网络日志');
console.log(blog);

我把里面2层的 var blog 注释掉以后看结果:

可以看到全部的console.log 都打印出了最外层的 blog 变量.

我们试想下函数外面能不能访问函数里面的变量

//var blog='一介布衣';

(function(blogName){
    //var blog=blogName;
    (function(){
        var blog='笔记';
        console.log(blog);
    })();
    console.log(blog);
})('网络日志');
console.log(blog);

运行结果:


笔记

undefined

undefined


可见函数内部确实是有作用域的.

var blog='一介布衣';

(function(blogName){
    //var blog=blogName;
    (function(){
        //var blog='笔记';
        console.log(blog);
    })();
    console.log(blog);
})('网络日志');
console.log(blog);

这一段代码典型的说明了javascript中基于原型链的语言特色, 第二层内的匿名函数打印 blog 变量时,首先在本层查找,找不到以后开始在上一层匿名函数中查找,找不到的话接着在全局作用域查找,最后终于找到了 var blog='一介布衣';


我们的问题来了:匿名函数有没有原型链?能不能被继承?

在网上找到一篇文章说: 匿名函数因为没有函数名,所以没有引用,我个人认为有一点点问题,如果有出入,请你告知我,非常感谢,QQ:378989619


我个人认为:匿名函数有引用

    (function(){
        //var blog='笔记';
        console.log(blog);
    })();

就上面这个匿名自启动函数,我们把上面的匿名函数分成2部分.

第一部分:

(function(){
        var blog='笔记';
        console.log(blog);
})

第二部分

();

其实就是从最后的圆括号分隔开了.我们现在运行一下 第一部分看看.

可以看到直接返回了匿名函数的定义,其实这里就是返回了一个匿名函数的引用,你也可以理解为一个指针,我们如何让这个匿名函数执行呢?就是在引用后面加上 (); 也就是加上第二部分即可.


上面的验证告诉我们匿名函数是有引用的.


下一个问题: 匿名函数有没有原型链? 答案是有!

这里面首先要弄清楚一个前提,上面样的函数才有原型链.

我随便定义一个方法是没有原型链的,或者说prototype 属性是不可见的/不可用的.

当我用构造函数创建一个新对象时,注意:这时的构造函数才有原型链 prototype 属性.

而被new 出来的函数实例是没有 prototype 属性的,但是它有一个 __proto__ 的只读属性,这个属性是一个指针,指向了构造函数的原型链.

总结一下:

1.function a(){ ...}  a 没有没有 prototype 属性/或者说是prototype不可见/不可用.

2.var b=new a();   这时 a 有了prototype 属性, b 没有prototype 属性,但是b 有 __proto__ 属性.


可见只有构造函数prototype才是可用/可见的.那我们上面说了匿名函数也有原型链,说明它可用当构造函数.

var c=new function(){
    this.name='匿名函数';
 };
console.log(c.__proto__);

上面我们创建了函数实例c ,c是由匿名函数当构造函数 new 出来的.最后我们打印 c.__proto__ (这个属性应该指向构造函数的prototype 属性)

结果:

[object Object]

这里直接下结论说匿名函数有原型链可能为时过早,我们通过下面一种方法来佐证.


javascript中没有继承,但是因为函数的私有作用域和原型链特性,我们可以用原型链来模拟继承.

如果想让 a 函数继承 b函数,我们只要让a的原型属性 prototype 指向 b函数的实例即可. (相当于b是a的上一级作用域,所以a能访问到b的所有变量,方法)

抛出问题:我们只要只能匿名函数是可以继承的,说明匿名函数是有原型链的.

先命名一个函数:

function ct(name){
    this.name=name;
}

然后我们把ct 函数的原型指向匿名函数的一个实例,匿名函数有属性和方法.

ct.prototype=new function(){
    this.name='匿名函数';
    this.setName=function(newName){
        this.name=newName;
        return '已修改';
    };
    this.getName=function(){
        return this.name;
    }
};

上面我们已经证明匿名函数是可以当构造函数的. 它包含一个字段 name ,2个方法 getName 和 setName .

我们再定义一个函数:

var t=new ct('一介布衣');

可以看到 t 是 ct 函数的一个实例,而我们的ct 函数又继承自匿名函数, 如果 t 实例有 name 字段 和 getName,setName 方法,说明ct 继承了匿名函数的实例.

console.log(t.__proto__,t.name,t.setName('李天王'),t.getName());

结果:

ct 函数实例 t  的 __proto__属性指向了ct 的原型. 实例 t 拥有了匿名函数实例的 属性和全部方法.可见 ct 函数原型继承了匿名函数.

所以,匿名函数有原型链并且可以继承.



回到顶部