V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
palmers
V2EX  ›  程序员

请大家指点一个 javaScript 继承代码,代码如下

  •  
  •   palmers · 2016-04-27 15:23:08 +08:00 · 3082 次点击
    这是一个创建于 3127 天前的主题,其中的信息可能已经有所发展或是发生改变。
    function Person() {
    	this.sname = '测试' ;
    	this.age = 23 ;
    	this.sex = '男' ;
    	Person.prototype.say = function() {
    		return this.sname + ' , ' + this.age + ' , ' + this.sex ;
    	} ;
    }
    
    
    function Student() {
    
    	Student.prototype = new Person() ;
    	Student.prototype.constructor = Student ;
    	this.school = 'xxx 大学' ;
    }
    
    var stu = new Student() ;
    alert(stu.__proto__) ;
    alert(stu.sname) ; //undefined
    

    为什么stu 没有继承Person 的属性呢? 只能访问自己的。 Student 的原型是[object Object], 请大家指点!谢谢大家!

    23 条回复    2016-04-28 20:39:21 +08:00
    ykjsw
        1
    ykjsw  
       2016-04-27 15:29:35 +08:00   ❤️ 1
    第一次 var stu = new Student() ;的时候, function Student 里面的 Student.prototype = new Person() ; 还没来得及执行

    你再次执行一次
    var stu = new Student() ;
    alert(stu.__proto__) ;
    alert(stu.sname) ;

    就是正确的了
    mrsatangel
        2
    mrsatangel  
       2016-04-27 15:37:04 +08:00
    Student.prototype = new Person() ;
    Student.prototype.constructor = Student ;
    移出构造函数体内
    mrsatangel
        3
    mrsatangel  
       2016-04-27 15:39:37 +08:00   ❤️ 2
    原因是执行 var stu = new Student() ;的时候在 Student 这个函数里面执行了修改 Student 的 prototype 的行为,但是这个修改不会影响当前这个 stu 对象的构造,也就是说当前的 stu 对象实际上并没有继承 Person 。再一次使用 Student 构造函数的时候所构造的实例才继承了 Person
    suikator
        4
    suikator  
       2016-04-27 15:42:30 +08:00 via Android
    这种继承写法不太好吧,万一 Person 是有参的怎么办
    jsonline
        5
    jsonline  
       2016-04-27 15:47:28 +08:00
    因为链接 __proto__ 与 prototype 是构造的最后一步
    palmers
        6
    palmers  
    OP
       2016-04-27 15:52:15 +08:00
    @ykjsw 为什么呢?
    palmers
        7
    palmers  
    OP
       2016-04-27 15:53:08 +08:00
    @mrsatangel 这个在哪里可以找到官方解释呢?
    palmers
        8
    palmers  
    OP
       2016-04-27 15:53:37 +08:00
    @suikator 恩 我随便举例的
    jsonline
        9
    jsonline  
       2016-04-27 15:57:37 +08:00   ❤️ 2
    learnshare
        10
    learnshare  
       2016-04-27 16:01:01 +08:00
    sex 不是性别, gender 才是;
    #2 的回答比较合适,可以翻翻 JS 权威指南第 6 版,其他书里也应该有讲到类和继承的实现方式
    palmers
        11
    palmers  
    OP
       2016-04-27 16:04:34 +08:00
    @jsonline 谢谢
    palmers
        12
    palmers  
    OP
       2016-04-27 16:05:22 +08:00
    @learnshare 嘿嘿 随便取的 我去看看 谢谢!
    sodatea
        13
    sodatea  
       2016-04-27 16:25:16 +08:00
    new 的过程

    ## ES5
    1. new: https://es5.github.io/#x11.2.2
    2. 我们只关心最后一步,调用 [[Construct]] https://es5.github.io/#x13.2.2
    3. 设置 prototype 在 5-7 步,调用构造函数在第 8 步,晚于前者

    ## ES2017
    流程是类似的,不过用词改了很多
    1. https://tc39.github.io/ecma262/#sec-evaluatenew
    2. https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
    3. 设置 prototype 属性在第 5.a 步, OrdinaryCreateFromConstructor 方法 https://tc39.github.io/ecma262/#sec-ordinarycreatefromconstructor
    调用构造函数是第 11 步

    通俗的解释就是 MDN 上说的那些
    palmers
        14
    palmers  
    OP
       2016-04-27 16:33:12 +08:00
    @sodatea 非常感谢 非常感谢! 很全面!
    kisnows
        15
    kisnows  
       2016-04-27 16:50:43 +08:00
    ```
    function Student() {
    Student.prototype = new Person() ;
    Student.prototype.constructor = Student ;
    this.school = 'xxx 大学' ;
    return Student.prototype
    }
    ```
    你可以这样改一下,虽然还是肯定不对,但是这样应该会好一点。
    其实就像 2 楼说的,你新建 student 实例的时候, Student 的 prototype 上还什么都没有。你需要理解一下 new 操作符都干了哪些事情,可以看看我的这篇文章,也许可以帮助你理解。
    [JavaScript 中的类和继承]( https://www.kisnows.com/2016/03/21/class%20and%20inherit%20in%20JavaScript/)
    palmers
        16
    palmers  
    OP
       2016-04-27 18:44:20 +08:00
    @kisnows 好的 谢谢!
    SmiteChow
        17
    SmiteChow  
       2016-04-27 21:42:38 +08:00
    martianyi
        18
    martianyi  
       2016-04-28 00:29:55 +08:00
    es6 大法好,说实话, es5 我也不会这么写
    palmers
        19
    palmers  
    OP
       2016-04-28 09:02:10 +08:00
    @SmiteChow 谢谢 提供代码实例, 但是对我来说好深奥哦~~ 我大概能理解到是使用空对象来桥接实现继承? 不知道我理解的对不对 非常感谢!!! 请问 您的链接后面 "显示 Gist 代码" 是怎么做到的? 是什么 markdown 语法
    palmers
        20
    palmers  
    OP
       2016-04-28 09:02:32 +08:00
    @martianyi 嘿嘿 我是前端小白 见笑
    xcodebuild
        21
    xcodebuild  
       2016-04-28 10:11:01 +08:00
    这种写法即使写对了也有很大的隐患,例如下面的代码

    function Person() {
    this.accounts = []
    }

    function Student() {
    }

    Student.prototype = new Person()

    var a = new Student()
    var b = new Student()

    a.accounts.push({github: 'https://github.com/IAmA'})

    console.log(b.accounts[0].github) // "https://github.com/IAmA"

    对 a 的原型链上的引用变量进行操作时同时改变了 b 的原型链上的值
    SmiteChow
        22
    SmiteChow  
       2016-04-28 11:49:19 +08:00   ❤️ 1
    @palmers 是的,主要是为了抹平 new Person() 和 直接写 Person() 的差别,要不然
    Person() 只是普通的函数调用
    new 出来的东西才是真正意义上的 instance

    显示 gist 是 V 站自带的功能
    palmers
        23
    palmers  
    OP
       2016-04-28 20:39:21 +08:00
    @SmiteChow thank you 非常感谢!!!!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5183 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 09:43 · PVG 17:43 · LAX 01:43 · JFK 04:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.