先引入问题:
1、如何准确判断一个变量是数组类型,用typeof,或者instanceof
var a = [1,2,3];
a instanceof Array;// true
typeof a // object, typeof是无法判断是否为数组的,只能区分object和function
2、写一个原型链继承的例子
例子1,比较low:
function Animal(){
this.eat = function(){
console.log('eat');
}
}
function Dog(){
this.sleep = function(){
console.log('sleep');
}
}
Dog.prototype = new Animal();// 相当于把Dog.prototype.__proto__指向了Animal.prototype
var littleDog = new Dog();
例子2,好多了:
function Element(id){
this.elem = document.getElementById(id);
}
// 模拟封装下JQ的html()方法:
Element.prototype.html = function(val){
var elem = this.elem;
if(val){
elen.innerHTML = val;
return this; // 为啥return this呢?是为了链式操作,this返回给下一个调用者
// 链式调用就是这样:html().on().html()
}else{
return elem.innerHTML
}
}
// 监听一下
Element.prototype.on = function(type, fn){
var elem = this.elem;
elem.addEventListener(type, fn);
return this; // 还是为了链式调用
}
var e = new Element("demo-div");
e.html("<p>hi</p>").on('click', function(){
console.log('clicked');
}).on('touchstart', function(){
console.log('touched');
})
3、描述new一个对象到的过程
- 创建一个新对象
- this指向这个新对象
- 执行代码,即对this赋值
- 返回this
4、zepto源码中如何使用原型链
构造函数
构造函数一般都是大写字母开头
new的过程:1.先创建一个this对象,2.对this.相关属性赋值,3.return this
function Foo(name, age){
this.name = name
this.age = age
this.class = 'class-1'
// return this // 默认有这一行
}
var f = new Foo('zhangsan', 20);
- 每个函数都有返回值,如果使用了return语句,则返回return后跟的值,如果没有使用return,则默认返回undefined.
- 特别的,如果这个函数是构造函数,则默认返回this对象,如果构造函数内使用了return语句,并且return后跟的是一个对象,则这个构造函数返回的是这个对象,否则返回this.
// p.name 是jack
var fun = function(){
this.name = 'peter';
return {
name: 'jack'
};
}
var p = new fun();
// p.name是peter
var fun = function(){
this.name = 'peter';
return 'jack';
}
var p = new fun();
构造函数-扩展
- 所有的引用类型都有构造函数
- var a = {}其实是var a = new Object()的语法糖
- var a = []其实是var a = new Array()的语法糖
- function Foo(){} 其实是 var Foo = new Function()
- 使用instanceof判断一个函数是否是一个变量的构造函数
原型规则和示例 - 原型规则是学习原型链的基础
- 5个规则:
1.所有的引用类型(数组、对象、函数),都具有对象特性,即可以自由扩展属性(null除外)
2.所有的引用类型(数组、对象、函数),都有一个__proto__属性(__proto__也叫隐式原型),属性值是一个普通的对象
3.所有的函数,都有一个prototype属性(prototype也叫显示原型),属性值也是一个普通的对象
4.所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值。
var a = [1,2,3];
console.log(a.__proto__ === Array.prototype); // true
// 说明:
// var a = [1,2,3]; 和var a = new Array(1,2,3)一样
// Array是js的内置函数,引用类型变量的__proto__指向构造函数的prototype,所以两者相等
5.当试图得到一个对象(引用类型)的属性时,如果这个对象没有这个属性,那么就会去它的__proto__(即它的构造函数的prototype)中寻找。
补充知识点:
1.变量被实例化后,构造函数的this和变量隐式原型中的this,都是指向被实例化的变量。
2.hasOwnProperty可以判断属性是否是对象的赋值属性(即是是否来自原型的属性),即通过=的方式赋值,而不是通过prototype赋值
// 变量被实例化后,构造函数的this和变量隐式原型中的this,都是指向被实例化的变量。
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.printMyName = function(){
console.log(this.name);
}
var tom = new Person("tom", 20);
tom.printMyAge = function(){
console.log(this.age);
}
tom.printMyName(); // tom,没有printMyName这个属性,就往构造函数的显性原型中查找
tom.printMyAge(); // 20
// hasOwnProperty可以判断属性是否是对象的赋值属性,即通过=的方式赋值,而不是通过prototype赋值
// 针对上述方法做示例
var prop
for(prop in tom){
// 高级浏览器已经在for in中屏蔽了来自原型的属性
// 但是浏览器兼容性保险起见,还是加上hasOwnProperty判断是否具备某个属性
if(tom.hasOwnProperty(prop)){
// 如果不是来自原型的属性,就打印出来
console.log(prop)
}
}
原型链
引用类型(对象)如果找不到某个属性或者方法,那么就会去它的__proto__中寻找,即从构造函数的prototype中寻找。如果构造函数中没有,就会从构造函数prototype的__proto__去查找,示例:
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.printMyName = function(){
console.log(this.name);
}
var tom = new Person("tom", 20);
tom.printMyAge = function(){
console.log(this.age);
}
tom.printMyName(); // tom,没有printMyName这个属性,就往构造函数的显性原型中查找
tom.printMyAge(); // 20
tom.toString(); // 最终会找到js内置函数Object.toStirng()
// 讲解:
// 第一步:程序发现tom实例中没有toString,那么就会查找tom的__proto__,即Person的prototype
// 第二步:发现Person的prototype也没有,那就去Person.prototype的__proto__去查找,即Object的prototype(Person的prototype也是对象,是Object的实例)
// 第三步:发现Object的prototype中有toString(),那就调用了
// 附加说明:如果Object的prototype中也没有这个属性,就会从Object.prototype对象的__proto__中查找,而js为了防止死循环,把Object.prototype的__proto__指向了null
// 所以:
console.log(tom.__proto__); // 有值,打印的是Person的构造函数
console.log(tom.__proto__.__proto__); // 有值,打印的Object的构造函数
console.log(tom.__proto__.__proto__.__proto__); // null,打印的是Object.prototype对象的__proto__,指向的是null
instanceof 非常重要
instanceof是用于判断引用类型属于哪个构造函数的方法
例如上一段代码的示例:tom instanceof Person // TRUE
判断逻辑是:tom的__proto__一层一层往上,能否对应到Person.prototype
同理 tom instanceof Object // TRUE