javascript 原型链和闭包问题

    function Person(first, last) {
        var fName = first;
        var lName = last;

        function firstName(first) {
            return first ? (fName = first) : fName;
        };

        function lastName(last) {
            return last ? (lName = last) : lName;
        };

        return {
            firstName: firstName,
            lastName: lastName
        }
    }
    Person.prototype = {
        show: function() {
            console.log("show");
        }
    }

    var person = new Person("michael", "jackson");
    console.log(person);

    function Book(name, author) {
        this.name = name;
        this.author = author;
    };
    Book.prototype = {
        show: function() {
            console.log("show");
        }
    }
    var book = new Book("java", "me");
    console.log(book);

代码如上图,Person类我使用闭包的方式创建实现private,Book类使用原型的方式创建,当我在给原型添加方法的时候,为什么Person类添加不了,Book类就可以添加成功

阅读 4.9k
8 个回答

当代码 new foo(...) 执行时:

  1. 一个新对象被创建。它继承自foo.prototype.

  2. 构造函数 foo 被执行。执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例。new foo 等同于 new foo(), 只能用在不传递任何参数的情况。

  3. 如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象,ps:一般情况下构造函数不返回任何值,不过用户如果想覆盖这个返回值,可以自己选择返回一个普通对象来覆盖。当然,返回数组也会覆盖,因为数组也是对象。

综上所述,以你的代码为例:

    function Person(first, last) {
        var fName = first;
        var lName = last;

        function firstName(first) {
            return first ? (fName = first) : fName;
        };

        function lastName(last) {
            return last ? (lName = last) : lName;
        };

        return {
            firstName: firstName,
            lastName: lastName
        }
    }
    Person.prototype = {
        show: function() {
            console.log("show");
        }
    }

下面这行代码发生了三件事情:

new Person("michael", "jackson"); //等同于下面的代码
//**************************
var o = Object.create(Person.prototype); //对应上面的`1`
var other = Person.apply(o, ["michael", "jackson"]);//对象上面的`2`
return typeof other === 'object' ? other : o; //对应上面的`3`

很明显,new Person("michael", "jackson")的结果在第三步的时候已经被取代了

参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new

    function Person(first, last) {
        var fName = first;
        var lName = last;

        function firstName(first) {
            return first ? (fName = first) : fName;
        };

        function lastName(last) {
            return last ? (lName = last) : lName;
        };

        this.firstName = firstName
        this.lastName = lastName
    }

我一般用闭包的封装一个模块,return出来接口(暴露接口),然后调用。
你发现,return出来的是一个对象,所以而不是用构造函数生成的对象,你只是用函数去生成对象。
发现自己解释不清楚,等待其他答案。

在new function()的时候,如果function的返回值是对象的话则返回该对象,否则返回function的实例
你的Person的返回值是个字面量对象,因此你的person变量是一个字面量对象,而不是Person的实例,所以没有Person中的原型方法
浏览器控制台数据结果也能看出来(贴图比较麻烦,就把结果粘贴过来了)
返回字面量对象的结果:
Object {}

firstName: firstName(first)
lastName: lastName(last)
__proto__: Object

如果是Person的实例话,结果如下:
Person

__proto__: Object
    show: ()
    __proto__: Object

function Person()中你返回了一个object对象,所以在你执行Person.prototype时Person已经不是function (这里指"类")了,而是一个object,而object是没有.prototype一说的。自己也瞧见了,Book中你没有返回对象,所以原型链上有了show方法。 ~~

工厂函数和构造函数应该分开,比如你在写Java的时候,一个类的构造函数就不会返回一个对象吧(实际上构造函数是么都返回不了)

你的这种写法叫工厂函数,应该这么用:

function person(first, last) { //《JavaScript语言精粹》中,老道提到,工厂函数最好使用非大写
    var fName = first;
    var lName = last;

    return {
        firstName: function (first) {
            return first ? (fName = first) : fName;
        },
        lastName: function (last) {
            return last ? (lName = last) : lName;
        },
        prototype: {
            show: function() {
                console.log("show");
            }
        }
    }
}

var aPerson = person("michael", "jackson");
console.log(aPerson);

同意 @iknight 的回答。

函数Person通过new操作符后它是一个构造函数,在构造函数执行的过程中,首先会创建一个新对象object,该对象就是当前实例,而它的所属类的原型指向Person,即object.__proto__ === Person.prototype,最后构造函数默认返回当前实例。

题主这时手动返回一个字面量对象object2,此时它是Object构造函数的实例,所以它的所属类原型应该是指向Object构造函数的原型,即object2.__proto__ === Object.prototype,因此它是不能使用Person.prototype上的方法的

function foo(){return 1}

var t1=new foo();
typeof t1 === 'number'
说明t1根本不是对象,不管你给foo怎么加原型属性都没用。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