专栏名称: klivitamJ
android/前端工程师
目录
相关文章推荐
新闻坊  ·  上海最新披露!多名银行高管被罚! ·  2 天前  
新闻坊  ·  上海最新披露!多名银行高管被罚! ·  2 天前  
中国安全生产网  ·  DeepSeek眼中,安全员是什么样子? ·  3 天前  
51好读  ›  专栏  ›  klivitamJ

关于Android工程师转vue的三两事儿(10)--原型与原型链

klivitamJ  · 掘金  ·  · 2019-05-16 15:53

正文

阅读 1

关于Android工程师转vue的三两事儿(10)--原型与原型链

说起原型和原型链接,着实让我这个前端菜鸟胡搞了好一阵子。虽然有点绕口的缘故,但是更多的还是自己比较浮躁带来的后果,这一块据说是前端的基础,看了很多遍才差不多有点头目。分享一下我领悟到的武林秘籍,希望能给您带来一点启迪,如果存在任何问题,请及时指正我,谢谢。😊😊😊😊

一、 浅谈数据属性和访问器属性

1. 创建对象:

通常创建对象一般都会有两种方法:

//利用object来创建对象
var person = new Person();
person.name = "klivitam";
person.age  = 23;

person.sayName = function(){
  alert(this.name)
}
复制代码
// 对象字面量法,推荐使用这种方法
var person = {
  name:"klivitam",
  age:23,
  
  sayName: function(){
    alert(this.name);
  }
}
复制代码

2. 属性类型

在javascript中,对象的属性一共分为两种:数据属性和访问器属性。

  • 数据属性 configurable :表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为true enumerable :表示能否通过for-in循环返回属性 writable :表示能否修改属性的值 value :包含该属性的数据值。默认为undefined 数据属性包含一个数据值的位置,在这个位置可以读取和写入值。以上就是描述数据值行为的四个特性。 okey,可能全凭着口述概念无法了解这个意思,现在就实操代码吧。
// "use strict"
var worker = {}
Object.defineProperty(worker, "job", {
	writable: false,
	value: "码农"
})
console.log(worker.job)
worker.job = "教师"
console.log(worker.job)
复制代码

writable=false
当把writable的属性改成true的时候,
writable = true
从上面的代码可以看出来writable是用来控制是否能修改属性的值。另外当writable为false的时候,并且使用严格模式下,会发生:
严格模式下,writable为false的时候修改值会报错

// "use strict"
var worker = {}
Object.defineProperty(worker, "job", {
	// writable: false,
	configurable:false,
	value: "码农"
})
console.log(worker.job)
delete(worker.job)
console.log(worker.job)
复制代码

当configurable为false的时候,使用delete方法会失效,并且在严格模式下,delete会报错。同理改成true的时候,则为undefined,说明删除成功了。
configurable为false
configurable为true
注意:当value的值没初始化的时候,默认放置undefined

至于最后一个我觉得就没必要代码进行演示了,同理可得。

特征默认值

  • 访问器属性 configurable :表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为false enumerable :表示能否通过for-in循环返回属性,默认为false Get :在读取属性时调用的函数,默认值为undefined Set :在写入属性时调用的函数,默认值为undefined 访问器属性不包含数据值,包含的是一对get和set方法,在读写访问器属性时,就是通过这两个方法来进行操作处理的。并且访问器属性不能直接定义,要通过Object.defineProperty()这个方法来定义。 直接上代码吧:
var worker = {
	_job:"码农",
	age: 23
}
Object.defineProperty(worker,"job",{
	get:function(){
		return this._job;
	},
	set:function(newJob){
		if(newJob!==this._job){
			this._job = newJob;
			this.age ++
		}
	}
})
console.log(Object.getOwnPropertyDescriptor(worker,"job"));
console.log(worker.job)
worker.job = "教师"
console.log(worker.job)
console.log("更换职业就变老一年,5555~:"+worker.age)
复制代码

现实的实例

##二、 js设计模式 ####1、 工厂模式 工厂模式是一个很基础的一个模式吧,反正我在学java (android)的时候经常会遇到这种模式,主要是抽象了创建对象的具体过程。具体的代码如下:

//屌丝程序员,只能偶尔意淫一哈 = l =,别喷我 
function addBeatiGrilWx(name,age,job){
	var gril = new Object();
	gril.name = name;
	gril.age = age;
	gril.job = job;
	gril.sayHi = function(){
		console.log("hi! " + this.name)
	};
	return gril
}
var lyf = addBeatiGrilWx("liuyifei",18,"actor");
lyf.sayHi();
console.log(lyf);
复制代码

效果如下

工厂模式效果图
工厂模式虽然解决了创建多个相似对象的问题,但是却没有解决对象识别的问题(即不清楚一个对象的类型),于是出现了构造函数模式。 ####2、 构造函数模式 构造函数可以用来创造特定类型的对象。具体的代码如下

function BeautiGril(name,age,photo){
	this.name = name;
	this.age = age;
	this.photo = photo;
	this.sayHi = function(){
		console.log("hi! "+this.name)
	}
}
var lyf = new BeautiGril("liuyifei",18,"baidu");
lyf.sayHi();
console.log(lyf)
console.log(lyf.constructor == BeautiGril)
console.log(lyf instanceof BeautiGril)
console.log(lyf instanceof Object)
复制代码

