什么是构造函数?
构造函数本身就是一个函数,与普通函数没有任何区别,不过为了规范一般将其首字母大写。构造函数和普通函数的区别在于,使用 new 生成实例的函数就是构造函数,直接调用的就是普通函数。
constructor
- constructor 返回创建实例对象时构造函数的引用。此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。
- 构造函数
1 2 3 4 5 6
| function Parent(age) { this.age = age; } var p = new Parent(50); p.constructor === Parent; p.constructor === Object;
|
- 普通函数
1 2 3 4 5 6 7
| function parent1(age) { return { age: age } } var p = parent1(20); p.constructor === Object;
|
- 对于基本类型(String、Number、Boolean、Symbol、null、undefined)constructor只读,当然null、undefined没有构造属性;对于引用类型constructor可修改。
new Class()详解
案例
- 代码:
1 2 3 4 5
| function Person(name, age){ this.name = name; this.age = age; } var p = new Person('chao', 12);
|
new Person(‘chao’, 12)一个对象的4个过程
- 创建一个空对象
- 让实例对象中this指向obj, 并且执行Person函数体
1
| var result = Person.call(this);
|
- 设置原型链,将obj的__proto__指向实例化对象的prototype成员对象
1
| obj.__proto__ = Person.prototype;
|
- 判断实例化返回类型
1 2 3 4 5
| if(typeof(result) === 'object'){ p = result; }else{ p = obj; }
|
模拟实现new
1 2 3 4 5 6 7 8 9 10
| function create() { Con = [].shift.call(arguments); var obj = Object.create(Con.prototype); var ret = Con.apply(obj, arguments); return ret instanceof Object ? ret : obj; };
|
原型
prototype
_proto_
原型链
- 含义:每个对象拥有一个原型对象,通过 _proto_ 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null。这种关系被称为原型链 (prototype chain)
1 2 3 4 5 6 7 8 9
| function Person(name, age){ this.name = name; this.age = age; } var p = new Person('chao', 12); p p.__proto__ === Person.prototype p.__proto__.__proto__ === Object.prototype p.__proto__.__proto__.__proto__ === null
|
总结
- Symbol 作为构造函数来说并不完整,因为不支持语法 new Symbol(),但其原型上拥有 constructor 属性,即 Symbol.prototype.constructor。
- 引用类型 constructor 属性值是可以修改的,但是对于基本类型来说是只读的,当然 null 和 undefined 没有 constructor 属性。
- _proto_ 是每个实例上都有的属性,prototype 是构造函数的属性,这两个并不一样,但 p._proto_ 和 Parent.prototype 指向同一个对象。
- _proto_ 属性在 ES6 时被标准化,但因为性能问题并不推荐使用,推荐使用 Object.getPrototypeOf()。
- 每个对象拥有一个原型对象,通过 _proto_ 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null,这就是原型链。
思考题
- js无限累计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function add(a){ function sum(b){ a += b; return sum; }
sum.toString = function(){ console.log('======'); return a; }
return sum; } add(1)(2)(3)
|
我们知道打印函数时会自动调用 toString()方法,函数 add(a) 返回一个闭包 sum(b),函数 sum() 中累加计算 a = a + b,只需要重写sum.toString()方法返回变量 a 就OK了