构造
构造是在 js 中创建物件(object)的过程, 使用 new
关键字来定义, 构造过程:
- 创建一个空的 js 物件
- 建立此物件与另一物件的关系(设置 constructor)
- 设置此物件
this
关键字 - 如果构造方法没有
return
, 那么返回this
原型
原型是 js 物件继承的机制, 一个物件被创造出来, 一定是具有其「原型」, 比如说二哈被构造出来, 那么它就具有狗的特性.
二哈 => 狗 => 生物 => null
原型分为显示原型(explicit prototype property)与隐式原型(implicit prototype link).
每个函数在创建之后都有一个 prototype
属性, 其值就是此函数的原型.
每个对象都有一个内置的 [[prototype]]
属性, 大多浏览器都支持使用 __proto__
来访问, 当然也可以使用 Object.getPrototypeOf()
来访问.
构造与原型关系
以二哈为例, 二哈是一个实例, 狗是一个构造器, 需要通过 new
关键字加 Dog
这个构造器才能构造出二哈.
二哈长什么样/有什么功能等都是与狗的原型密切相关.
function Dog(name, age) { this.age = age this.name = name}
var ha = new Dog('ErHa', 1)
> haDog {name: "ErHa", age: 1}
构造器:
> ha.constructorƒ Dog(name, age) { this.age = age this.name = name}> Dog.constructorƒ Function() { [native code] }
可以看到二哈(ha)的构造器是狗(Dog), 狗的构造器是 Function
.
原型:
> ha.prototypeundefined> Dog.prototype{constructor: ƒ}
> ha.__proto__{constructor: ƒ}> Dog.__proto__ƒ () { [native code] }
二哈是个实例, 只有隐式原型, 而狗既有显示原型又有隐式原型, 因为它是个构造器, 又是被实例出来的. 可以看出:
ha.__proto__ === Dog.prototypeObject.getPrototypeOf(ha) === Dog.prototype // (same above)
js 是门动态语言, 所以可以随意给实例/构造器添加属性:
> ha.foo = 'foo'> Dog.prototype.bar = 'bar'> ha.foo"foo"> ha.bar"bar"
> ha instanceof Dogtrue> ha instanceof Objecttrue
> ha.__proto__ === Object.prototypefalse> ha.__proto__ === C.prototypetrue
> ha.constructor.name"Dog"
关于 class
class 是 ES6 中基于 js 原型继承链的语法糖, 以上狗的 class 表示如下:
class Dog { constructor(name, age) { this.age = age this.name = name }}
> Dog.constructorƒ Function() { [native code] }
普通类型
> var a = 'a'; var b = 2; var c = true;> a.constructorƒ String() { [native code] }> b.constructorƒ Number() { [native code] }> c.constructorƒ Boolean() { [native code] }> a.__proto__String {"", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}> b.__proto__Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, toPrecision: ƒ, …}> c.__proto__Boolean {false, constructor: ƒ, toString: ƒ, valueOf: ƒ}
小问题
Function.prototype.a = 'a'Object.prototype.b = 'b'function Person() {}var p = new Person()console.log(p.a) // undefinedconsole.log(p.b) // b
有位群友问:
继承关系不应该是 p - Person - Function - Object 吗,应该都可以打印出来,为什么中间没有 fucntion 了呢 Person.proto===Function.prototype
他错在 p
继承与 Person
, 应该是继承与 Person.prototype
, 而 Person.prototype
继承与 Object.prototype
.
Function 是其他声明函数的构造函数,proto 隐式原型指向其构造函数的显式原型
总结
