[js]04js设计模式02 原型链模式

js原型链模式

  • 构造函数模式中拥有了类和实例的概念,且实例和实例质检是相互独立开的–实例的识别
function CreateJsPerson(name,age) {
    this.name=name;
    this.age=age;
    this.writeJs = function () {
        console.log("my name is "+ this.name +", i can write js la la");
    };
};

var p1 = new CreateJsPerson("liuyifei",18);
var p2 = new CreateJsPerson("maotai",22);
console.log(p1.writeJs===p2.writeJs); //false

共享数据
- 给予构造函数模式的原型解决了 方法或者属性的共有问题, 把实例质检相同的属性和方法提取成共有的属性和方法, 想让谁公有就把他放在
CreateJsPerson.prototype
上即可.



function CreateJsPerson(name,age) {
    this.name=name;
    this.age=age;
    CreateJsPerson.prototype.writeJs = function () {
        console.log("my name is "+ this.name +", i can write js la la");
    };
};

var p1 = new CreateJsPerson("liuyifei",18);
var p2 = new CreateJsPerson("maotai",22);
console.log(p1.writeJs===p2.writeJs); //true
  • 原型特点
    • 1,每个函数数据类型(普通函数,类)都有一个天生自带的属性: prototype(原型),并且这个属性是一个对象数据类型的值
    • 2,并且在prototype上的浏览器天生给添加了一个属性constructor(构造函数),属性值是当前函数(类)本身
    • 3.每个对象数据类型(普通的对象,实例,prototy…)也天生自带一个属性: __proto__属性值是当前实例所属类的原型(protorytype).
function Fn() {
    this.x = 100;
}
Fn.prototype.getX = function () {
    console.log(this.x);
};
var f1 = new Fnl;
var f2 = new Fn2;

image

Object是JS中所有对象数据类型的基类(最顶层的类)
- 1,f1 instanceof Object -> true 因为f1通过proto可以向上级查找,不管多少级,最后总能找到Object.
- 2,在Object.prototype上没有proto这个属性

image

image

  • 3,原型链模式
    • f1.hashOwnProperty(“x”); //hasOwnProperty是f1的一个属性
    • 但是我们发现在f1的私有属性上没有这个方法,那么如何处理呢?
    • 通过对象名.属性名 的方式来获取属性值的时候,首先,对象的私有属性上进行查找,如果私有中存在属性,则返回私有属性值
    • 如果私有中没有则通过proto来向上级查找,找到类的原型,(类的原型上定义了属性和方法都是当前实例的共有属性和方法) 原型上存在的话,获取的是公有的属性值.
    • 如果原型上也没有,则继续通过原型上的proto继续向上查找,一直找到objecet.prototype为止.
    • 这种机制就是原型链模式
function Fn() {
    this.x = 100;
    this.sum=function () {

    };
};
Fn.prototype.getX = function () {
    console.log(this.x);
};
Fn.prototype.sum=function () {};

var f1 = new Fnl;
var f2 = new Fn2;
f1.getX===f2.getX; //true
f1.__proto__.getX === f2.getX; //true
f1.getX === Fn.prototype.getX; //true
f1.sum ===f2.__proto__.sum;//false
f1.sum === Fn.prototype.sum;//false  跳过自己私有的去查询

在IE浏览器中我们原型链模式也是同样的原理,到那时IE浏览器怕你通过proto把公有的修改,禁止我们用proto

//f1.hasOwnProperty --> f1.__proto__.__proto__.hasOwnProperty
f1.sum = function () {
    //修改自己的sum
};
f1.__proto__.sum=function () {
    //修改类原型上的sum
};
Fn.prototype.sum=function () {
     //修改类原型上的sum
}

image

js原型链模式的扩展

原型链模式的扩展

  • this
  • 原型扩展
function Fn() {
    this.x = 100;
    this.y = 200;
    this.getY=function () {
        console.log(this.y);
    }
}

Fn.prototype={
    constructor: Fn, //如果不写,则contractor指向了object
    y:300,
    getX: function () {
        console.log(this.x);
    },
    getY: function () {
        console.log(this.y);
    }
};
var f = new Fn;
f.getX(); // 100
  • 在原型模式总,this常用的有2种情况:

    • 在类中this.xxx=xxx; this–>当前类的实例
    • 某个方法中this–>看执行时候”.”前面是谁就是谁
  • 看执行顺序时候

    • 1,需要首先确定this的指向,(this是谁)
    • 2,把this替换成对应的代码
    • 3,按照原型链的查找机制,一步步查找结果
f.getX(); // console.log(f.x)-->100
f.__proto__.getX(); //console.log(f.__proto__.x) -->undefined
Fn.prototype.getX(); // undefined
Fn.prototype.getY(); //  300

