JavaScript面向对象编程

创建对象

//1.字面量
var obj1 = {}
//2.构造函数
function A(){}
var obj2 = new A();//{}
//3.Object.create()
var obj3 = Object.create(obj1)

构造函数与实例

//构造函数。与普通函数的区别只是调用方式。所以一般约定首字母大写。
function A(){
    this.a = 1;
    this.fnA = function(){}
}
//实例。不要忘记new。
var objA= new A();//{a: 1, fnA: ƒ}

prototype与proto

  • prototype。构造函数有一个属性叫prototype。即是原型对象。原型对象中的属性和方法会被所有实例共享。
  • 对象实例中有个属性proto指向构造函数的原型对象。
objA.__proto__ == A.prototype;//true
A.prototype.pFnA = function(){console.log(1)};
A.prototype.pA1 = 1;
objA.pFnA();//1;
objA.pA1 == 1; //true;
var objB == new A();
objB.pFnA == objA.pFnA;//true;
objB.pA1 == objA.pA1;//true;

对象中的值的查找与原型链

//在构造函数原型上加一个实例属性的同名属性。
A.prototype.a = 2;
objA.a;//1;
objA;//{a: 1, fnA: ƒ}
delete objA.a;
objA;//{fnA: ƒ},实例属性中的a已删除。
objA.a;//2 来自A.prototype;

a的查找顺序顺序:实例属性(objA)=>原型(A.prototype)。一旦找到就不会继续往上找。

//对象通用方法。
objA.hasOwnProperty;//ƒ hasOwnProperty() { [native code] }

hasOwnProperty是多数对象的公有方法。它是怎么找到的呢。
objA实例属性中没有。A.prototype中没有。
查看A.prototype,发现它中间也有一个值prototype。是的,prototype其实也是一个普通的对象,也是某个构造函数的实例,这个值指向它的构造函数Object()的原型,Object.prototype。在Object.prototype中找到hasOwnProperty方法。即是objA.__proto__.__proto__中,这样就形成了一条原型链。

终点:

objA.haha;//undefined;

haha是实例属性中没找到,原型链中也没找到,所以返回undefined。
从上面的分析我们找到了Object.prototype中。然后继续找。发现Object.prototype.proto == null;这就是原型链的终点了。

继承

如果把构造函数看成类。根据原型链的查找原理,我们要让子构造函数的实例能调用到父类的原型中的方法和属性,要原型链查找的时候能查找到父类的prototype。子类的prototype为父类的实例或直接等于父亲的prototype。
* 子类的prototype为父的实例。继承了父类的实例属性和原型属性

C.prototype = new P();
  • 借用构造函数。继承了加在this上的属性。
function C(){
    P1.apply(this);
    P2.apply(this);
}
  • 共享原型。继承了原型。不推荐。
C.prototype = P.prototype
  • 借用和设置原型。
function C(a,b,c,d){
    P.apply(this,arguments);
}
C.prototype = new P();
  • 临时代理函数。只继承原型。
function inheirt(C,P){
    var F = function(){}
    F.prototype = P.prototype;
    C.prototype = new F()
}
  • Object.create。
C.prototype = Object.create(P.prototype)
  • ES6 class中定义普通变量。
class C extends P {
    constructor(){
        super()
    }
    say(){
        console.log('hello');
    }
}

注:重写过后的prototype对象需要prototype.constructor = C;上面的代码都省略了。

多态

属于一个分层结构的同一个分支的对象,在发送相同的消息时(也即在被告知执行同一件事时),可通过不同方式表现出该行为。

function Animal(){}
Animal.prototype.makeSound = function(){
    console.log('animal makeSound');
}

function Dog(){}
Dog.prototype = new Animal();
Dog.prototype.makeSound = function(){
    console.log('wangwang');
}

function Duck(){}
Duck.prototype = new Animal();
Duck.prototype.makeSound = function(){
    console.log('gaga');
}

function Bird(){}
Bird.prototype = new Animal();


function makeSound(obj){
    obj.makeSound && obj.makeSound();
}

makeSound(new Dog);//wangwang
makeSound(new Duck);//gaga
makeSound(new Bird);//animal makeSound。没有重写该方法,调用父类方法。

子类的原型上的定义了与父类同名的方法,根据原型链查找的原理,会直接调用子类原型中定义的方法。如果没有自定义该方法,则调用父类方法。
在某些设计模式下,如果不允许直接调用父类的该方法。可以在父类的改方法中抛出错误,而实现类似其他语言的抽象方法的功能。

封装

把一个对象的状态和行为聚合在一起。数据和实现的隐藏。

我们发现上面无论是字面量定义的对象还是new出来的对象。它的属性都可以直接obj.a这样来读写。相当于是暴露在外的。很容易被其他程序代码修改。

JavaScript中的数据隐藏主要通过闭包来实现。我们把一些变量定义在闭包中,通过特定的函数来对其进行读写。

示例一:

function A(){
    var name = 'nameA';
    this.getName = function(){
        return name;
    }
    this.setName = function(newName){
        name = newName;
    }
}
var a = new A();
a.name;//undefined;
a.getName();//nameA
a.setName('name2');
a.getName();//name2;

示例二.所有实例中共享的私有变量:

function A(){}
A.prototype = (function(){
    var name = 'name1';
    return {
        getName:function(){
            return name;
        }
    }
})();
var a1 = new A;
var a2 = new A;
a1.getName();//name1;
a2.getName();//name1

示例三.一个简单的模块:

var module = (function() {
    //私有变量
    var privateA = '1';
    var privateB = '2';
    //私有方法。
    function A(a) {return privateA+1}
    function B() {}
    function C() {}

    //公有API。可选择暴露一些接口出去。
    return {
        A: A,
        B: B
    }
})();

另外,对于暴露出去的数据,如果是引用类型。可能出现私有性失效的问题。可通过克隆以及最低授权原则来处理。

function A(){
    var arr = [1,2,3];
    this.getArr = function(){
        return arr;
    }
}
var a = new A();
var arr = a.getArr();//[1,2,3];
arr.push(4);
a.getArr();//[1,2,3,4],私有变量被修改了。

github地址: https://github.com/liusaint/ls-blog/issues/16

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值