原型对象与原型链(结合案例分析)

原型对象原型链

所有的构造函数都有一个属性,原型/原型对象(本质就是一个对象)prototype
Student.prototype

fucntion Student(name,age,sex){
	this.name = name;
	this.age = age;
	this.sex = sex;
}
console.log(Student.prototype)// 就是一个对象
// 通过原型创建的方法,将来构造函数所有的实例对象都是可以访问的,并且他们占用的都是同一个地址空间。因为Student.prototype在内存中只有一份,所以sayHi 方法在内存中也是只占用一份
//添加方法的时候在  Student.prototype 上添加方法,即:
Student.prototype.sayHi = function(){
	console.log('大家好,我是 ' + this.name)
}
var s1 = new Student('lilei',18,'男')
var s2 = new Student('hmm',18,'女')
s1.sayHI()
s2.sayHi()
// 那么在s1和s2中都是可以访问    sayHi()方法的
console.log(s1.sayHi === s2.sayHi) // => true

prototype就是构造函数的原型 也叫原型对象
  • 所有在原型对象上添加的方法,都在构造函数的实例对象中的__proto__ 对象里面
  • __proto__ 对象里面都有一个constructor属性
  • 对象中的__proto__ 属性就指向了构造函数中的原型属性 Student.prototype
  • 如果构造函数中有一个syaHi()方法,构造函数中的原型对象里面同样 有一个sayHi()方法,name访问sayHI()方法的时候,访问的是构造函数中的方法,而不是构造函数的原型对象中的方法
  • 如果构造函数中没有sayHI()方法的时候,就会去找构造函数的原型对象中的方法
  • 如果构造函数中没有这个方法,同时构造函数中的原型对象中也没有这个方法,就会报错s1.say is not a function
  • 综上的总结:因为方法的调用方法,(先去构造函数本身去寻找,然后再去对象的__proto__中去查找在构造函数的原型对象上添加的方法syaHi()方法)。所以 对象的.__proto__等于构造函数的prototype属性
  • __proto__ 属性是一个非标准的属性,所以在生产环境下不能使用
  • 在原型对象中有一个属性 constructor ,这个属性就指向了 构造函数
  • 对象可以访问 原型对象中的所有成员 s1.constructor访问的就是原型对象中的 constructor 属性
  • s1.constructor存储的就是构造函数。
  • 所以 constructor属性的作用就是 记录了创建该对象的构造函数。比如我们想知道这个对象是有那个构造函数创建的,通过 constructor属性就可以知道。
  • 结合上面的例子 s1.constructor === Studenttrue
  • 调用方法的时候是根据就近原则来调用的

设置属性的规则

  • 如果对象本身有某一个属性,就直接改变这个属性的值
  • test属性是在原型对象上,如果对象本身没有 test 属性,在设置属性的值的时候,不会搜索原型链。而是会给对象新增一个属性值 test,而不会去找 prototype中的属性test。同时新增的test属性会把原型对象中的test给覆盖掉(因为访问的规则就是先去寻找对象中的属性看有没有,有了的话,就不会去原型对象中查找了)

使用原型对象的注意点

  • 在以后如果想给原型对象中设置方法的时候,没有必要一个一个对象的进行设置,像下面这样:
