js是一门基于对象的语言,但它没有完整的class概念,至少在ES5中是没有的
封装--原始模式:
Cat = {name : '',color : ''};let cat1 = {};cat1.name = '大花';cat1.color = 'white';let cat2 = {};cat2.name = '二哈';cat2.color = 'yellow';
此时js中没有类的概念,可以看出:两个实例的猫 cat1 和 cat2 没有任何联系
因此前人对原始模式进行改进
封装--构造函数模式
function Cat(name,color) {
this.name=name;
this.color=color;
}
let cat1 = new Cat('大花', 'white'); // Cat {name: '大花', color:'white'}
let cat2 = new Cat('二哈', 'yellow');
现在看起来,是不是好多了?两只猫用一个构造函数构造出来
但是还存在一个问题,如果两个猫存在共同的属性type,以及方法eat,那会造成资源的浪费
封装--工厂模式
function Cat(name,color) {this.name=name;this.color=color;}Cat.prototype.type = '猫科动物';Cat.prototype.eat = function () {console.log('吃鱼');};let cat1 = new Cat('大花', 'white');let cat2 = new Cat('二哈', 'yellow');console.log(cat1);console.log(cat1.type);
这样两个实例都有type属性和eat方法,指向同一个地址,做到了节省资源的目的
console.log(cat1.eat == cat2.eat); // true
为了配合protype使用,在Object的原型上定义了isPrototypeOf
console.log(Cat.prototype.isPrototypeOf(cat1)); // trueconsole.log(cat1.hasOwnProperty('name')); // true 判断是否是自身属性,继承属性不算console.log('name' in cat1); // 判断属性在不在实例上,继承也算
继承--构造函数绑定
使用call或apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:
function Animal() {this.species = '动物';}function Cat(name,color) {Animal.apply(this, arguments);this.name=name;this.color=color;}let cat1 = new Cat('大花', 'white');console.log(cat1.species);
继承--prototype模式
”猫“的 prototype 指向 Animal 的实例,这样猫的实例就能继承 Animal 了
function Animal() {this.species = '动物';}// Animal.prototype.species = '动物‘;function Cat(name,color) {this.name=name;this.color=color;}Cat.prototype = new Animal();Cat.prototype.constructor = Cat; // 手动纠正cat1.constructor指向Animallet cat1 = new Cat('大花', 'white');console.log(cat1.species);
浅拷贝
把父对象的属性,全部拷贝给子对象,也能实现继承
var Chinese = { nation:'中国' };var Doctor ={ career:'医生' }function extendCopy(p) {var c = {};for (var i in p) {c[i] = p[i];}c.uber = p;return c;}var Doctor = extendCopy(Chinese);Doctor.career = '医生';console.log(Doctor.nation); // 中国
浅拷贝存在一个问题,当Chinese中存在一个数组属性nation: ['汉族',’回族‘,’苗族‘],改变子对象属性时,父对象属性有被篡改的风险
深拷贝
此处不作考究,需要递归进行浅拷贝
(结束)