JS封装(上)

JavaScript 中类的特性:

  • 构造函数
  • 静态属性,静态方法
  • 共有属性,共有方法
  • 私有属性,私有方法

一个简单的类

//Person():构造函数, Person:类
var Person = function(name, age){
//共有属性
this.name = name;
this.age = age;
//共有方法
this.sayName = function(){
console.log(this.name);
};

当对象被实例化后,构造函数会立即执行它所包含的任何代码
使用方式:

var p1 = new Person('zhuzhuxia',2);
var p2 = Person('zhuzhuxia',2); //注意这里少了 new
console.log(p1) //{name: "zhuzhuxia", age: 2, sayName: function}
console.log(window.name); //undefined
console.log(window.age); //undefined
console.log(p2) //undefined
console.log(window.name); //zhuzhuxia
console.log(window.age); //2

Tip:
这里要说明下,使用 new 关键字,JavaScript会识别为对象,将 this 指向类的实例中,但是如果没有使用 new 关键字,this 将会指向全局变量 window,及 this.name = "zhuzhuxia" 等价于 window.name = "zhuzhuxia",因此 p2 是个无效值!

解决方案:

var Person = function(name, age){
if (this instanceof Person){
//共有属性
this.name = name;
this.age = age;
//共有方法
this.sayName = function(){
console.log(this.name);
};
} else {
return new Person(name, age);
}
}

效果:

var p1 = new Person('zhuzhuxia',2);
var p2 = Person('zhuzhuxia',2); //注意这里少了 new
console.log(p1) //{name: "zhuzhuxia", age: 2, sayName: function}
console.log(window.name); //undefined
console.log(window.age); //undefined
console.log(p1) //{name: "zhuzhuxia", age: 2, sayName: function}
console.log(window.name); //undefined
console.log(window.age); //undefined

一个复杂的类

有了上面的例子之后,我们在此基础之上就可以进行我们的完善了。

//全部在构造函数中创建的成员(注:只是以下形式定义的成员),将会在每个实例中生成同名的成员副本
//因而实例越多占用的内存越多
function Person(name, age) {
//私有属性,不能被外部公开访问
var defname = 'zhuzhuxia';
//私有方法,不能被外部公开访问
var sayName = function () {
console.log(this.name);
}
function sayAge() {
console.log(this.age);
}
//公有属性,可以被外部公开访问,且通过 实例 调用
this.name = name;
this.age = age;
this.address = '中国';
//公有方法,可以被外部公开访问,且通过 实例 调用
this.say = function () {
this.sayHello(defname); //在公有方法中可以访问私有成员和 prototype中的成员
}
}
//公有属性,可以被外部公开访问,且通过 实例 调用
//区别:prototype中添加成员,只有一份,与实例个数无关
Person.prototype.sayHello = function (name) {
if (name == undefined)
console.log('Hello ' + this.name); //访问实例中的公有属性
else
console.log('Hello ' + name);
}
//静态属性,可以被外部公开访问,但只能通过 构造函数 来调用
Person.classname = '人';
//静态方法,可以被外部公开访问,但只能通过 构造函数 来调用
Person.showclass = function () {
console.log(this.classname);
}

实例化后使用:

//实例化
var p = new Person('test');
/*---- 测试prototype ----*/
console.log(p.prototype); //undefined 实例对象没有prototype
console.log(Person.prototype); //{sayHello: ƒ, constructor: ƒ}
console.log(Person.prototype.constructor); //Person(name,age){...} 构造函数整体,可以换做 alert来输出
console.log(Person.prototype.constructor.classname); //china 相当于myObject.name;
/*---- 测试属性 ----*/
console.log(Person.address); //undefined Person中的this指的不是函数本身,而是调用address的对象,而且只能是对象
console.log(Person.classname); //人
console.log(p.address); //中国 此时this指的是实例化后的p,及p是调用address的对象
console.log(p.classname); //undefined 静态属性不适用于一般实例
console.log(p.constructor.classname); //人 想访问类的静态属性,先访问该实例的构造函数,然后在访问该类静态属性
/*---- 测试方法 ----*/
Person.showclass(); //人 直接调用 构造函数(类)的静态方法
p.say(); //Hello zhuzhuxia Person类中的方法将会被实例继承
p.sayHello(); //Hello test Person类的prototype原型下的方法将会被实例继承
p.constructor.showclass();//人 调用该对象构造函数(类函数)的方法(函数)
/*-- 错误的方法调用 --*/
//sayHello是原型方法,不是类的方法
//Person.sayHello(); //Uncaught TypeError: Person.sayHello is not a function
//showclass是Person类的方法,和实例对象没有直接关系
//p.showclass(); //Uncaught TypeError: p.showclass is not a function

封装js类

这里我们用闭包来实现,首先解释下闭包的概念。
闭包概念:一个函数有权访问另一个函数作用域中的变量,即在一个函数内部创建另一个函数

实现如下:

var Person = (function(){
//静态私有属性方法
var home = "China";
function sayHome(name){
console.log(name + "'s home in " + home);
}
//构造函数
function _person(name, age){
var _this = this;
//构造函数安全模式,避免创建时候丢掉new关键字
if(_this instanceof _person){
//共有属性, 方法
_this.name = name;
_this.getHome = function(){
//内部访问私有属性,方法
sayHome(_this.name);
};
_this.test = sayHome; //用于测试
//构造器
_this.setAge = function(age){
_this.age = age + 12;
}(age);
}else{
return new _person(name, age);
}
}
//静态共有属性方法
_person.prototype = {
constructor: _person,
drink: "water",
sayWord: function(){
console.log("ys is a boy");
}
}
return _person;
})();

调用如下:

var p1 = new Person("ys", 12);
p1.getHome(); //ys's home in China
console.log(p1.age); //24
var p2 = Person("ys", 12);
p2.getHome(); //ys's home in China
console.log(p2.age); //24
console.log(p2.test == p1.test); //true, 证明静态私有变量共享性

总结

  • 有些公共属性,方法,可以设置为静态的,这样可以在每次实例化的时候,不需要额外开辟内存资源,达到真正意义上的共享,
  • 有些公共的属性方法,只想在内部程序处理时候达到共享,则设置为,静态私有属性方法,
  • 有些公共的属性方法,想在实例对象中达到共享,则设置为prototype属性方法

相关参考

  • 本文作者: zhuzhuxia
  • 本文链接: https://zhuzhuyule.com/blog/Front/JS封装(上).html
  • 温馨提示: 由于原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处, 方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
如果觉得我的文章对您有用,请随意打赏。您的支持将是我继续创作的动力!