Student.prototype.sayHi() = function(){
	console.log('hihihihi)
}
Student.prototype.eat() = function(){
	console.log('eataeatjllll)
}
// 可以方便的像下面这样:
Student.prototype= {
	sayHi : function(){
		console.log('hihihihi)
	}
	eat : function(){
		console.log('eataeatjllll)
	}
}
  • 把对象的prototype 属性修改成一个对象之后,s1.constructor 的指向就变了?
  • 这是因为原来为修改对象的 prototype属性之前, prototype属性指的是构造函数本身,当你重新将prototype值修改为一个对象的时候,,就是重新赋值,里面的构造函数就没有了。但是不为空,还是一个对象(object)这是因为原型链的关系,找不到constructor 竖向,就会继续往上寻找 __proto__对象里面的constructor属性,当前的指的是Object这个构造函数了,这就是为什么指向发生改变而不是消失。

原型对象的应用

  • 可以扩展内置对象中的方法
  • 数组或者String中的 prototype 属性是不可以修改的。例如
Array.prototype = {
	getSunm:function(){
		...........
	}
}
// 这样为prototype属性进行重新赋值就不允许的,因为会破坏原有的内置对象。
  • 把一个函数当做工具来使用的时候,将函数名首字母大写

bind()

  • bind方法是ES5中新增的方法。ie9之后才支持
  • bind中的第一个参数可以改变函数中的this的指向
  • bind 是表示新创建一个函数,并没有修改原有的构造函数。bind并没有让方法执行。还是需要自己来调用
  • 可以使用 函数.bind.(that) 就可以在函数内部使用 this,不使用that

贪吃蛇案例代码优化

  • 原始的我们写了很多个js文件。每一个文件的执行顺序都是不能随便换的。因为下一个文件需要依赖于上一个文件中创建的方法。这样在本地上运行是没有问题的,但是一旦我们将代码文件都部署到服务器上的时候就会出现问题
  • 我们知道,一个网页的执行过程是这样的。首先访问index.html入口文件,一行一行的进行解析,遇到一个script标签的时候,会去服务器上寻找对应的js或者其他文件,然后下载到本地,然后才能执行。这里引入了很多个script标签,这就造成了,每次遇到一个script标签,都要去服务器上查找这个文件,然后下载。我们知道网速是不稳定的,有可能出现某一个文件下载的速度比较慢,这就会造成,下面的文件已经下载好了,但是上一个文件还没有下载完成,然后下面的文件再去调用上一个文件中的方法就会出错,查找不到。我们我们可以将所有的js文件合并到一个一个js文件中,只使用一个script文件。这样就优化了,只需要从服务器中下载一个文件就可以了。减少向服务器请求的次数,加快了页面的加载速度
  • 将来我们可以使用工具去合并js代码。现在我们手动合并一下。把所有js文件中的代码剪切到index.js文件中,然后就可以把其他的js文件删除了。
  • 合并完成后的问题:因为我们是每一个js文件中都是一个自调用函数(function () { .... })()。一个js文件中使用多个自调用函数就会出错:原因是:一个自调用函数执行结束的时候,返回值是undefined。然后中间的空格浏览器会忽略掉,然后这个undefined就和下一个自调用函数组成这样
undefined(function () {
 	....
  })()
  // 此时浏览器就会认为这个是一个新的函数undefined函数的调用。然后就会出错。
  // 解决办法就是每一个自调用函数写完之后 必须写一个 ; 来告诉浏览器上下是没有关系的,这个是一个语句的结束
  // 但是我们在看别人的代码的时候,都是将 ; 写到每一个自调用函数之前的,这是一个代码规范。这是为了防止下面的情况:
  var fn = function(){
	
	}
	(function () {
 	....
  	})()
  	// 这种情况上面的也会和下面的自调用函数组成一个方法,认为是方法的调用,就会出错。所以最好的办法就是在自调用函数之前加 ;
  // 就像这样:
 ; (function () {
 	....
  })()
 ; (function () {
 	....
  })()
  • 最后一步我们把index.js文件中的代码再次进行压缩。因为一个空格和换行,一个变量和注释都要占内存空间的,如果能把这些优化一下,这个js文件的体积就会变得更小,将来去服务器中访问的时候下载的速度就更快了。之后我们会有固定的工具进行压缩,现在我们在网页上搜索,在线压缩代码,将我们的代码复制上去进行压缩,然后把压缩号的代码复制到我们的项目中去。项目依然可以指向。(压缩就是将变量名变短,空格,换行都去掉,注释去掉)
  • 再次进行代码的优化:我们在自调用函数中会使用到 window,undefined这两个变量。因为我们需要将我们写的函数方法暴露给window对象。我们想办法将window这个变量也压缩成w。我们可以给自调用函数传入形参和实参window,undefined
;(function ( window,undefined ) {
 	....
 	window.Tools = Tools
  })(window,undefined)
  //这样压缩的时候形参和函数里面的 window可以被压缩成  w一个字母。但是实参是不会被压缩的
  • 这样做的好处是:
1.传入window 是让变量名可以被压缩
2.传入undefined 是,一个是可以被压缩,另外就是 因为在老版本的浏览器中 ,undefined是可以被重新赋值的。所以这里是为了防止被重新赋值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值