JS 之封装

531 阅读2分钟

小知识,大挑战!本文正在参与“  程序员必备小知识  ”创作活动

本文同时参与 「掘力星计划」  ,赢取创作大礼包,挑战创作激励金

1、生成实例对象的原始模式

var Cat = {
    name : '',
    color : ''
}
var cat1 = {}
cat1.name = "大毛"
cat1.color = "黄色"
var cat2 = {}
cat2.name = "二毛"
cat2.color = "黑色"

优点:将两个属性封装在一个对象里,这是最简单的封装

问题:

  1. 多生成几个实例,代码就一直在重复冗余;

  2. 实例与原型之间,没有半点关联

2、原始模式的改进

function Cat(name,color) {
    return {
        name:name,
        color:color
    }
}
var cat1 = Cat("大毛","黄色")
var cat2 = Cat("二毛","黑色")

3、构造函数模式

构造函数实际上也就是个普通函数,只是里面采用this,this变量会绑定到实例对象上

function Cat(name,color) {
    this.name = name;
    this.color = color;
}
var cat1 = new Cat("大毛","黄色")
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色

这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数

通过instanceof运算符,可以验证原型对象与实例对象的关系

alert(cat1.constructor == Cat); //true
alert(cat2.constructor == Cat); //true
alert(cat1 instanceof Cat); //true
alert(cat2 instanceof Cat); //true

构造函数模式的问题:

像是一些不变的属性或方法,如果都在构造函数里定义,就会出现每次生成实例,都为重复的内容,多占用了内存

4. 采用Prototype模式修订构造函数模式的问题

将不变的属性跟函数直接定义在prototype上

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};

然后,生成实例

var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠 

这时所有实例的type属性和eat()方法,都是同一个内在地址,指向prototype对象

alert(cat1.eat == cat2.eat); //true
 Cat.prototype.constructor == Animal
 cat1.constructor == Cat.prototype.constructor
 Cat.prototype = new Animal()
 
 cat1.constructor == Animal

自己实现个 new 操作符

function create(Con,...args){
	var obj = {}
	// 将 obj 实例与 Con.prototype 关联起来,达到可以访问构造函数 Con 对应的原型链上的属性和方法
	Object.setPrototypeOf(obj,Con.prototype) //obj.__proto__ = Con.prototype
	// 执行 Con 构造函数中的代码,将 this 绑定为当前实例对象 obj ,并传入剩余的参数
	var result = Con.apply(obj,args) // var result = Con.call(obj,...args)
	// 如果返回的是引用类型的对象,则返回;否则默认返回当前实例对象obj
	return result instanceof Object ? result : obj
}

验证:

function Person(name,age){
	this.name = name;
	this.age = age;
}
Person.prototype.speak = function() {
	alert(this.name + "speak!")
}
var p = create(Person,"张三",3)
p.speak() //张三speak!