javascript - 问一个JS继承的问题

 炙天痕_953 发布于 2022-11-09 05:24
function Tree () {}

Tree.prototype.leaf = 0
Tree.prototype.addLeaf = function () {this.leaf++}

let tree1 = new Tree()
let tree2 = new Tree()

tree1.addLeaf()
tree1.addLeaf()

console.log(tree2.leaf) 

更新:这里我把箭头函数去掉下
为什么输出是0.......求解惑

7 个回答
  • 我赞同一楼的回答,但是还有一问想请解答:
    当Tree的原型对象里面有一个对象字面量属性时,情况似乎不太一样了:

    var Tree = function(){};
    Tree.prototype.men = {
        age:15
    };
    Tree.prototype.setAge = function(){this.men.age = 20};
    var tree1 = new Tree();
    var tree2 = new Tree();
    tree1.setAge(20);
    console.log(tree2.men); // {age:20}

    请问,这里为什么又是20?为什么没有在tree1里单独创建一个属性,而是修改的是原型上值?

    2022-11-12 01:41 回答
  • 没看懂,你这描述里面没有箭头函数啊?
    如果你问的就是你所写的代码,那可以这样解释:因为你没有执行实例上的这个函数啊!

      tree2.addLeaf();  

    那当然最后tree2.leaf还是0了!

    2022-11-12 01:41 回答
  • function Tree () {}
    
    Tree.prototype.leaf = 0
    Tree.prototype.addLeaf = function () {this.leaf++;debugger}
    
    let tree1 = new Tree()
    let tree2 = new Tree()
    
    tree1.addLeaf()
    tree2.addLeaf()
    
    console.log(tree2.leaf) 
    

    结果为1,你倒数第二句语句打错了

    2022-11-12 01:41 回答
  • console.log(leaf)
    NaN
    2022-11-12 01:41 回答
  • 很简单,this指向与原型问题。

        function Tree () {}
        
        Tree.prototype.leaf = 0 //这一步,所有的new Tree都会获得一个公共的 leaf 属性
        
        //关键在与这里的 this.leaf. 箭头函数没有独自的this,这里的this会指向的是window. 所以是 window.leaf++
        Tree.prototype.addLeaf = () => {this.leaf++}
        
        let tree1 = new Tree()
        let tree2 = new Tree()
        
        tree1.addLeaf() //window.leaf自加了1
        tree1.addLeaf() //window.leaf自加了1
        
        console.log(tree2.leaf) 
    2022-11-12 01:41 回答
  • 来晚了,根据楼主的更新,谈下自己的理解,抛砖引玉。。。:

    this.leaf++ 可以看做:

    this.leaf = this.leaf + 1
    

    this本身原来是是没有leaf属性的,所以会去this的原型链上找,结果在Tree.prototype找到了(Tree.prototype.leaf = 0),所以这句可以看成:

    this.leaf = 0 + 1
    

    相当于在this上增加了leaf属性为1,下次访问this.leaf已经不会从原型链取值了。
    所以tree1执行完2次addLeaf之后是:

    { leaf: 2 }
    

    而tree2还是空的,自身没有leaf属性,tree2上访问leaf属性仍会去原型链上找,原型上leaf还是0。

    2022-11-12 01:41 回答
  • 首先是箭头函数内部 this 指向的问题,
    箭头函数内部本身没有 this ,内部 this 只能通过作用域链往上查找.
    所以

    Tree.prototype.addLeaf = () => {this.leaf++}

    这里的 this 指向 window.

    然后...没时间了, 领导要我打扫办公室卫生. 下面这个 demo 你先看着. 等会回来再说..
    https://jsfiddle.net/pqjag5vj/

    OK, 回来了, 题目也改了

    Tree.prototype.addLeaf = function () {
        this.leaf++
    }
    tree1.addLeaf()
    tree1.addLeaf()

    说说执行 tree1.addLeaf() 这句代码的时候发生了什么,
    JS 函数内部 this 指向只有在调用的时候才确定,
    那么, tree1 调用 addLeaf 的时候, addLeaf 内部 this 是指向 tree1 的.
    也就是说,执行 tree1.addLeaf() , addLeaf 函数其实相当于

    function () {
        tree1.leaf++
    }

    然后就是实例属性与原型属性同名问题.
    虽然可以实例可以通过原型链访问到原型中的值, 但是不能通过对象实例重写原型中的值.
    所以, tree1.leaf 中的 leaf 就是在实例上创建的属性, 后面执行 tree1.addLeaf 的时候修改的也是 tree1 上的 leaf 属性, 并非原型上的 leaf 属性.

    当 tree2 访问 leaf 属性的时候, 还是按照原型链往上找,
    原型上的 leaf 并没有给修改, 所以还是 0.

    那么, 我们怎么修改得让它符合预期, 使他修改原型上的属性呢, 一种是我上面给出的 demo , 通过 proto 对象实例的属性(它指向对象构造函数的原型对象) 来访问并修改原型上的属性.
    还有通过apply, bind, call 等方法, 把 addLeaf 的 this 绑定到希望的原型对象上.

    2022-11-12 01:41 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有