-
原型
【构造函数】 首字母大写,他里面定义了各种需要共享的属性和方法。构造函数里面有prototype属性,是个指针,指向他的【原型对象】,原型对象中有个construction属性,默认指回构造函数。可以向原型对象中写入属性和方法
当new一个【实例对象】时,构造函数中的this指向这个实例对象,实例对象中有个[[Prototype]],指向构造函数的原型对象,可以通过浏览器提供的__proto__
来访问到。
继承:根据proto一级一级的向上查找,找到了父辈和爷爷辈的属性
- 构造函数通过 构造函数.prototype ,来定义原型对象(向其中写入属性和方法),达到共享数据、节省内存的目的
- 原型对象中有 constructor 构造器,指向他的构造函数
- 通过 new 构造函数,可以创建一个实例对象,这个实例对象继承了构造函数中的所有属性和方法,同时,可以通过浏览器属性proto,来访问原型对象中的属性和方法
- 当输出实例对象中的属性或方法时,会首先输出对应的构造函数中的对应属性或方法,如果找不到,则通过proto也就是原型链,向上寻找其构造函数中对应的属性或方法,一级一级逐层向上,直到找到为止。
- 一切的原型链都会最终指向 Object.prototype ,而 Object.prototype 的proto为null。
new 一个对象的过程: var obj = new Foo()
- 创建了一个新的空对象 {}
- 将构造函数的作用域赋给新对象(this就指向新对象)执行构造函数的代码(为对象添加属性)
- 设置原型链,将obj的proto指向了 Foo 函数对象的 prototype 原型对象
- 返回新对象 obj
工厂模式:函数名小写,函数内部new Object(),有返回对象return X,直接调用函数可以创建
属性遮蔽:实例会现在自身查找有没有对应的属性或者方法,如果没有,就去proto上面去找,如果还没有,就继续在proto.proto去找,一直到为null,停止搜索。这种情况称为"属性遮蔽 (property shadowing)。
弊端:如果在当前实例没有的属性和方法,js就会遍历原型链上所有的属性和方法,这样很耗费性能。所以请注意代码中原型链的长度,并在必要时将其分解,以避免可能的性能问题
不要试图修改或扩展原生对象的原型:尽量不要去修改类似Object.prototype,你可能会覆盖原型属性或方法,也可能对继承自Object的实例发生不可预知的bug**
- this 指向问题
function foo(){}
var obj = {}
- 默认绑定:function中的this,如果直接执行,那么指向的是全局对象-window
- 隐式绑定:整个调用链上,处于方法上一层的对象,如 obj.foo(),this指的是obj对象
- 显示绑定:call和apply bind的参数形式类似于call,但是返回的是显式绑定后的函数对象,需要后续去调用执行。 bind常用于柯里化一个函数对象。 如:foo.call(obj),this指向obj。(显式绑定中,如果对this不敏感,可以传入null,但是可能有副作用。 更安全的做法是,传入一个空对象,即var empty = Object.create(null),它连指向Object.prototype的proto都没有,比{}更空。)
- new绑定:var obj = new foo(),this指向obj这个实例对象
- ⚠️箭头函数没有this绑定,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)
优先级
- new在调用构造函数的时候做初始绑定。
- 显式绑定或硬绑定优先级最高。
- 没有显式绑定,就使用隐式绑定。
- 如果都没有,就使用默认绑定(undefined,是不是全局看严格模式)。
网友评论