数组去重–扩展数组原型方法

Array.prototype.myUnique = function () {
    // this -> ary
    var obj={};
    for(var i=0;i<this.length;i++){
        var cur = this[i];
        if(obj[cur]==cur){
            this[i] = this[this.length-1];
            this.length--;
            i--;
            continue;
        }
        obj[cur]=cur;
    }
    obj = null;
};

var ary=[12,11,21,12,45,12,44,12,55,66,44,55,66];
ary.myUnique(); // this-> ary
// Array.prototype.myUnique(); //this->Array.prototype
console.log(ary);

链式写法

  • 链式写法原理: 执行完成数组的一个方法可以紧接着执行下一个方法
  • ary为什么可以使用sort方法? -> 因为sort是array.prototype上的公有方法,而数组ary是Array的一个实例,所以ary可以使用sort方法–>数组才能使用我们array原型上定义的属性和方法
  • sort执行完成后,返回的是一个排序后的”数组”,可以继续执行reverse()
  • reverse执行完成的返回值是一个数组,可以继续执行pop
  • pop执行完成的返回值是那个元素,不是一个数组了.
var ary=[12,11,21,12,45,12,44,12,55,66,44,55,66];

arr.sort(function (a,b){
    return a - b;
}).reverse().pop();
console.log(ary);
  • 所以再次push报错了
arr.sort(function (a,b){
    return a - b;
}).reverse().pop().push("maotai");
Array.prototype.myUnique = function () {
    // this -> ary
    var obj={};
    for(var i=0;i<this.length;i++){
        var cur = this[i];
        if(obj[cur]==cur){
            this[i] = this[this.length-1];
            this.length--;
            i--;
            continue;
        }
        obj[cur]=cur;
    }
    obj = null;
    return this;//目的是为了实现链式写法
};

思考

  • 在数组原型上有一个方法叫slice,我们要求自己实现一个mySlice,要求和原来的slice功能一模一样
Array.prototype.mySlice=function () {
    < js code >
};

考虑情况:
- slice(n,m);
- slice(n);
- n和m是负数
- n

(5).plus(10).reduce(2)  5+10-2
Number.prototype.plus = function(num){}
Number.prototype.reduce = function(num){}

批量设置原型上的公有属性

function Fn() {
    this.x = 100;
}
Fn.prototype.getX=function () {
    console.log(this.x);
};
Fn.prototype.getY=function () {
    console.log(this.Y);
};

如果这样添加,那还是比较麻烦的.

解决办法:
- 1, 设置别名

var pro = Fn.prototype; //把原来的原型的地址赋值给我们的pro,现在操作的是同一个内存空间.
function Fn() {
    this.x = 100;
}
var pro=Fn.prototype;
pro.getX=function () {
    console.log(this.x);
};
pro.getY=function () {
    console.log(this.Y);
};
  • 2,重构原型对象的方式

默认地: 函数原型链如下

function Fn() {
    this.x = 100;
}

  • 重构方式扩展

    • 重构原型对象的方式–>自己新开辟一个堆内存,存储我们公有的属性和方法,把浏览器原来给Fn.prototype开辟的那个替换掉.
function Fn() {
    this.x = 100;
}
Fn.prototype={ //对象形式重新开辟内存
    a: function () {

    },
    b: function () {

    }
}

存在的问题:
- constractor没了, 被指向到了object
- 只有浏览器天生给Fn.prototype开辟的堆内存里才有constractor,而我们自己开辟的这个堆内存没有这个属性,这样constractor指向的不再是Fn了,而是object了.

console.log(f.constructor); // 没做任何处理钱是,object

  • 为了和原来保持一致,我们需要手动的增加constractor的指向.

  • 用这种方式给内置类添加公有属性
Array.prototype.unnique = function () {
    constractor: Array,
    unique: function () {
    }    
};
console.dir(Array.prototype);

// 发现无效,我们这种方式会吧之前已经存在于原型上的属性和方法给替换掉,所以这种方式修改内置类的话,浏览器是给屏蔽掉的.

存在重写问题

  • 但是我们可一个个的修改内置的方法,当我们通过下述方式在数组的原型上增加方法,如果方法名和原来的内置的重复了,会吧人家内置的修改掉.我们以后在内置原型上增加方法,命名都要加特殊的前缀.
Array.prototype.sort=function () {
    console.log(this); //this-> ary, 我们当前操作的数组
    console.log("ok");
};

var ary = [1,2,2,3,1,1,2,3,3,3,4];
ary.sort();
console.log(ary);


// 输出 ok,而非排序后的结果.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值