Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

代码复用之继承 #7

Open
pfan123 opened this issue Jun 2, 2017 · 0 comments
Open

代码复用之继承 #7

pfan123 opened this issue Jun 2, 2017 · 0 comments

Comments

@pfan123
Copy link
Owner

pfan123 commented Jun 2, 2017

代码复用之继承

js继承通常分两类:原型链的继承,实例对象继承(浅拷贝,深拷贝)

原型链的继承

  • 1.借用构造函数:
	function Parent(name){
		this.name= name || "adam",
		this.age="24";
	}
	Parent.prototype.say = function () {
		return this.name
	}	

	function Child(name){
		Parent.apply(this, arguments)
	}

	var child = new Child()

缺点:子类无法继承父类 prototype 共享属性,原型链断裂。

  • 2.借用和设置原型:
	function Parent(){
		this.name = "adam"
	}
	Parent.prototype.say = function () {
		return this.name
	}	

	function Child(){
		Parent.call(this)
	}

	Child.prototype = new Parent()

	Child.prototype.constructor = Child

	var child = new Child()

缺点:实现继承原型,同时继承了两个对象的属性,即添加到this的属性以及原型属性。在绝大多数的时候,并不需要这些自身的属性,因为它们很可能是指向一个特定的实例,而不是复用。

  • 3.共享原型:
	function Parent(){
		this.name = "adam"
	}
	Parent.prototype.say = function () {
		return this.name
	}	

	function Child(){
		Parent.call(this)
	}

	Child.prototype = Parent.prototype;

	var child = new Child()

优点: 效率比较高(不用执行和建立父类Parent的实例了),比较省内存。
缺点: 子类Child.prototype和父类Parent.prototype现在指向了同一个对象,那么任何对Child.prototype的修改,都会反映到Parent.prototype,影响作用域。

如这样操作Child.prototype.constructor = Child; 则 alert(Parent.prototype.constructor); // Child

  • 4.利用空对象作为中介:
function Parent(name){
	this.name=name || "gaolu",
	this.age="24";
}
Parent.prototype.sayName=function(){
	return this.name;
}

function Child(name){
   this.sex = “male”,
   Parent.apply(this, arguments)
}
function inhert(C,P){
	var F=function(){}; //F是空对象,所以几乎不占内存
	F.protototype = P.prototype;
	C.prototype = new F();
	C.prototype.constructor = C;
	C.uber = P;
}

inhert(Child, Parent)
var child = new Child()

此种方式最优,也被大多数框架库所采用,节省内存效率较高。

  • 5.利用 Object.create 实现继承

Object.create()

//通过Object.create()继承
function Parent(){
	this.name = "adam"
}

Parent.prototype.say = function () {
	return this.name
}

function Child (name){
	Parent.call(this)
}

Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
console.log(new Child())
  • 6.利用 ES6 中 extends 实现继承
    使用 extends 实现继承,更简单,不会破坏 instanceof 运算的危险。
class Queue{
	consturctor(contents = []) {
		this._queue = [...contents]
	}
	pop() {
		const value = this._queue[0];
		this._queue.splice(0, i);
		return value;
	}
}

//继承
class PeekableQueue extends Queue{
        constructor(...args) {
             super(...args);
       }
	peek() {
		return this._queue[0];
	}
}

实例对象继承(非构造函数的继承)

  • 浅拷贝

简单的把父对象的属性,全部拷贝给子对象,也能实现继承

	function extend(p){
		var c = {}
		for (var i in p){
			c[i] = p[i];
		}
		c.uber = p;

		return c;
	}

  • 深拷贝

如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。所谓"深拷贝",就是能够实现真正意义上的数组和对象的拷贝。它的实现只要递归调用"浅拷贝"就行了。

	function deepExtend(p, c){
		var c = c || {};
		
		for(var i in p){
			if(typeof p[i] === 'object'){
				c[i] = (p[i].constructor === Array) ? [] : {};
				//c[i] = (Object.prototype.toString.call(p[i]) === '[object Array]') ? [] : {};
				deepExtend(p[i], c[i])
			}else{
				c[i] = p[i]
			}
		}

		c.uber = p

		return c;
	}

引伸数组的常用方法拷贝

  • 1.slice
arrayObject.slice(start,end)

返回一个新的数组,不影响父数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

parent = [1,2,3,4]
//slice() 与 slice(0),开始参数默认为0
child = parent.slice()
child.push(22)
console.log(parent, child) // [1, 2, 3, 4], [1, 2, 3, 4, 22]

  • 2.concat
arrayObject.concat(arrayX,arrayX,......,arrayX)

该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本

parent = [1,2,3,4]
child = parent.concat([])
child.push(22)
console.log(parent, child) // [1, 2, 3, 4], [1, 2, 3, 4, 22]
  • 3.for in 实现拷贝

ps: 三者效率,slice 与 concat 相当,而for in 最差

  • 4.扩展运算符(...)

ES6 中,扩展运算符也能很方便的拷贝数组

const items = [1,2,3,4] 
const itemCopy = [...items]

注意 splice 不能实现数组拷贝

arrayObject.splice(index,howmany,item1,.....,itemX)

splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目,该方法会改变原始数组

//使用splice()
var x = [14, 3, 77]
var y = x.splice(1, 2)
console.log(x)           // [14]
console.log(y)           // [3, 77]

//使用slice()
var x = [14, 3, 77];
var y = x.slice(1, 3);
console.log(x);          // [14, 3, 77]
console.log(y);          // [3,77]

由此,也发现 spliceslice 区别,splice会改变原生数组,而slice返回一个新的数组。

参考:

从__proto__和prototype来深入理解JS对象和原型链

Javascript 面向对象编程(一):封装

Javascript面向对象编程(二):构造函数的继承

Javascript面向对象编程(三):非构造函数的继承

Object.create()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant