JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object ,Function 是JS自带的函数对象。javascript
怎么区分?其实很简单,凡是经过 new Function() 建立的对象都是函数对象,其余的都是普通对象。Function Object 也都是经过 New Function()建立的。html
构造函数可用来建立特定类型的对象。像Object和Array这样的原生构造函数,在运行时会自动出如今执行环境中。java
function Person() {
}
var person = new Person();
person.name = 'Kevin';
console.log(person.name) // Kevin
复制代码
按照国际惯例,构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。git
要建立Person的新实例,必须使用new操做符。通常是经历如下四个步骤:github
上面例子中,person 就用有一个constructor (构造函数)属性,该属性是指向Person。api
不管何时,只要建立一个新函数,就会根据一组特定的规则为该函数建立一个prototype属性,这个属性指向函数的原型对象。普通对象没有 prototype,但有 __proto__
属性。数组
如上面例子,Person.prototype 指向了原型象,而 Person.prototype.constructor 又指回了Person。函数
而 person 只是一个对象实例。ui
而person能够访问保存在原型中的值,但却不能重写原型中的值。若是咱们在 person 中添加一个属性,而该属性与实例原型中的一个属性同名,那个person中的属性会暂时屏蔽原型中的属性,删除后,仍是读回原型中的属性this
function Person() {
}
Person.prototype.name = 'Perty';
var person = new Person();
person.name = 'Kevin';
console.log(person.name) // Kevin
delete person.name
console.log(person.name) // Perty
复制代码
解析器的操做是:
删除后,再运行时:
在建立对象(不管是普通对象仍是函数对象)的时候,都有一个叫作 __proto__
的内置属性,用于指向建立它的函数对象的原型对象 prototype。以上面的例子为例:
console.log(person.__proto__ === Person.prototype) // true
复制代码
一样的,Person.prototype 也一样有 proto 属性,它指向建立它的函数对象(Object)的prototype
console.log(Person.prototype === Object.prototype) // true
复制代码
继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null
console.log(Object.prototype.__proto__) // null
复制代码
咱们把这个有 __proto__
串起来的直到 Object.prototype.__proto__
为null的链叫作原型链。
person.__proto__ ==> Person.prototype.__proto__ ==> Object.prototype.__proto__ ==> null
读过zepto的源码都了解到$实际上是一个函数,同时在 $ 身上又挂了不少属性和方法。
如下代码:
<p id="p1">段落1</p>
<p id="p2">段落2</p>
<p id="p3">段落3</p>
<script type="text/javascript" src="js/zepto-1.1.6.js"></script>
复制代码
$('p')
返回的是类数组的同样东西。
咱们先一步步来分析一下它到底是不是数组:
var arr = [1,2,3];
var $p = $('p');
// 对比1
arr.__proto__.constructor === Array; // true
$p.__proto__.constructor === Array; // false
// 对比2
arr instanceof Array; // true
$p instanceof Array; // false
复制代码
从原型指向中,能够看出$p真的只是相似数组同样的数组。而数组是没有addClass
,removeClass
等等的属性。
咱们能够看console中,运行console.log($p.__proto__)
,就能够看$p
可调用的方法(这也是平时在使用zepto时,忘记api方法名时,能够即时查出来)
同理,咱们查看数组下面的方法console.log(arr.__proto__)
能够看到在arr
中是没有addClass
,removeClass
等等的属性的。
那咱们也为arr
建立一个addClass
方法试试:
var arr = [1,2,3]
arr.__proto__ = {
addClass: function () {
console.log(123);
}
};
arr.addClass(); // 123
复制代码
此时咱们再去拿arr来作第一次的那几个验证,获得的结果就和以前的$p同样了,即arr此时也称了一个不是数组的数组
这样就能够成功建立了addClass
方法,而这个解析器的操做是:
[1,2,3]
addClass
运行arr.addClass()
时:
这里只是浅析zepto的基本设计,也是了解zepto设计原理的开始,想要更深刻理解zepto,请移步zepto