JS代码复用-原型继承

818 阅读3分钟
 JS原型继承 javascript作为脚本语言,没有类的概念,为提高代码复用效率需要解决继承问题


  •   JS对象一般生成方式

 var person1 = {
name: 'Jack',
age: 18,
sayName: function () {console.log(this.name)},
}
var person2 = {
name: 'Mike',
age: 16,
sayName: function () {console.log(this.name)},
}
  • 工厂模式解决方案:封装的对象作为函数的返回值 

function createPerson (name, age) {
return {
name: name,
age: age,
sayName: function () {console.log(this.name)},
       }
}
var person1_return = createPerson('Jack', 18)
console.log(person1_return.name)//Jack
var person2_return = createPerson('Mike', 16)
person2_return.sayName()//Mike

 把一个对象用函数封装,并作为函数的返回值,就可以用此函数获取对象的属性值。给定不同参数就是不同对象。但没有解决封装的函数的对象特征识别问题。

  •  构造函数解决方案:new操作符衍生对象类型属性 

constructor
function Person (name, age) {
this.name = name;
this.age = age;
this.sayName = function () {console.log(this.name)};
}
var person1_new = new Person('Jack', 18)
person1_new.sayName()//Jack
var person2_new = new Person('Mike', 16)
console.log(person1_new.name)//Mike

 new操作符的原理 当使用 new 操作符调用 Person() 的时候,实际上这里会先创建一个对象var instance = {}, 然后让内部的 this 指向 instance对象,this = instance 接下来所有针对 this 的操作实际上操作的就是 instance, 在函数的结尾处会将this返回,return this,也就是返回instance。

 该方案可以识别对象的具体类型了。每一个实例对象中有一个constructor属性,该属性指向创建该实例的构造函数,但该方案存在一个浪费内存的问题,每一个实例对象syaName都是一模一样的内容,每一次生成一个实例,都必须生成重复的内容,多占用一些内存,如果实例对象很多,会造成极大的内存浪费。

  •  更好的解决方案:prototype原型继承,属性共享 。

 function Person (name, age) {
this.name = name;
this.age = age;
this.sayName = function () {console.log(this.name)};
}
Person.prototype.sayAge = function () {console.log(this.age)}
var p1 = new Person('Jack', 18)
p1.sayName() // => Jack
p1.sayAge() // => 18
var p2 = new Person('Mike', 16)
p2.sayName() // => Mike
p2.sayAge() // => 16
console.log(p1.constructor === Person) // => true
console.log(p1.__proto__ === Person.prototype) // => true
console.log(p1.__proto__.constructor === Person) // => true

 每一个实例对象都具有一个 constructor 属性指向创建该实例的构造函数,对象的constructor 属性最初用来标识对象类型,现在推荐使用instanceof操作符。

 每一个实例对象都具有一个__proto__ 属性,指向创建该实例的构造函数的原型对象,即构造函数的prototype属性。

 console.log(p1.sayName === p2.sayName)// => flase
console.log(p1.sayAge === p2.sayAge) // => true 

每个构造函数都有一个prototype属性指向该构造函数的原型对象,所有对象实例需要共享的属性和方法定义这个对象上。未定义在prototype属性上的属性new出来的属性指针不同。

  •  番外:原型式继承

 Object.create()基于已有的对象创建新对象。

function object(o){
function F(){}
F.prototype = o;
return new F();
}
var person = {name:"jack"}
var person1= object(person)
console.log(person1.name);//jack

 ES5通过Object.create()方法规范了原型继承,Object.create()===object() 

var person2 = Object.create(person)
console.log(person2.name);//jack

 ES6类class(ES6类的所有方法都定义在ES5构造函数prototype属性上)

class Point { 
constructor(x, y) { //默认方法
this.x = x; 
this.y = y; 
    }
toString() { 
return '(' + this.x + ', ' + this.y + ')'; 
    }
}
var point = new Point(2, 3); 
console.log(point.toString())//(2,3)