一切都是对象
当然,也不是所有的都是对象,值类型就不是对象。
typeof用来判断类型:
function show(x) {
console.log(typeof x); // undefined
console.log(typeof 10); // number
console.log(typeof 'abc'); // string
console.log(typeof true); // boolean
console.log(typeof function () { }); // function
console.log(typeof [1, 'a', true]); // object
console.log(typeof { a: 10, b: 20 }); // object
console.log(typeof null); // object
console.log(typeof new Number(10)); // object
}
show();
undefined、number、string、boolean 是值类型,不是对象。
函数、数组、对象、null、new Number(10) 是引用类型,都是对象。
typeof判断对象,不能区分 Object、Array、Null,都会显示object(除了函数)
判断一个变量是不是对象:值类型的判断用 typeof,引用类型的类型判断用 instanceof。
var fn = function () {};
console.log(fn instanceof Object); // true
对象都是通过函数创建的
对象都是通过函数创建的 , 有些人可能反驳,因为:
var obj = { a: 10, b: 20 };
var arr = [5, 'x', true];
这个是一种“快捷方式”,在编程语言中叫做“语法糖”。
以上代码的本质是:
// var obj = { a: 10, b: 20 };
// var arr = [5, 'x', true];
var obj = new Object();
obj.a = 10;
obj.b = 20;
var arr = new Array();
arr[0] = 5;
arr[1] = 'x';
arr[2] = true;
而其中的 Object 和 Array 都是函数:
console.log(typeof (Object)); // function
console.log(typeof (Array)); // function
所以说 — 对象都是通过函数来创建的。
插一句-创建对象有几种方法
1.创建Object实例,再添加属性和方法
var person = new Object()
person.name = 'tom'
2.使用对象字面量模式
var person = {
name:'tom'
}
3.使用构造函数
function Person(name,age){
this.name = name
this.age = age
}
var person1 = new Person('tom',21)
4.Object.create
Object.create(proto,[propertiesObject])
参数 proto 表示新创建对象的原型对象,必填。
var a = { rep: 'apple' }
var b = Object.create(a)
console.log(b) // {}
console.log(b.__proto__) // {rep: "apple"}
console.log(b.rep) // apple
prototype原型
函数也是一种对象,也是属性的集合,可以对函数进行自定义属性。
每个函数都有一个属性叫做 prototype,prototype 的属性值是一个对象(属性的集合,再次强调!),默认的只有一个叫做 constructor 的属性,指向这个函数本身。
prototype 原型既然作为对象,属性的集合,不可能就只有 constructor,肯定可以自定义的增加许多属性。例如 Object 的 prototype 就有好几个其他属性。
可以在自定义方法的 prototype 中新增自己的属性
function Fn() {}
Fn.prototype.name = '王福朋';
Fn.prototype.getYear = function () {
return 1988;
};
__proto__隐式原型
之前说 每个函数 function 都有一个 prototype 属性,即原型。
而 每个对象都有一个 proto 属性,即隐式原型,指向 创建该对象的函数 的 prototype。
obj 对象是被 Object 函数创建的,因此 obj.proto === Object.prototype。我们可以用一个图来表示。
Object.prototype 是一个特例,它的 proto 指向的是 null
函数也是一种对象,也是被创建出来的。谁创建了函数呢?Function 注意这个大写的“F”。
以上代码中,第一种方式是比较传统的函数创建方式,第二种是用new Functoin创建。
不推荐用第二种方式,只是演示函数是被 Function 创建的。
就会出现:
Foo.proto === Function.prototype
Object.proto === Function.prototype
Function.proto === Function.prototype
Function.prototype 也是对象,它的 proto 指向 Object.prototype
即:Function.prototype._proto === Object.prototype
原型链
简单总结
1、prototype:函数都有这个属性,指向原型对象****
2、constructor: 原型对象默认获得这个属性,指向构造函数
3、proto: 对象( null 除外)都有这个属性 ,指向构造函数的原型对象
tips : 函数也是一个对象,也有 proto 属性
原型链完整图:
Object是所有对象的爸爸,所有对象都可以通过__proto__找到它Function是所有函数的爸爸,所有函数都可以通过__proto__找到它Function.prototype和Object.prototype是两个特殊的对象,他们由引擎来创建- 除了以上两个特殊对象,其他对象都是通过构造器
new出来的 - 函数的
prototype是一个对象,也就是原型 - 对象的
__proto__属性指向原型,__proto__将对象和原型连接起来组成了原型链
instanceof 原理
用 instanceof 来判断引用类型变量,判断规则就是根据原型链:
A instanceof B:沿着 A 的 proto 这条线来找,同时沿着 B 的 prototype 这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回 true。如果找到终点还未重合,则返回 false。
按照以上规则,“ f1 instanceof Object ”返回的是 true
可以解释很多比较怪异的现象:
手写 instanceof
function instance_of(L, R) { // L 表示左表达式,R 表示右表达式
var O = R.prototype; // 取 R 的显示原型
L = L.__proto__; // 取 L 的隐式原型
while (true) {
if (L === null)
return false;
if (O === L) // 这里重点:当 O 严格等于 L 时,返回 true
return true;
L = L.__proto__;
}
}
测试
1、person1.proto 是什么?
2、Person.proto 是什么?
3、Person.prototype.proto 是什么?
4、Object.proto 是什么?
5、Object.prototype.proto 是什么?
答案:
第一题:
因为 person1.proto === person1 的构造函数.prototype
所以 person1.proto === Person.prototype
第二题:
因为 Person.proto === Person 的构造函数.prototype
所以 Person.proto === Function.prototype
第三题:
Person.prototype 是一个普通对象,我们无需关注它有哪些属性,只要记住它是一个普通对象。
因为一个普通对象的构造函数是 Object
所以 Person.prototype.proto === Object.prototype
第四题,参照第二题,因为 Person 和 Object 一样都是构造函数
Object.proto === Function.prototype
第五题:
Object.prototype 对象也有 proto 属性,但它比较特殊,为 null 。因为 null 处于原型链的顶端,这个只能记住。Object.prototype.proto === null
继承
javascript 中的继承是通过原型链来体现的。先看几句代码
访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着 proto 这条链向上找,这就是原型链。
访问 f1.b 时,f1 的基本属性中没有 b,于是沿着 proto 找到了 Foo.prototype.b。
如何区分一个属性到底是自己的还是从原型中找到的呢?使用 hasOwnProperty,特别是在 for…in… 循环中。
f1 的这个 hasOwnProperty 方法是从哪里来的? f1本身没有,Foo.prototype 中也没有
它是从 Object.prototype 中来的
对象的原型链是沿着 proto 这条线走的,因此在查找 f1.hasOwnProperty 属性时,就会顺着原型链一直查找到 Object.prototype。
由于所有的对象的原型链都会找到 Object.prototype,因此所有的对象都会有 Object.prototype 的方法。这就是所谓的“继承”。
说一个函数的例子吧。
我们都知道每个函数都有 call,apply方法,都有 length,arguments,caller 等属性。为什么每个函数都有?这肯定是“继承”的。函数由 Function 函数创建,因此继承的 Function.prototype 中的方法。不信可以请微软的 Visual Studio 老师给我们验证一下:
那怎么还有 hasOwnProperty 呢?—— 那是 Function.prototype 继承自 Object.prototype 的方法。