具体的效果如下:

效果图
创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型,这也是前面提到他相较于工厂模式的优势。 构造函数模式看似很好,但是也存在一个问题,就拿上面的代码来说如果我创建多个实例,不止lyf(毕竟还是想多要几个小姐姐的 咳咳)一个。而此时sayHi这个公共的方法就会被多次重复创建。这样其实不太可取的,如果把sayHi方法放置出去,

function BeautiGril(name,age,photo){
	this.name = name;
	this.age = age;
	this.photo = photo;

}
function sayHi(){
	console.log("hi! "+this.name)
}
复制代码

那么相当新建了一个全局方法,这样岂不是更加的没有必要了么?此时就要引入到原型模式了。

3. 原型模式

我们创建的函数都有prototype(原型)属性,这个属性是指针,指向一个对象,而这个对象的用途是 包含由特定类型的所有实例所共享的属性和方法 ,使用原型对象就可以让所有实例对象均包含这些属性及方法。

function Worker(){}
Worker.prototype.name = "programmer";
Worker.prototype.work = "programming...";
Worker.prototype.heartSound = function(){
	console.log(this.name+" want rest,but he still "+this.work)
}

var xiaoZhang = new Worker();
xiaoZhang.heartSound();

var xiaoWang = new Worker();
xiaoWang.heartSound();

console.log(xiaoZhang.heartSound ==xiaoWang.heartSound)
复制代码

这里我还是说一下,我将heartSound()方法和所有的属性直接添加到了Woker的原型属性中,然后通过new创建对象,在原型模式中这些属性和方法对于所有的实例是共享的。 但是这里存在有点问题--那就是并不是所有的worker都是程序员。这就引发了最后一种模式的混用。

3. 原型模式+构造器模式

这个模式在我的理解上来说,主要是为了避免单独用原型模式所带来弊病,就拿上一份代码来说,并不是所有的worker都是程序员,如果想一个医生想去复用这个类的时候,就必须改变其原型上的值,如果改变其原型的值,那么整个都会乱套了。于是我想到构造器模式

function Worker(name,work){
	this.name = name;
	this.work = work;
}
Worker.prototype.heartSound = function(){
    console.log(this.name+" want rest,but he still "+this.work)
}

var xiaozhang = new Worker("programmer","programmer....");
xiaozhang.heartSound(); // programmer want rest,but he still programmer....

//医生也需要休息
var xiaomei = new Worker("doc","sos");
xiaomei.heartSound(); // doc want rest,but he still sos
复制代码

##三、 原型链 前面也差不多谈到了 原型 这个概念,什么叫原型呢?其实我有一个不太好,但是又很恰当的例子来描述这些个概念(看嗯哼家小狗、小猫想到的):

  • 小狗是小狗妈妈生的、小猫是小猫妈妈生的。小狗和小猫被称为对象的实例,狗妈妈、猫妈妈被称为对象的原型
  • 狗妈妈和狗爸爸能通过交配生出一大堆小狗出来,其中交配就被称为构造函数
  • 狗妈妈有很多狗宝宝,但是狗宝宝却只有一个狗妈妈,这可以被称之为原型的唯一性
  • 我们可以通过狗宝宝找到狗妈妈,狗妈妈也可以找到狗外婆,以此类推 这就是相当于原型链
  • 大家都知道狗有很多品种,很多品种里面也有发育好的,发育差的、胖的瘦的...例如胖的泰迪也是泰迪=>泰迪也是狗=>狗=>哺乳动物=>动物=>生物。总之一切的一切都有一个起点,这条链的终点将会被指向同一处,这就好比原型链最终指向null
  • 小泰迪生下来之后,它的样貌会跟泰迪妈妈大同小异,这就类比于原型的继承。
  • 小泰迪的主人领养小泰迪之后将其打扮成另外的模样,这就类比于对象属性可以覆盖原型属性。但是小泰迪的模样并不会改变小泰迪弟弟的模样,这就类比于对象属性的改变不会影响原型的改变。

其实有了上面的一个基本的了解之后,我们再来一步一步写代码就会比较容易了。

{
	function Dog(name){
		this.name = name
	}
	Dog.prototype.action = function(){
		console.log(this.name+" wang..");
	}

	let xiaogou1 = new Dog("xiaogou1");
	xiaogou1.action(); // xiaogou1 wang..

	let xiaogou2 = new Dog("xiaogou2")
	xiaogou2.action(); // xiaogou2 wang..

	let xiaogou3 = new Dog("xiaogou3");
	xiaogou3.action(); // xiaogou3 wang..

}
复制代码

如上面所示 xiaogou1、xiaogou2、xiaogou3被称为对象实例而Dog被称为这群小狗的原型。可以通过构造方法来创建出1,2,3三只小狗。

{
	function Cat(name){
		this.name = name;
	}
	Cat.prototype.action=function(){
		console.log(this.name+" miao!!!")
	}

	function Dog(name){
		this.name = name
	}
	Dog.prototype.action = function






请到「今天看啥」查看全文