js中得构造方法其实也是一个普通方法为了区别于普通方法构造器一般开头字母大写例如
function Dog(name) {
this.name = name
}
此时我们创建了一个Dog得构造方法,当然它也是一个对象我们可以直接给它附上属性和方法等,但是这是一个抽象得东西,我们想得到得是一个具体得dog,有自己得属性和方法,所以需要用它去建造一个对象需要用到 new 关键字告诉js引擎我要创造一个dog对象实例,那么这个过程都发生了什么呢
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
原型链理解起来麻烦还容易忘,其实只要拆两个步骤,简单而且万能,再也不会被别人绕蒙了
1、首先我们要创建构造方法,这时候程序会同时创建一个 prototype 属性,这个属性是一个对象,留给未来通过它创建得对象引用,所以说构造器得prototype和对象得__proto__ 指向得是同一个东西
2、我创建对象后我要知道对象是谁创建得所以我要给引用的对象一个constructor表示这个对象是由谁创建得,所以让这个constructor指向那个构造函数就ok啦
此时几乎已经万能啦,流程图啥的都不要看了,本来很简单得东西弄得那么复杂,再强调一遍,构造函数都有
prototype属性是为了给对象增加额外得能力,注意是额外,如果对象本身有那个属性也就是上边那个name那就没必要也不会到这个prototype对象里边找啦。
然后咱们测试一下,主要为了印证上班那两句话,同时加深理解巩固一下
上班我已经创造一个Dog构造方法,那么我们脑子就首先想到他已经创建了一个prototype对象啦,我创建得对象直接用我就行了,只不过此时我这个对象里边啥都没有,此时 new ('单身狗') 得话我只有一个本身得name属性。下面我再给 prototype 一些能力,比如
Dog.prototype.age = 11
那么prototype就有了age的属性,生成的对象也自然能访问到这个属性的能力,想一想既然我说过两个地方用的prototype是一个东西那么这个代码在new以前和以后执行肯定都是可以的,它不像构造方法里边的那一堆东西,new 以后我们便没什么关系了,所以那些东西要提前写好,当然一般都会写在前边,我已经生成对象实例了,我直接用多好,优先级还高,还不用一点点往下查,何乐而不为呢?第一句话已经印证了,是不是超级有用。
然后往下想想,这个prototype也是一个对象,既然是对象可定也有__proto__指向另一个构造函数的prototype 那么这个函数是什么呢,其实就 Object 因此 Dog的构造方法也同时有了Object.prototype的能力,比如 toString 等等。
call apply bind 方法
任何方法可以是构造器的同时它也是一个对象,既然是对象那么就会有构造器,它的构造器是 Function,
比如新建一个构造器A Function A(){} 那么
A.__proto__ === Function.prototype
所以 A 继承了Function.prototype上的方法,有apply、call、bind等,所以可以通过
A.call(xxx)
这种方式使用,从而改变this指针,他们的区别是apply、call差不多,只不过apply第二个参数是数组,call是2~n个参数,他们返回调用的结果 bind 返回的是一个复制函数,并没有调用
一些应用场景
Object.prototype.toString 判断类型
//类数组没有数组的方法可以借用数组的方法
var arrayLike = {
0: 'OB',
1: 'Koro1',
length: 2
}
Array.prototype.push.call(arrayLike, '添加元素1', '添加元素2');
//获取最大最小值,省略了展开步骤
const arr = [15, 6, 12, 13, 16];
const max = Math.max.apply(Math, arr); // 16
const min = Math.min.apply(Math, arr); // 6