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 函数原型继承了匿名函数.
所以,匿名函数有原型链并且可以继承.