原型对象和原型链
假设,在你面前只有一门伟大的JavaScript语言,一个项目立项,没有任何一行代码,JavaScript的库世界仍然是空白的,你需要用原生的JavaScript代码一行一行搭建一个网站。
首先你需要创造第一个对象。
(在以类为中心的面向对象编程语言中,类和对象的关系可以想象成铸模和铸件的关系,对象总是从类中创建而来。而在原型编程的思想中,类并不是必需的,对象未必需要从类中创建而来,一个对象是通过克隆另外一个对象所得到的)
关键字是克隆,你的项目目前还是一片荒芜,那你从哪里去拿东西来克隆作为你的第一个对象呢?
答案:从原型对象中拿东西。我称对象的第一个原型对象(Object的原型对象)为 源原型对象
介绍一下源原型对象的属性:
- 源原型对象作为开天辟地之前就存在的一坨东西,他是JavaScript提供给我们开创世界的最原材料。
其中它具有所有原型对象都有的东西:constructor 和 constructor里面的<prototype>
,即各层级的原型对象都会拥有一个constructor指向它的构造函数和 constructor里面一个指向上一层原型对象的<prototype>
指针,而这些由许多原型对象形成的树形结构关系,就称为原型链。原型链的终点始终是源原型对象
(注:本文所有的控制台输出都是火狐浏览器的输出,有些浏览器中<prototype>
会输出为__proto__
)
原型层级说明图:
-
实例对象的属性包含了两种属性,一种是本地属性(又称为实例属性),一种是引用的属性,即原型属性。
-
由于所有的实例对象共享同一个prototype对象(或者说共享同一条原型链),那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样,这就是Javascript原型继承机制的设计思想。
new Object()
new关键字的理解:
1、创建一个空的简单JavaScript对象(即{})
2、链接该对象(设置该对象的constructor)到另一个对象 ;
3、将步骤1新创建的对象作为this的上下文 ;(apply,call)
4、如果该函数没有返回对象,则返回this
实现一个和new的作用一样的myNew方法:
function _new(constructor, ...arg) {
var obj = {}; // 对应于上面的步骤 1
obj.__proto__ = constructor.prototype; // 对应于上面的步骤 2
var res = constructor.apply(obj, arg); // 对应于上面的步骤 3
return Object.prototype.toString.call(res) === '[object Object]' ? res : obj; // 对应于上面的步骤 4
}
function abc(a) {
this.a = a;
};
let a1 = _new(abc, '22')
console.log(a1);
字面量创建对象
字面量创建是属于一个语法糖,本质还是通过 new Object()
继承
学习继承前,先要彻底弄懂bind、apply 、call,他们的共同点和不同点,他们的应用场景。
- bind 根据原函数创建一个新函数,并指定this指向和预设参数
○ 应用
■ 创建指定this指向的函数。
■ 拥有预设的初始参数的偏函数
■ 配合setTimeout使用(例如setTimeout() 里操作某个对象的属性,this指向的是window而不是目标对象)
■ 多次快捷调用 - apply 调用一个指定this指向的函数,参数为数组或类数组
○ 妙用
■ 将数组各项添加到另一个数组(区别于concat的新建一个合并数组)
■ 配合内置函数遍历数组各项的需求,可以避免循环。
■ 使用apply来链接构造器 - call 调用一个指定this指向的函数,参数为一个或者多个
○ 妙用
■ 调用父构造函数
■ 调用匿名函数
阮一峰大神下面的四文已经说得很明白了。有其他理解我再补充
Javascript继承机制的设计思想
部分代码和解析文字参考以下资料。致谢
《JavaScript设计模式与开发实践》——曾探