call、bind、apply
三者都是绑定函数的this指向,其中call和apply会立即执行,bind会返回一个函数,apply次参为数组。
DOM.addEventListener('click', function(){}.call(this), false);
# 什么情况下有this指向问题
- 函数里面嵌套函数
- new 一个构造函数
- 绑定事件的事件处理函数(click, onmouseover, onmouseout, drag)
# instanceof
instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
原型链 prototype chain
之所以大部分属性都放到原型链上面,因为大部分属性都是读取型,每次new命令都会产生该次属性,如果挂在圆形上就不会每次实例化都产生该属性,而且方法大部分都存放在原型,只有初始化属性才放在构造函数里面。避免属性一个一个地赋值,推荐使用对象那样赋值。
# __proto__
__proto__存放在this的对象里面,作为key值,它的value是构造函数的prototype,原型链的顶端是Object.prototype
__proto__:constructor.prototype
constructor.prototype={
constructor: Fn,
__proto__: Other Prototype
}
# 修改原型属性
1. 修改基本类型的原型属性,只能修改当前实例化的对象,不能修改原型链上的属性。(因为要访问父级某个属性,肯定时当前实例没有该属性,所以本来想在当前实例修改父级的原型属性,但却给当前实例化对象添加了属性)
2. 修改引用类型的原型属性,当前实例化对象可以获取到父级甚至爷爷级别的原型属性地址,从而改变引用或者改变里面的值都是有可能的。
带你进一步了解原型prototype
原型是构造函数上的一个属性,原型是所有实例对象上的祖先,而且要new的时候才产生作用,也就是在继承的时候产生作用。有点类似作用域的变量访问。
# 实现继承的方案
- 实现借用别的构造函数的内置方法,可以使用apply或者call,使用位置是当前实例化对象的构造函数里面。通过,call或者apply改变this的指向。存在不能借用原型链上属性的缺点。
- 通过原型对象之间赋值可以只复制原型对象上面的属性不复制构造函数里面的方法和属性
Fn.prototype = Fn2.prototype
- 为了弥补原型对象是引用赋值造成互相干扰的问题,可以通过以下两种方法弥补
- 圣杯模式:通过一个中间函数作为中转站,然后将实例化的对象作为原型属性的value
- 使用Object.create(Fn.prototype);创建一个独立的指向Fn原型属性的对象,然后将其赋值给原型对象。
- 还有一种方法就是实例化出来的对象作为另一个构造函数的原型Fn.prototype = new Fn1()。这样可以继承构造函数以及原型链上的属性和方法。
插件结构
;(()=>{
function Test () {}
Test.prototype = {};
return Test;
})()
分析:
1. 最外层用IIFE包裹,隔离外界
2. 定义构造器和原型
3. 返回构造器
在ES6里面可以用Class来替换构造函数
纯函数
任何时候输入相同的参数,都有相同的返回值返回