1

构造函数内部:

tips:

在构造函数内部通过this(用于指向当前对象)变量添加属性或方法,
此处定义的属性和方法都是为对象自身所拥有,
每次通过类创建实例时, this指向的属性都会得到相应的创建.

var Person = function(name, sex) {
    // 私有属性: 只能被【私有方法】和【特权方法】访问
    var contact = 'xxxxx@qq.com';
    var number = '88888888';

    // 私有方法: 在构造函数里声明, 能被【私有函数】【特权方法】访问, 只能访问【私有方法】和【私有属性】
    var getInfo = function(name, sex) {
        console.log('My name is ' + name + ', I’m a ' + sex + '!');
        console.log('My email is ' + contact);
    };

    // 公有属性
    this.name = name;
    this.sex = sex;

    // 特权方法: 可以访问【私有属性】【私有方法】【公有属性】
    this.intro = function() {
        getInfo(name, sex);
    };
    this.getContact = function(number) {
        console.log(number);
    };

    // 构造器
    this.getContact(number);
};

构造函数外部:

tips:

通过点语法定义的属性和方法不会添加到新创建的对象,因此类的实例无法访问, 只能通过类的自身(Person)访问.

// 类静态公有属性(对象不能访)
Person.isChinese = true;

// 类静态公有方法(对象不能访问到)
Person.speak = function() {
    console.log('what???');
};

类的原型:

tips:

一种是为原型对象属性赋值, 另一种是将一个对象赋值给类的原型对象.
通过prototype继承的属性或方法是每个对象通过prototype访问到的,
所以每次通过类创建实例时, 这些属性和方法不会再次创建.

Person.prototype = {
    // 显示指定对象的constructor属性
    constructor: Person,
    // 公有属性
    hobby: 'reading',
    // 公有方法
    sport: function() {
        console.log('run');
    }
};

// test:
var tony = new Person('Tony', 'man', '25');

console.log('--- 访问【公有属性】 ---');
console.log(tony.name);            // Tony
console.log(tony.sex);            // man

console.log('--- 访问【特权方法】 ---');
console.log(tony.intro());        // My name is Tony, I’m a man!
                                // My email is xxxxx@qq.com

console.log('--- 访问【类静态公有属性】和【类静态公有方法】 ---');
console.log(tony.isChinese);     // undefined
console.log(tony.speak());        // undefined

console.log('--- 通过类自身访问【类静态公有属性】和【类静态公有方法】 ---');
console.log(Person.isChinese);    // true
console.log(Person.speak());    // what???

console.log('--- 访问【公有属性】及【公有方法】 ---');
console.log(tony.hobby);        // reading
console.log(tony.sport());        // run


// 通过闭包实现:
var Person = (function() {
    // 静态私有变量
    var isChinese = true;

    // 静态私有方法
    var speak = function() {};

    // 创建类
    var _person = function() {
        // 私有属性: 只能被【私有方法】和【特权方法】访问
        var contact = 'xxxxx@qq.com';
        var number = '88888888';

        // 私有方法: 在构造函数里声明, 能被【私有函数】【特权方法】访问, 只能访问【私有方法】和【私有属性】
        var getInfo = function(name, sex) {
            console.log('My name is ' + name + ', I’m a ' + sex + '!');
            console.log('My email is ' + contact);
        };

        // 公有属性
        this.name = name;
        this.sex = sex;

        // 特权方法: 可以访问
        this.intro = function() {
            getInfo(name, sex);
        };
        this.getContact = function(number) {
            console.log(number);
        };

        // 构造器
        this.getContact(number);
    };

    // 构建原型
    _person.prototype = {
        constructor: _person,
        // 公有属性
        hobby: 'reading',
        // 公有方法
        sport: function() {
            console.log('run');
        }
    };

    // 返回类
    return _person;
})();

类的两种写法

  1. 标准原型写法

function Person() {}
Person.prototype.sayHi = function() {}

var me = new Person();
console.log(me.constructor === Person);    // true;
  1. 对象字面量

function Person() {}
Person.prototype = {
    sayHi: function() {}
}
var me = new Person();
console.log(me.constructor === Person);    // false;
console.log(me.constructor === Object);    // true;

使用对象字面量的缺点:

使用对象字面形式改写原型对象改变了构造函数的属性,因此它现在指向Object而不是Person.

原因:

因为原型对象具有一个constructor属性,这是其他对象实例所没有的.
当一个函数被创建时,它的prototype属性也被创建, 且该原型对象的constructor属性指向该函数.
当使用对象字面形式改写原型对象Person.prototype时, 其constructor属性将被置为泛用对象Object.

解决:

在改写原型对象时手动重置其constructor属性.

    // 对象字面量修正:
    function Person() {}
    Person.prototype = {
        constructor: Person,
        sayHi: function() {
            console.log('Hi~');
        }
    }
    var me = new Person();
    console.log(me.constructor === Person);    // true;
    console.log(me.constructor === Object);    // false;

创建对象的安全模式

var Person = function(name, sex) {
    this.name = name;
    this.sex = sex;
};

var tony = new Person('Tony', 'boy');
console.log(tony.name);     // Tony
console.log(tony.sex);        // boy

var anna = Person('Anna', 'girl');
console.log(window.name);     // Anna
console.log(window.sex);    // girl

console.log(anna);        // undefined
console.log(anna.name);        // Uncaught TypeError: Cannot read property 'name' of undefined

tips:

new可以看作是对当前对象this不停地赋值,
如果没有new, 则会直接执行函数, 因为函数在全局作用域中执行了,
所以在全局作用域中this指向的当前对象就自然是全局变量,
属性都添加到window上面了;
另外一个则因为Person类中没有return语句,
则函数执行完没有返回执行结果. 所以实例对象为undefined;

// 创建对象的安全模式
var Person = function(name, sex) {
    // 判断执行过程中this是否是当前对象(如果是说明是用new创建的)
    if(this instanceof Person) {
        this.name = name;
        this.sex = sex;
    } else {
        // 否则重新创建这个对象
        return new Person(name, sex);
    }
}

引路人
146 声望12 粉丝