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

来源:互联网 发布:时代网络大厦美食广场 编辑:程序博客网 时间:2024/06/05 00:07

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; //truef1.__proto__.getX === f2.getX; //truef1.getX === Fn.prototype.getX; //true
f1.sum ===f2.__proto__.sum;//falsef1.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.prototypeconsole.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,而非排序后的结果.
原创粉丝点击