JavaScript面向对象编程

JS面向对象的程序设计,大部分初学者写JS都是运用的面向过程的思维来写的(即一个function后接着另一个function)

其实JS中的function就是一个对象,如下:

var HelloWscats = function(){
    console.log("wscats is not cat");
}

var _init = function(){
    var obj = new HelloWscats();
}

_init(); // wscats is not cat

此时我们就可以调用_init方法打印 wscats is not cat ,它调用了HelloWscats的对象,当然这个HelloWscats对象没有任何属性和方法,它只有一个构造方法HelloWscats(),相当于调用了一个没有任何属性和方法的类,当使用new进行创建的时候,就调用了它的构造方法(也就是执行了HelloWscats里面的console.log("wscats is not cat");),当然现在很多JS的对象是直接定义了属性,而构造方法里面是没有其他可执行代码的。

其实HelloWscats就是我们所说的创建对象中的其中一种构造函数模式

var _init2 = function(param){
    var obj = new Object();
    var obj = {}
    obj.action = "b";
    Object.defineProperty(obj, "name", {
        configurable: false,
        writable: false,
        value: "Wscats",
    });
    obj.name = "wscats"; //无效
    delete obj.name; //无效
    console.log("wscats is not cat");
    return obj;
}
_init2("wscats is not cat");

我们稍微改一下,执行_init2()的时候,相当于创建对象中的另一种——工厂模式,创建对象交给一个工厂方法(_init2)来实现,可以传递参数。

这里创建对象的方式跟构造函数方式的区别在于:

  • 构造函数能看到具体的定义对象类型HelloWscats,而工厂模式不能,因为这里工厂模式创建对象都是使用Object的原生构造函数来完成的。

本质是这两句代码结果的区别:

var obj = new HelloWscats(); //构造HelloWscats函数,并实例化HelloWscats对象
var obj = new Object(); //new一个Object对象,在工厂函数里面扩展该对象,并return该对象

再写一个简单的例子来说明他们的区别,如下:

var Constructor = function() {
    console.log("wscats is not cat from constructor");
}

var objFromConstructor = new Constructor();

var Factory = function() {
    var obj = new Object();
    console.log("wscats is not cat from factory");
    return obj;
}

var objFromFactory = Factory();

对于对象,肯定是要赋予它属性和方法的

我们可以用prototype在原型上进行赋值,比如我们要给HelloWscats对象增加一个name属性和say方法,那么我们就可以这样添加

var HelloWscats = function(){
    this.action = "Code";
    console.log("wscats is not cat");
}

HelloWscats.prototype = {
    name: "wscats",
    say: function(){
        console.log("Wscats is not cat");
    }
}

HelloWscats.prototype.skill = "Good Cat";

var _init = function(){
    var obj = new HelloWscats();
    obj.say();
    console.log(obj);
}

_init();

这里我们看到,先是执行了构造函数中的代码,然后执行原型链中的代码。

这里需要注意的是,如果我们实例化了HelloWscats对象

var _init = function(){
    var obj = new HelloWscats();
    obj.say();
    obj.action = "b";
    console.log(obj);
}

我们可以改变这个对象的action属性,但我们没有办法改变原型链的对象,这个就类似于继承了HelloWscats对象的原型链的对象,继承的这些子类无法去更改,但是子类可以修改自己本身的属性和方法。

下面我们可以继续在构造函数里面写一个var privateVariables = "I am ur cat"; 来让HelloWscats拥有一个私有成员变量,当然这个变量也只有该对象的方法能访问,具体就是this.getPrivate函数能读到该私有变量的成员

var HelloWscats = function(){
    var privateVariables = "I am ur cat";
    this.getPrivate = function(){
        console.log(privateVariables);
    }
    this.action = "Code";
    console.log("wscats is not cat");
}

HelloWscats.prototype = {
    name: "wscats",
    say: function(){
        console.log("Wscats is not cat");
    }
}

HelloWscats.prototype.skill = "Good Cat";

var _init = function(){
    var obj = new HelloWscats();
    obj.say();
    obj.action = "b";
    obj.getPrivate();
    console.log(obj);
}

_init();

它的巧妙之处其实在于这个构造函数的作用域,只能在类的构造函数里面进行访问该私有变量

上面我们一直用obj.name = "wscats" 或者 obj = {name: "wscats"}这两种方法来定义obj的属性,其实也可以使用defineProperty方法进行定义

Object.defineProperty(obj, "name", {
    configurable: false,
    writable: false,
    value: "Wscats",
});

defineProperty方法接收三个参数:属性所在的对象,属性名和一个描述对象(必须是:configurable、enumberable、writable、value)

可以设置以下的数据类型(默认为true),这四个数据属性也是对象属性的默认四个数据属性:

  • configurable:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性
  • enumberable:表示是否可通过for-in循环返回属性
  • writable:表示是否可修改属性的值
  • value:包含该属性的数据值

如下,设置configurable为false,则修改name属性和删除name属性都变得无效

Objetc.defineProperty(obj, "name", {
    configurable: false,
    value: "Wscats",
})
obj.name = "wscats"; // 无效
delete obj.name; // 无效

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值