prototype是怎样工作的
js类型分为基本类型和对象, 对象分为函数对象和一般对象, 用typeOf, 函数对象返回"function", 一般对象返回"object",基本类型返回"number, string, boolean, undefined"
函数对象(包括Function对象本身,使用了递归定义)是内置对象Function的实例。只有函数对象能用new生成一般对象。一般对象不能使用new再生成对象。
函数对象可以作为构子,用new生成新的一般对象。不过, Object,Array, RegExp不用new关键字({},[], / /),但String, Number, Boolean都要。
new生成的对象有一个内部引用proto(getPrototypeOf
),指向构子函数的prototype(钩子函数的prototype,和对象的getPrototypeOf方法
指向一个地方), 从那里继承属性和方法。这个内部引用就叫成对象的prototype, 通过Object.getPrototypeOf得到,形成prototype链。prototype就是一个供继承用的对象。 而钩子函数的getPrototypeOf
指向Function.prototype
,最后才指向Object.prototype
不管函数对象一般对象,都有constructor属性,这个constructor都从构子函数的prototype(getPrototypeOf
)继承。缺省,只要构子缺省的prototype没有改写,prototype的constructor都指向构子。
所有的函数对象, 其构子一律是Function, 非函数对象,构子函数是创建他的函数。比如Math就是Object
每个构子定义的时候都会自动附上prototype属性, 创建出的对象本身又有一个属性constructor指向构子。因此prototype只在函数对象上存在. 如果把构子的prototype设为null, 则构子创建对象.proto为Object.proto.
- 函数对象.proto --> Function.proto --> Object.proto
- 简单对象.proto --> Object.prototype_
- new或者Object.create()对象.proto --> 函数.prototype链 -->Object.proto
https://stackoverflow.com/questions/572897/how-does-javascript-prototype-work
prototype vs constructor构子函数中规定的对象属性不能再添加,此时可以添加到prototype对象。
Object
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
构子函数,把值打包对象,有length和prototype两个属性。创建手段有new Object(); Object.create();{}
in vs hasOwnProperty
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty hasOwnProperty对象是否含有直接自己的属性(不是继承来), in会检查prototype
instanceOf vs typeof
都判断类型信息。instanceOf检查构子,typeof得到字符串
instanceOf, 判断是否对象由给定的构子创建, 看构子的prototype是否在对象的prototype链中。 这也是为什么primitive类型不适用,因为很多时候primitive类型都不用构子创建,也不推荐这样使用。
typeof检查一个值属于六种类型中的哪一个, string, number, boolean, object, function, undefined, 不依赖构子,即使未定义的变量也可以使用。
instanceof
tests the presence of constructor.prototype in object's prototype chain. 测试对象的prototype链中是否存在constructor.prototype https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof#Description
function C() {};
var o = new C();
console.assert(o instanceof C && Object.getPrototypeOf(o) === C.prototype && o instanceof Object && C.prototype instanceof Object);
C.prototype = {};
var o2 = new C();
console.assert(o2 instanceof C && !o instanceof(C) && !Object.getPrototypeOf(o) !== C.prototype)
function D() {}
D.prototype = new C(); // add C to [[Prototype]] linkage of D
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true since C.prototype is now in o3's prototype chain
instanceof测试随着构子的prototype属性, 或者Object.setPrototypeOf方法而变化。
Object和Function
function ninja(){};
console.assert(ninja instanceOf Object && ninjia.instanceOf Function);
prototype
https://stackoverflow.com/questions/572897/how-does-javascript-prototype-work
以下判断都是true
function Person() {};
// 因为Person作为function创建, 因此与所有的function共享prototype函数对象
console.log(Object.getPrototypeOf(Person) === Person.__proto__ === Function.prototype);
// 构成Person → Function.prototype → Object.prototype 的__proto__链条
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);
// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:在两个链条上跳转
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === p.__proto__ === Person.prototype);
// prototype链条与Person所构建的对象几乎没有关系,Person构建的对象有自己的prototype链条
//p → Person.prototype → Object.prototype (end point)
console.log(p.constructor === Person);
console.log(p instanceof Person);
由此看到Person与两个chain(一个是函数本身代表的对象,一个是作为构子,构子才有prototype, 对象通过Object.getPrototypeOf方法,或者隐含的proto属性,图1)都有关系,要从一个链跳到另外一个, 可以用.prototype从构子的链跳到对象的链, 可以用.constructor从对象的链跳到构子的链。
prototype属性并没有主体的prototype链的信息,只有主题创建的对象的信息。prototype属性实际上叫做prototypeOfConstructedInstances更好。
Person.prototype对象在函数创建的时候就创建了,尽管函数没有执行,但该对象仍然以函数为构子。因此有两个对象产生, 一个是Person函数本身,另一个prototype对象,在创建对象的时候作为prototype. 此对象是后面创建的对象的prototype链的parent.