OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

JavaScript中的继承,构造函数以及new关键字的作用


分享到
分类 大话编程   关键字 JavaScript   发布 kris  1407809075995
注意 转载须保留原文链接,译文链接,作者译者等信息。  
通常一个构造函数是这样子的,它带有一个area的原型方法,在构造函数中传入长、宽并计算面积。

var Shape = function(width, height) {
    this.width = width;
    this.height = height;
};
Shape.prototype.area = function() {
    return this.width * this.height
};
var shape = new Shape(20, 30);
shape.area();
> 600

输出很完美,这也是经典JavaScript实现继承的方法,通过prototype添加对另外一个对象的引用。

不过一部分JavaScript程序是非常讨厌new关键字的,这个关键字有太浓烈的Java烙印了,而且掩盖了JavaScript基于原型的本质,降低了程序员使用JS语言的效率,因此你想把它省了,看看结果?

注* "JavaScript The Good Parts“的作者Douglas Crockford 曾写道  "A much better alternative is to not use new at all." (page 49),    参见另一程序员对AngularJS的吐嘈, 你已经毁了JavaScript(吐嘈之一就是里面到处都是new)

var shape = Shape(20, 30);
shape.area();
> TypeError: Cannot read property 'area' of undefined

道理再简单不过了,你只不过是执行了一个函数,但是这个函数并没有返回值,所以shape必然是undefined,看来new关键作用之一跟Java是一样的,就是实例化此对象并返回这个对象本身。所以你又试改写了一下函数:

var Shape = function(width, height) {
    var self = this;
    self.area = function() {
        return width * height;
    }
    return self;
};
var shape = Shape(20, 30);
shape.area();
> 600

不错,It works!也不用实例化Shape了,看上去一切正常,代码看上去更简单了,隐藏了不必要的属性,不过似乎你没有意识到你设计了一个潜在的更大的坑,尝试在console中打印这些:

area
> function () { return self.width * self.height; }

为什么are变成了全局变量?你不死心,又在window里打印
window.area
> function () { return width * height; }

结果还一样,其实这一现象在"Javascript: The Good Parts"一书中有很好的解析:

If you forget to include the new prefix when calling a constructor function, then this will not be bound to the new object. Sadly, this will be bound to the global object, so instead of augmenting your new object, you will be clobbering global variables. That is really bad. There is no compile warning, and there is no runtime warning. (page 49)

如果你在一个构造函数中忘了加new,那么这个新对象就不会绑定到新的实例上,不幸的是,它会绑定到全局对象上,你就会影响全局变量。这是非常糟糕的。没有编译警告,并且没有运行时的警告。(第49页)

看来在function函数内使用this绑定公开属性是非常危险的,因为你不确定会不会有人忘写了一个new,或者故意不加一个new,也许这就是为什么基于function的构造函数现在用得越来越少的原因吧,其实解决的办法非常简单,只需更改一处。

var Shape = function(width, height) {
    var self = {};
    self.area = function() {
        return width * height;
    }
    return self;
};

var shape = Shape(20, 30);
shape.area(); >600

其实还有很多其它的解决方案,还有一些开源项目甚至根本不使用构造函数,在此不再累述。

社区评论 ( Beta版 )
  • #0 iSayme 1407821393779
    function Shape(width, height) {
    
      if (!(this instanceof Shape)) {
        return new Shape(width, height);
      }
    
      this.width = width;
      this.height = height;
    
      return this;
    }
    
    Shape.prototype.area = function() {
      return this.width * this.height
    };
    
    
    var shape = Shape(20, 30);
    
    console.log(shape.area());
    
  • #1 kris 1407821880268

    @iSayme #0

    呵,这种解决方案比较正统

  • #2 己删除 1407855250956
  • #3 glen 1408280521990

    单例以后,如何实现继承?个人觉得new挺好,有效的隔绝了作用域。

  • #4 kris 1408327175484
    @glen #3

    这个得看个人喜好,基于Object就基本上需要使用Object.create来继承,不过需要单独写一个方法来进行构造函数的工作,如:

    var Shape = function() {
    
        var width  = 0
          , height = 0;
    
        //构造函数
        var init = function(w, h) {
            width  = w;
            height = h;
        }
    
        var area = function() {
            return width * height;
        }
    
        return { init: init, area: area };
    };
    
    //实例化
    var shape = Shape();
    shape.init(20, 30)
    shape.area();
    
    //继承
    var square = Object.create(Shape());
    square.init(30, 30);
    square.area();
    

    基于Function与基于Object皆可,不过个人最近比较倾向于基于Object的。而且构造函数被提取出来以后,一旦构造规则发生改变,再写一个构造函数即可,不会对原有功能造成影响。

  • #5 魏寸为 1437391041508

    f

  • #6 魏寸为 1437391073968

    可以用原型继承,var a = Object.create(obj);

  • #7 nk 1462928959292
    var shape  ={};
    shape  = function(w,h){ return w* h;}
    

    这里提出一个简单的方法,但是稍微复杂或者要带参建议使用new关键字构造方法,如果单单是工具,那么直接封装到一个全局变量就行了。

  • #8 nk 1462929078585
    shape.area = function(w,h){ return w* h;}   //上面掉参
    

    不可修改,不可删除的评论是不是不科学?

  • #9 赵才交 1489143233763

    范文芳 范德萨都是第三方发到付

  • #10 任厌无 1489415976843

    1

  • #11 孙妈丹 1502788858814

    ..

OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. OurJS-免费开源的博客引擎,论坛系统,网站模板和轻量级的CMS
  2. 痛苦的Java程序员
  3. JavaScript:世界上误解最深的语言
  4. 我不懂Swift
  5. 微软开源TypeScript编绎器
  6. CSS字体大小: em与px、pt、百分比之间的对比
  7. 开源的多行字符串工具: 在JS中整段地写HTML
  8. 树树莓派推出新版本Model B+
  9. 在nginx中使用lua脚本
  10. Google官方支持的NodeJS访问API,提供后台登录授权
  11. AirJD-简单好用的免费建站工具

 相关阅读 - 大话编程
  1. fibjs 比 nodejs 快五倍
  2. 痛苦的Java程序员
  3. OneBody:开源的社交网络,邮件列表,词典和内容管理系统
  4. 我不懂Swift
  5. 2014 Hangjs 见闻流水账第一天
  6. Linux 桌面的发展之路!
  7. 为什么我不建议你将JavaScript作为主力语言
  8. 静态web的回归
  9. CoffeeScript的箭头为何重要
  10. 什么是最好的编程语言?(怎样才能爱上编程呢?)

 关键字 - JavaScript
  1. 如何用CSS将select/option文本居中或居右对齐
  2. 用原生HTML5控件实现输入框自动提示(下拉列表补全)功能
  3. JavaScript中怪异的地方
  4. 在JavaScript中创建命名空间的几种写法
  5. JavaScript中的继承,构造函数以及new关键字的作用
  6. 纽约时报使用Html5 WebRTC记录访问者IP地址
  7. 正则中test、exec、match的简单区别,以及括号的用法
  8. NativeScript的工作原理:用JavaScript调用原生API实现跨平台
  9. 2015年的JavaScript:Angular之类的框架将被库取代
  10. 少年,不要滥用箭头函数啊:JS中lambda表达式的优缺点和使用场景

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号