原型
了解原型链,我们先了解下原型
- 所有的对象都有toString()、valueOf()、constructor、hasOwnProperty()等
- 所有的数组都是有对象应该有的属性
- 所有的数组都有push()、shift()、join()、slice()、splice()等
- var array = [] 应该有数组共有的所有属性
var array = []
我们用console.dir()检测下array有什么属性
我们发现 console.dir(array) 打出来的结果是:
- array 有一个属性叫做
__proto__
(它是一个对象) -
array.__proto__
有很多属性,包括 push()、shift()、join()、slice()、splice()等 -
array.__proto__
其实也有一个叫做__proto__
的属性,包括toString()、valueOf()、constructor、hasOwnProperty()等 -
array.__proto__.__proto__
其实也有一个叫做__proto__
的属性(console.log 没有显示),值为 null
原型链
当我们读取 array.toString 时,JS 引擎会做下面的事情:
- 看看 array 数组本身有没有 toString 属性。没有就走到下一步。
- 看看
array.__proto__
有没有 toString 属性,发现array.__proto__
有 toString 属性,于是找到了
所以 array.toString 实际上就是第 2 步中找到的 array.__proto__.toString
。
可以想象,
- 如果
array.__proto__
没有,那么浏览器会继续查看array.__proto__.__proto__
- 如果
array.__proto__.__proto__
也没有,那么浏览器会继续查看array.__proto__.__proto__.__proto__
- 直到找到 toString 或者
__proto__
为 null。
上面这个搜索过程,是连着由__proto__
组成的链子一直走的。
这个链子,就叫做原型链。
API
hasOwnProperty() 方法
hasOwnProperty() 方法会返回一个布尔值,指示对象是否具有指定的属性作为自身(不继承)属性。
var o = {
name:'jack'
}
o.hasOwnProperty('name'); // true
o.hasOwnProperty('toString'); // false
Object.create() 方法
Object.create() 方法使用指定的原型对象和其属性创建了一个新的对象。
var a ={
name:'jack'
}
var b = {
form:'china'
}
a = Object.create(b)
prototype
对象.__proto__
=== 对象.constructor.prototype
function Person(){}
Person.prototype.name = 'jack'
var person= new Person()
console.log(person.name) // jack
console.log(person.__proto__ === Person.prototype) // true
console.log(Person.__proto__ === Person.constructor.prototype) // true
console.log(Person.__proto__ === Function.prototype) //true
console.log(Person.prototype.constructor === Person) // true
console.log(Object.prototype.__proto__ === null) // true
console.log(Object.prototype.constructor === Object) // true
console.log(person.constructor === Person) // true
console.log(person.constructor === Person.prototype.constructor) // true
只有对象才有__proto__
,只有函数才有 prototype
。
JS原型继承
通过一段代码来展示js原型继承的过程
下面这段代码如何让Cat是Animal的子类
function Animal(){
this.物种=物种
}
Animal.prototype.run={}
function Cat(name){
Animal.call(this) //这句话是调用Animal里的方法.由于下边会用new调用这段代码所以这里的this指向的是一个空的临时对象里.
this.name=name
}
Cat.prototype.say=function(){}
Cat.prototype.__proto__ = Animal.prototype //这种写法虽然可以但是会消耗大量的页面性能,而且对IE的兼容也是IE11才可以
Cat.prototype = Object.creat(Animal.prototype) //这种方法只能支持到IE9
function FakeAnimal(){} //创建一个空的对象这样避免this.物种=物种添加到原型里,因为new会调用Aniaml里的临时对象里的this.物种=物种
FakeAnimal.prototype = Animal.prototype //让这个假的对象拥有真的Animal原型
Cat.prototype =new FakeAniaml() //利用new方法会让让FakeAniaml.__proto__指向FakeAniaml.prototype,也就是让Cat.prototype拥有FakeAniaml.prototype属性方法
var cat = new Cat()
Cat.run()
下面用ES6 class的方法写出上边一样的效果
class Animal{
constructor(物种){
this.物种=物种
}
run(){}
}
class Cat extends Animal{ //extends让Cat继承Animal的原型
constructor(){
super('加菲猫') //把父类的函数运行一下
this.name =name
}
say(){}
}
ES6 class如果想在原型链里添加属性目前看来不行或许下个版本会添加新的方法
如何用new面向对象编写jQuery
function $(selector){
if(this instanceof $ === false){ //判断是否用new instanceof 检测this是否在$函数原型链里
return new $(selector)
}else{
var array = document.querySelectorAll(selector)
for(var i = 0;i<array.length;i++){
this[i]=array[i]
}
}
}
$.prototype.on =function(){
console.log('你调用了 on')
return this
}
$.prototype.addClass =function(){
console.log('你调用了 addClass')
return this
jQuery('div').on().addClass()