值得推荐:理解 JavaScript 的原型链和继承
instanceof 运算符可以用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上1
什么意思呢?
来个题Function instanceof Object;用高中数学的话就是把x,y代入公式得:
instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。
等等,斜体字的这俩到底是什么鬼意思?
prototype属性是原型链吗?
JS是基于原型链面向对象语言,也就是说所有对象都是以对象为模板创建实例的。如果是其他oo语言的背景比如Java或Ruby,都习惯于创建一个class模板,class创建object实例。比如ruby:
为什么要把方法绑到prototype上?直接 A.toString…= 不行吗?
在解释prototype之前,先解释一下 new A 到底发生了什么2:
但是 __proto__ 又是什么
__proto__ 才是原型链
__proto__ 是内部 [ [Prototype ]] (说了半天原型链这就是牛逼闪闪的 原型链, 指向对象或者null)的getter和setter方法(已加入ES6规范3,但是还是建议只使用Object.getPrototypeOf())
JS对象能使用它原型链对象的所有方法,比如所有的对象的原型链(的原型链的原型链的原型链…)都最终会指向Object(或null)。因此,所有的对象都能使用Object.prototype上的方法,比如我之前覆盖掉的 toString 本身就是Object.prototype上的方法,如果没有覆盖,它是可以拿到所有Object上的方法的:
instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。
所以instanceof其实就是
为了养成良好的习惯,实际项目最好使用 getPrototypeOf 取原型链,这里只是为了方便我采用__proto__
下面来看第二个题
Object instanceof Function
难道可以互相链吗?这意味着
多简单呢,一共就分别有两类:
原型链指向Function.prototype的函数们
原型链指向Object.propotype的对象们
而原型链顶端的Object.prototype就再没有原型链了,所以是空
现在再回头看题目是不是so easy了。
也没什么卵用得 contructor
如果你好奇的在FireFox Console中看一下 a 除了刚才那些玩意,还有一个奇怪的东西
话说 A 里面这个constructor是个什么鬼,我们来玩它一下
然而除了这个功能也并没有什么卵用嘛。
真的是这样吗?
.
..
…
….
…..
……
…….
恩,真的!
Bonus 继承
下面这个是babel 从es6 class
Author: Jichao Ouyang
什么意思呢?
来个题Function instanceof Object;用高中数学的话就是把x,y代入公式得:
instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。
等等,斜体字的这俩到底是什么鬼意思?
prototype属性是原型链吗?
JS是基于原型链面向对象语言,也就是说所有对象都是以对象为模板创建实例的。如果是其他oo语言的背景比如Java或Ruby,都习惯于创建一个class模板,class创建object实例。比如ruby:
class A这里的类A就是所有 A.new 创建出来的实例的模板而已。而对于原型链语言JS来说,同意的事情要这样做
def initialize name @name = name end
def to_s
@name
end
endputs A.new('hehe') # => hehe
function A(name){ this.name = name
}
A.prototype.toString = function(){ return this.name
}var a = new A('hehe')
console.log('object name is:' + new A ('hehe')) // => object name is: hehe
- 这里的怪怪的函数其实就是constructor,相当于ruby例子里的initialize
- 而prototype上的方法toString也就是类似class模板上的方法。
为什么要把方法绑到prototype上?直接 A.toString…= 不行吗?
在解释prototype之前,先解释一下 new A 到底发生了什么2:
1: // var a = new A('hehe') =>2: var a = new Object();3: a.__proto__ = A.prototype; (proto)4: A.call(a, 'hehe');其中 A.call 的意思是先把A的this设置为a,然后执行A的body也就是this.name=name
但是 __proto__ 又是什么
__proto__ 才是原型链
__proto__ 是内部 [ [Prototype ]] (说了半天原型链这就是牛逼闪闪的 原型链, 指向对象或者null)的getter和setter方法(已加入ES6规范3,但是还是建议只使用Object.getPrototypeOf())
JS对象能使用它原型链对象的所有方法,比如所有的对象的原型链(的原型链的原型链的原型链…)都最终会指向Object(或null)。因此,所有的对象都能使用Object.prototype上的方法,比如我之前覆盖掉的 toString 本身就是Object.prototype上的方法,如果没有覆盖,它是可以拿到所有Object上的方法的:
a.toString === A.prototype.toString // truea.toLocalString === Object.prototype.toLocalString // truea.__proto__ === A.prototype // true所以,现在是否可以理解这句话了呢
instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。
所以instanceof其实就是
Function.__proto__ === Object.prototype// false擦,假设失败了呢,让我们来看看为什么不对,Function.__proto__到底指哪去了
Function.__proto__ === Function.prototype//true原来指向自己的prototype了呢,那就意味着…
Function instanceof Function//trueyes,然而 Function instanceof Object似乎也能解释了
Function.__proto__ === Function.prototypeFunction.__proto__.__proto__ === Object.prototype所以如果我们让
Function.__proto__.__proto__ = nullFunction instanceof Object//false这回知道为什么不要用 __proto__ 了吧,一不小心重写了会导致所有继承自它的对象都受影响。
为了养成良好的习惯,实际项目最好使用 getPrototypeOf 取原型链,这里只是为了方便我采用__proto__
下面来看第二个题
Object instanceof Function
难道可以互相链吗?这意味着
Object.__proto__ === Function.prototype// true// 但是Firefox取不到Object.__proto__, 看来做了保护,必须要用// Object.getPrototypeOf(Object) === Function.prototype要晕了, 忍不住要画个图
多简单呢,一共就分别有两类:
原型链指向Function.prototype的函数们
原型链指向Object.propotype的对象们
而原型链顶端的Object.prototype就再没有原型链了,所以是空
现在再回头看题目是不是so easy了。
也没什么卵用得 contructor
如果你好奇的在FireFox Console中看一下 a 除了刚才那些玩意,还有一个奇怪的东西
话说 A 里面这个constructor是个什么鬼,我们来玩它一下
a.constructor === A.prototype.constructor这只是函数都有的一个玩意而已, 由于js的函数可以作为构造器,也就是可以 new ,所以所有的 函数的prototype.constructor都指向自己,因此所有的 new 出来的对象也都有一个reference能找到自己的构造器。
A.prototype.constructor === A
A.prototype.constructor = nulla.constructor // => nulla instanceof A // true
然而除了这个功能也并没有什么卵用嘛。
真的是这样吗?
.
..
…
….
…..
……
…….
恩,真的!
Bonus 继承
下面这个是babel 从es6 class
class A{编译出来的ES5继承
constructor(name) { this.name= name
}
toString() { return this.name
}
}class B extends A {
toString(){ return this.name + 'b'
}
}
function _inherits(subClass, superClass) {其他地方都不用看了,inherits 函数用到了之前学到的所有玩意,要求实现要满足下列所有的cases,就当是课后练习了:
// 密}var A = (function () { function A(name) { this.name = name;
}
A.prototype.toString = function toString() { return this.name;
}; return A;
})();var B = (function (_A) { function B() { if (_A != null) {
_A.apply(this, arguments);
}
}
_inherits(B, _A);
B.prototype.toString = function toString() { return this.name + 'b';
}; return B;
})(A);
var a= new A('A');var b= new B('B');
a.constructor === A &&
b.constructor === B &&
a instanceof A &&
b instanceof A &&
b instanceof B
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof
- 这里只是意思,但是如果真的改变 __proto__ 是非常低效的https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
- http://www.ecma-international.org/ecma-262/6.0/#sec-additional-properties-of-the-object.prototype-object
Author: Jichao Ouyang