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).
- 1,每个函数数据类型(普通函数,类)都有一个天生自带的属性:
function Fn() {
this.x = 100;
}
Fn.prototype.getX = function () {
console.log(this.x);
};
var f1 = new Fnl;
var f2 = new Fn2;
Object是JS中所有对象数据类型的基类(最顶层的类)
- 1,f1 instanceof Object -> true 因为f1通过proto可以向上级查找,不管多少级,最后总能找到Object.
- 2,在Object.prototype上没有proto这个属性
- 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
}
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,而非排序后的结果.