Open Hibop opened 5 years ago
prototype
new Fn()
对于有基于类的语言经验 (如 Java 或 C++) 的开发人员来说,JavaScript 有点令人困惑,因为它是动态的,并且本身不提供一个class实现相关类的继承。全靠一种很奇特的"原型链"(prototype chain)模式,来实现类的继承扩展。(在 ES2015/ES6 中引入了class关键字,但只是语法糖,JavaScript 仍然是基于原型的)。
prototype chain
历史说起 http://blog.vjeux.com/2011/javascript/how-prototypal-inheritance-really-works.html
Brendan Eich
1.引入new 从构造函数constructor(相当于类class)到实例
new
constructor
class
function GirlFriend (name) { // this.gender = '女'; this.name = name; } var lujisGirl = new GirlFriend('庄颜'); // 《三体》罗辑的梦中女神 var jdsGirl = new GirlFriend('奶茶');
2.prototype属性的引入 构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。无法做到数据共享,也是极大的资源浪费。 比如:女神都有的特点——美、体贴、善良的女性...
function GirlFriend (name) { // this.gender = '女'; this.name = name; } GirlFriend.prototype.gender = '女'; var lujisGirl = new GirlFriend('庄颜'); var jdsGirl = new GirlFriend('奶茶'); console.log(lujisGirl.gender, jdsGirl.gender); // '女' '女' GirlFriend.prototype.gender = '男'; // 假设 console.log(lujisGirl.gender, jdsGirl.gender); // '男' '男'
实例对象共享构造函数的同一个prototype对象, 这样便实现了"继承"。
1.在JavaScript中创建函数时,JavaScript引擎会向函数添加prototype属性。此prototype属性是一个对象(称为原型对象),默认情况下具有构造函数属性。构造函数属性指向原型对象是属性的函数。
Fn.prototype.constructor === Fn
2.JavaScript创建实例对象时(new constructor(), 赋值创建, Object.create()除外),JavaScript引擎会将__proto__属性添加到新创建的对象中,该对象称为dunder proto(魔术__proto__ (php/python有此概念))。proto指向构造函数的原型对象。
new constructor()
Object.create()
__proto__
dunder proto
obj.__proto__ === Fn.prototype
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop] else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop) else return undefined }
回到myGirl栗子:lujisGirl(实例) --> GirlFriend.prototype --> Object.prototype --> null
lujisGirl(实例) --> GirlFriend.prototype --> Object.prototype --> null
谈到继承时,JavaScript只有一种结构:对象(实例对象, 构造函数(函数也是对象))。
实例对象只有__proto__属性, 函数对象既有prototype对象, 也有__proto__属性;prototype对象有constructor和__proto__属性。
实例对象(obj )的__proto__指向它构造函数的原型对象(prototype)。该原型对象(prototype)也有一个自己的原型属性proto ,层层向上直到一个对象(Object.__proto__)的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
Object.__proto__
null
Object.prototype.__proto__ === null
// 伪代码 function new(GirlFriend(args)) { var obj = {}; // 创建空对象 obj.__proto__ = GirlFriend.prototype; // 建立原型链[继承] var result = GirlFriend.call(obj, args); // 构造函数执行,将this-> obj, 非继承属性 this.name执行 return typeof result === 'object'? result : obj; // 判断构造函数return: 无返回值 或者 返回一个非对象值 }
stackoverflow上一个人的回答来:
In JavaScript, most functions are both callable and instantiable: they have both a [[Call]] and [[Construct]] internal methods.
在JS中,绝大多数的函数都是既可以调用也可以实例化的.我们既可以直接执行函数得到函数的返回值.也可以通过new操作符得到一个对象.
无:null
无中生有: null --> No.1_obj (Object.prototype);
Object.prototype
顶层机器:Object() + 模板对象 => 批量新对象: new Object({a: 12})
继承自Object.prototype(No.1)
二级机器:分化的构造函数: String、Number、Boolean、Array、Date、Error..., 在No.2基础上+新功能
String、Number、Boolean、Array、Date、Error...
继承自No.2 [No.2是谁造出来?]
缺少一台制造机器的机器: Function诞生,生产No.2
所有上层机器(构造函数)都是Function创造
Object作为一个机器可以看做是有由Function制造出来的,而Function作为一个对象可以看做是由Object制造出来的。
搞懂下边一张经典图,便搞懂js对象世界
// 看成对象 Object instanceof Function; Function instanceof Function; Object instanceof Object; Function instanceof Object; Object.__proto__ === Function.prototype; Function.__proto__ === Function.prototype; Object.__proto__.__proto__ === Object.prototype; Function.__proto__.__proto__ === Object.prototype; // 到顶级 Object.__proto__.__proto__.__proto__ === Function.__proto__.__proto__.__proto__ === null;
typeof sth
obj instanceof constructor
Object.prototype.toString.call(obj) // 最靠谱
Object.prototype.toString.call(obj)
export function type(obj) { const toString = Object.prototype.toString; const map = { '[object Boolean]': 'boolean', '[object Number]': 'number', '[object String]': 'string', '[object Function]': 'function', '[object Array]': 'array', '[object Date]': 'date', '[object RegExp]': 'regExp', '[object Undefined]': 'undefined', '[object Null]': 'null', '[object Object]': 'object' }; return map[toString.call(obj)]; }
HTMLDivElement.prototype | |.__proto__ | HTMLElement.prototype | |.__proto__ | Element.prototype | |.__proto__ | Node.prototype | |.__proto__ | EventTarget.prototype | |.__proto__ | Function.prototype | |.__proto__ | Object.prototype | |.__proto__ | null
首先问自己:静态属性、原型属性、实例方法、构造函数、继承/扩展
function Foo(){ getName = function(){ console.log(1) } return this; } Foo.getName = function(){ console.log(2) } Foo.prototype.getName = function(){ console.log(3) } var getName = function(){ console.log(4) } function getName(){ console.log(5) } // pls ouput the results: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
https://hackernoon.com/prototypes-in-javascript-5bba2990e04b
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes
https://github.com/mqyqingfeng/Blog/issues/2
http://blog.vjeux.com/2011/javascript/how-prototypal-inheritance-really-works.html
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
https://medium.com/@peterchang_82818/javascripter-%E5%BF%85%E9%A0%88%E7%9F%A5%E9%81%93%E7%9A%84%E7%B9%BC%E6%89%BF%E5%9B%A0%E5%AD%90-prototype-prototype-proto-object-class-inheritace-nodejs-%E7%89%A9%E4%BB%B6-%E7%B9%BC%E6%89%BF-54102240a8b4
http://www.ituring.com.cn/article/56184
先创建对象,然后再修改原型:覆盖后,已经创建的对象无法访问到修改后的原型
内容提要
prototype
: js历史;new Fn()
的实现原理;面向对象的三个基本特征是:封装、继承、多态。
Javascript继承机制和prototype设计
Brendan Eich
负责开发这种新语言。他觉得,没必要设计得很复杂:Javascript里面所有的数据类型都是对象(object),这一点与Java非常相似。但是,他随即就遇到了一个难题,到底要不要设计"继承"机制呢————Javascript里面都是对象,必须有一种机制,将所有对象联系起来。最终js面向对象的设计
1.引入
new
从构造函数constructor
(相当于类class
)到实例2.
prototype
属性的引入 构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。无法做到数据共享,也是极大的资源浪费。 比如:女神都有的特点——美、体贴、善良的女性...原型
1.在JavaScript中创建函数时,JavaScript引擎会向函数添加
prototype
属性。此prototype
属性是一个对象(称为原型对象),默认情况下具有构造函数属性。构造函数属性指向原型对象是属性的函数。2.JavaScript创建实例对象时(
new constructor()
, 赋值创建,Object.create()
除外),JavaScript引擎会将__proto__
属性添加到新创建的对象中,该对象称为dunder proto
(魔术__proto__
(php/python有此概念))。proto指向构造函数的原型对象。原型链查找
回到myGirl栗子:
lujisGirl(实例) --> GirlFriend.prototype --> Object.prototype --> null
结论:
谈到继承时,JavaScript只有一种结构:对象(实例对象, 构造函数(函数也是对象))。
实例对象只有
__proto__
属性, 函数对象既有prototype
对象, 也有__proto__
属性;prototype对象有constructor
和__proto__
属性。实例对象(obj )的
__proto__
指向它构造函数的原型对象(prototype
)。该原型对象(prototype
)也有一个自己的原型属性proto ,层层向上直到一个对象(Object.__proto__
)的原型对象为null
。根据定义,null
没有原型,并作为这个原型链中的最后一个环节。new背后的故事
stackoverflow上一个人的回答来:
在JS中,绝大多数的函数都是既可以调用也可以实例化的.我们既可以直接执行函数得到函数的返回值.也可以通过new操作符得到一个对象.
JavaScript 世界万物诞生记
要点概括:
无:
null
无中生有: null --> No.1_obj (
Object.prototype
);顶层机器:Object() + 模板对象 => 批量新对象: new Object({a: 12})
二级机器:分化的构造函数:
String、Number、Boolean、Array、Date、Error...
, 在No.2基础上+新功能缺少一台制造机器的机器: Function诞生,生产No.2
所有上层机器(构造函数)都是Function创造
Object作为一个机器可以看做是有由Function制造出来的,而Function作为一个对象可以看做是由Object制造出来的。
搞懂下边一张经典图,便搞懂js对象世界
js对象的类型判断
typeof sth
;obj instanceof constructor
; // 构造函数实例Object.prototype.toString.call(obj)
// 最靠谱HTML元素的prototype
js属性方法整理,class语法糖(es6+)
最后的小实战
参考文献
https://hackernoon.com/prototypes-in-javascript-5bba2990e04b
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes
https://github.com/mqyqingfeng/Blog/issues/2
http://blog.vjeux.com/2011/javascript/how-prototypal-inheritance-really-works.html
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
https://medium.com/@peterchang_82818/javascripter-%E5%BF%85%E9%A0%88%E7%9F%A5%E9%81%93%E7%9A%84%E7%B9%BC%E6%89%BF%E5%9B%A0%E5%AD%90-prototype-prototype-proto-object-class-inheritace-nodejs-%E7%89%A9%E4%BB%B6-%E7%B9%BC%E6%89%BF-54102240a8b4
http://www.ituring.com.cn/article/56184