JavaScript对象(三)

对象(三)

接JavaScript对象(二)

1.原型模式

        每个函数都有一个prototype属性,该属性指向该函数的原型对象,在原型对象中的属性和方法被所有该函数实例所共享。

        因此我们可以在原型对象中定义属性和方法。

// 使用原型模式创建一个构造函数
function Person() { }
// 在Person的原型对象上进行属性和方法的定义
Person.prototype.name = 'zs';
Person.prototype.age = 21;
Person.prototype.gender = '男';
Person.prototype.sayName = function () {
    console.log(this.name);
};
var p1 = new Person();
var p2 = new Person();
p1.sayName(); //zs
//p1实例上的name属性
p1.name = 'lisi';
p1.sayName(); //lisi
p2.sayName(); //zs
delete p1.name;
p1.sayName(); //zs

        虽然在原型中的name属性已经赋了值,是不能修改的。

        但是,我们想根据实例的不同,赋予不同的name,也可以通过实例名.name进行赋值。

        即:p1.name = ‘lisi’; 但是这个name属性不是Person原型中的,而是实例中的,在实例中声明了name属性,那么构造函数上的name就会被遮蔽(称为属性遮蔽),在进行调用sayName方法时,后台会先在实例中查找是否有name这个属性,若有则会返回该值,若没有才会向上去构造函数中查找。

        若想继续使用原型中的name属性,但是又已经在实例中定义了name属性,那么,我们可以通过delete操作符,将实例中的name属性删除,就可以继续向原型中搜索。

1.1 判断属性
in操作符

        检测属性是否在实例或者原型上

function Person() { };
Person.prototype.age = 21;
Person.prototype.gender = '男';
Person.prototype.sayName = function () {
    console.log(this.name);
};
var p1 = new Person();
p1.name = 'lisi';
console.log("name" in p1); //true  name在实例上
console.log("age" in p1);  //true  age在原型上
hasOwnProperty属性

检测在实例上是否拥有该属性

function Person() { };
Person.prototype.age = 21;
Person.prototype.gender = '男';
Person.prototype.sayName = function () {
    console.log(this.name);
};
var p1 = new Person();
console.log(p1.hasOwnProperty('name'));  //false
console.log(p1.hasOwnProperty('age'));  //true
判断属性是否是原型属性

        属性在原型上有,但在实例中没有

function Person() { };
Person.prototype.name = 'zs';
Person.prototype.age = 21;
Person.prototype.gender = '男';
Person.prototype.sayName = function () {
    console.log(this.name);
};
var p1 = new Person();
var p2 = new Person();
p2.name='lisi';
// 判断属性是否是原型属性
function hasPrototyprProperty(obj, name) {
    return !(obj.hasOwnProperty(name)) && (name in obj)
}
console.log(hasPrototyprProperty(p1, 'name')); //true

console.log(hasPrototyprProperty(p2, 'name')); //false
1.2 简便式原型模式

        在上述的例子中,每定义一个原型属性或者方法都需要重写一遍’Person.prototype’,造成了代码冗余。

        我们可以通过一个对象字面量直接将所有的属性和方法包括在内

        但是通过这个方式,这个构造函数的原型的constructor指向就会由指向Person变为指向Object

        解决方式:重写原型对象时,直接设置constructor的值

        但是,原来的constructor属性默认是不可枚举的,设置之后constructor属性会变为可枚举的,这是不行的

        因此,我们不在对面字面量中直接定义constructor属性,而是通过Object.defineProperty()方法来定义constructor属性

function Person() { }
// 当一个Person.prototype使用对象字面量进行赋值时
// 它的constructor指向就会发生变化,可通过对应的属性指回它原来的构造函数
Person.prototype = {
    // 1.设置constructor属性,可枚举,不推荐该方式
    //constructor: Person,
    name: 'zs',
    age: 23,
    gender: 'male',
    sayName: function () {
        console.log(this.name);
    }
}
// 2.利用定义属性信息设置
Object.defineProperty(Person.prototype, 'constructor', {
    //不可枚举
    enumerable: false,
    value: Person
})
var p1 = new Person();
console.log(p1.constructor);  //[Function: Person]
1.3 原型模式的问题
  1. 弱化了向构造函数传递初始化参数的能力,导致所有实例默认都取得相同的属性值
  2. 共享特性,当在原型中定义了一个引用类型的数据时,当某一个实例进行更改里面的值时,原型中的该属性会直接发现改变,那么其他实例调用的时修改后的值。
function Person() { }
Person.prototype = {
    constructor: Person,
    name: 'zs',
    age: 23,
    gender: 'male',
    friends: ['zs', 'lisi']
}
var p1 = new Person();
var p2 = new Person();
p1.friends.push('larry')
console.log(p1.friends); //[ 'zs', 'lisi', 'larry' ]
console.log(p2.friends); //[ 'zs', 'lisi', 'larry' ]

        在Person实例中有friends这个数组,当p1实例使用push方法向该数组添加元素时,Person中的friends也会发生改变,因为他们指向的是同一个引用地址,即同一个friends数组。

        就比如p1新交了一个朋友,p1的朋友列表进行了更新,但是p2并不认识他,但是p2的朋友列表里面也有他,这就造成了混乱。

这个问题,我们通过组合模式解决。

2.组合模式

        组合模式就是将构造函数模式和原型模式组合起来使用。

        构造函数用于定义实例属性,原型模式用于定义方法和共享属性。

// 用构造函数保存实例属性
function Person(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.friends = []
}
// 用原型模式保存实例方法
Person.prototype = {
    construtor: Person,
    sayName: function () {
        console.log(this.name);
    }
}
var p1 = new Person('lisi', 21, 'male')
var p2 = new Person('wangwu', 22, 'female')
p1.friends.push('yyy')
p2.friends.push('xxx')
console.log(p1.friends); //[ 'yyy' ]
console.log(p2.friends); //[ 'xxx' ]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值