原型
function Fn(){
}
Fn.prototype.play = fuciton(){
}//prototype 就是这个函数的原型 给原型上添加方法就相当于ES6中的静态方法
var a = new Fn();
console.log(f)//当实例化构造函数时,实例化会将构造函数的prototype对象下的所有方法和属性添加在实例化对象的原型链中
function Box(){
}
Box.prototype = {
a:1,
run:function(){},
play:function(){}
}//如果直接用等号赋值的话,会出现一些问题,你会发现类中的原型上的constructor没有了,此时还需要在加上constructor,如果原本类中还有别的方法也会被替换掉,所以尽量不要使用这种方式。
Object.defineProperty(Box.prototype,"constructor",{
value:Box
})//当给Box这个类的原型上加入了数据后,在给他加上constructor属性
当我们实例化对象这个Box时,实例化对象的原型链就等同于类的原型
var b=new Box();
console.log(b);//实例化对象中的原型链就和父类中的原型是等同的
console.log(Box.prototype===b.__proto__)//true
使用原型的好处在于当你需要给某一类添加方法时,可以直接给某一类上的这个原型上直接加一个方法,就方便我们调用和使用。例如我想给div这一个类加一个方法,这样的话我所有的div都可以使用
var div0 = document.querySelector(".div0");
var div1 = document.querySelector(".div1");
div0.setBg=function(){
this.style.width="100px",
this.style.height="50px";
this.style.backgroundColor="red";
} //只给div0设置就只有div0有这个方法,其他div无法使用
HTMLDivElement.prototype.setBg=function(){
this.style.width="100px",
this.style.height="50px";
this.style.backgroundColor="red";
}//给所有div类添加方法,此时所有div均可调用
div0.setBg();
div1.setBg();
也可以使用 Object.defineProperties来给某一类的原型中追加方法,
Object.defineProperties(HTMLDivElement.prototype, {
width: {
set: function (value) {
this.style.width =value + "px";
},
get: function () {
return parseFloat(getComputedStyle(this).width);
}
},
height: {
set: function (value) {
this.style.height = value + "px";
},
get: function () {
return parseFloat(getComputedStyle(this).height);
}
},
bgColor: {
set: function (_v) {
this.style.backgroundColor = (typeof _v === "string") ? _v : "#" + _v.toString(16)
.padStart(6, "0");
},
get: function () {
return parseFloat(getComputedStyle(this).backgroundColor);
}
},
利用原型重构Array的some方法
Array.prototype.some1=function(fn){
for(var i=0;i<this.length;i++){
if(fn(this[i],i,this)) return true;
}
return false;
}
在原型上我们可以添加或者更改某一便于我们使用的方法,它可以给某一类添加,更方便我们的代码执行。
继承
ES6的继承
在ES6中继承可以直接使用extends
class A {
constructor() {
}
run() {
console.log("a");
}
play(){
console.log('b')
}
}
class B extends A {
constructor() {
super();//继承时一定要写入super()
}
run(){
super.run();
console.log("c");
}
}
let b = new B();//此时实例化对象b也具有A类的方法
ES5的继承
ES5中的继承是将某一类的实例化对象复制给某一类的原型来达到继承
function Box(){
}
Box.prototype.run=function(){
}
Box.prototype.a=10;
function Ball(){
}
Ball.prototype=new Box();//用这个方法来实现继承,但是此时他的原型中的constructor丢失,所以要重新追加,使用下面的方式
Object.defineProperty(Ball.prototype,"constructor",{
value:Ball
})
这样看上去没又任何问题,但是一旦传入参数是就会又问题,当我传入参数时,没有办法给Box这个构造函数传参,打印的结果就会为undefined.
function Box(b){
this.a=a;
console.log(b)
}
Box.prototype.run=function(){
}
Box.prototype.a=10;
function Ball(b){
}
Ball.prototype=new Box();
Object.defineProperty(Ball.prototype,"constructor",{
value:Ball
})
冒充继承
此时我们需要修改Box中 的this指向,只需要在Ball这个构造函数中加入下面语句。
function Ball(b){
Box.call(this,b);
}
这个时候我们修改了Box中的this指向,当前this为实例化对象Ball的对象,这样我们就可以进行传参,这个语句就相当于ES6中的super一样。我们成这种方式为冒充继承。
寄生式继承
但是这种方式也有问题,就是当你创建一个实例化对象时,他会运行Box这个构造函数种的内容,我们一般情况下需要它继承,但是又不想让他执行这个函数体,此时我们又有了一种方式,我们称它为寄生式继承。
寄生式继承的方式就是你在新建一个和你需要继承类一摸一样的类,不过在它这个构造函数种什么都不写,只复制你需要继承类的原型 ,然后在使用继承 。
function Box(b){
this.b=b;
console.log(b);
}
Box.prototype.run=function(){
}
Box.prototype.a=10;
function F(){
}//创建一个新的类
F.prototype=Box.prototype;//复制原型
function Ball(b){
Box.call(this,b);
}
Ball.prototype=new F();//继承给Ball这个类
Object.defineProperty(Ball.prototype,"constructor",{
value:Ball
})
使用这种写法就达到了我们所需要的目的。
ES5继承的封装
使用寄生继承
Function.prototype.extend = function (superClass) {
function F() {}
F.prototype = superClass.prototype;//复制需要继承原型
var proto = this.prototype;//保留当前类中的原型上的方法,属性
this.prototype = new F();//继承完后然后在追加之前的原型上的数据
var names = Object.getOwnPropertyNames(proto);
for (var i = 0; i < names.length; i++) {
var desc = Object.getOwnPropertyDescriptor(proto, names[i]);
Object.defineProperty(this.prototype, names[i], desc);
}
Object.defineProperty(this.prototype, "constructor", {
value: this,
});//防止当前类的原型上的constructor丢失
//后面的代码是为了保证继承的原型上的数据没有任何问题来判断的
this.prototype.superClass = superClass;
if (superClass.prototype.constructor !== superClass) {
Object.defineProperty(superClass.prototype, "constructor", {
value: superClass,
});
}
};
使用时直接调用就可以使用
function Box(b) {
this.b = b;
console.log(b);
}
Box.prototype.run = function () {
console.log("a");
};
Box.prototype.a = 10;
function Ball(b) {
this.superClass.apply(this,arguments);//修改继承类种的this指向
}
Ball.prototype.play=function(){
}
Ball.extend(Box);//直接调用就可以