前端笔记—从入门到坟墓[js][new 与object.create()原理][4]
前端笔记—从入门到坟墓[js][原型链解读][3]
前端笔记—从入门到坟墓[js][闭包][2]
前端笔记—从入门到坟墓[js][作用域与上下文][1]
原型链结构图(重点)
仔细观察图会发现,有几个出现频率比较高的词:
__proto__ : 指向该对象的隐式原型对象,即[[prototype]],通常也就是所谓的该对象原型链的起点
prototype :指向该对象的显式原型对象(只有函数拥有)
constructer:指向该对象的构造器(这个属性属于一个函数的显式原型对象的属性,用于指向该函数,就是在指回去)
关系归纳
由上图可知很多信息,需要仔细观察上图。
普通对象
var foo={};//字面量方式定义对象
foo.__proto__===Object.prototype;//true
注:字面量方式定义对象,其隐式原型指向Object的显式原型,所以foo可以直接调用Object.prototype下的任意方法
函数对象
function foo2(){};
foo2.prototype.c = '1'
foo2.__proto__===Function.prototype;//ture
foo2.__proto__.__proto__===Object.prototype;//ture
foo2类似于图中Person对象的位置,它是Function的实例。所以其隐式原型指向Function的显示原型。
实例对象
//实例对象
var foo3 = new foo2()
foo3.__proto__ === foo2.prototype //ture
foo3.__proto__.__proto__===Object.prototype //ture
foo3 类似于图中per对象的位置,它是Person的实例。
Object
Object().__proto__ === Object.prototype
//turn 注: Object()返回普通对象obj,类似于刚刚的第一种情况
Object.__proto__ === Function.prototype
//turn 注: Object是Function一个实例
Function
Function().__proto__=== Function.prototype
//turn 注: Function()返回函数对象,类似于刚刚的第二种情况
Function.__proto__ === Function.prototype
//turn 注: Function有隐式原型,只不过Function的显式原型等于隐式原型。
Array
Array().__proto__ === Array.prototype//turn
Array().__proto__.__proto__=== Object.prototype//turn
Array.__proto__ === Function.prototype//turn
Array在图中没有出现,但是它的位置类似于图中Person对象的位置,它的隐式原型指向Function.prototype,其实例对象([]或new Array或Array())的隐式原型指向Array的显式原型。
Math
Math.__proto__ === Object.prototype//turn
总结
console.dir(Function.__proto__)//Function
console.dir(Object.__proto__)//Function
console.dir(String.__proto__)//Function
console.dir(Array.__proto__)//Function
console.dir(Number.__proto__)//Function
console.dir(Date.__proto__)//Function
console.dir(Math.__proto__)//Object
常用api
for in
遍历所有可枚举属性(包含原型链的属性)
var F = function(){
this.a = '1'
}
F.prototype.b = '2'
var f = new F()
f.c = '3'
for(var i in f){
console.log(f[i])//1,3,2,
//涉及到原型链的问题,顺序是:132,因为最先查找自身属性(a,c),再去查找原型链属性(b)
}
hasOwnProperty()
检测一个对象是否含有特定的自身属性(原型链上的不算)
var F = function(){
this.a = '1'
}
F.prototype.b = '2'
var f = new F()
f.c = '3'
for(var i in f){
if(f.hasOwnProperty(i)){
console.log(f[i])//1,3
}
}
isPrototypeOf()
一个对象是否在另一个对象的原型链上
function Parent(){}
Object.prototype.isPrototypeOf(Parent)//true
instanceof
一个对象的原型链上是否有另一个对象的显示原型(.prototype)
也可以说:一个对象是否是另一个对象的实例
console.log(Parent instanceof Object) //true
Object.getPrototypeOf()
返回[[Prototype]]指定对象的原型
console.dir(Object.getPrototypeOf(Parent))//Object.prototype
console.dir(Parent.__proto__)//效果同上
Object.setPrototypeOf()
设置[[Prototype]]指定对象的原型
Object.getPrototypeOf(Parent,Object.prototype)//等于Parent.__proto__ = Object.prototype
判断变量类型
判断:对象,数组,函数,布尔,字符串,数字等常用类型。
介绍几个常用判断方法
//判断变量类型
///测试用例
var a = {a:1}
var b = 1
var c = '1'
var d = true
var e = false
var f = null
var g = undefined
var h = function(){}
var i = [1,2]
console.log('判断一个变量就是一个对象')
function isObj(item){
return {}.toString.call(item) == '[object Object]'
}
function isObj2(item){
return (item instanceof Object&&
!(item instanceof Array)&&
!(item instanceof Function))
}
function isObj3(item){ //注:typeof null == ‘object’
return (typeof item == 'object'&&!Array.isArray(item)&&item!=null)
}
console.log('判断一个变量就是一个数组')
function isArr(arr){
return Array.isArray(arr)
}
function isArr2(arr){
return arr instanceof Array
}
function isArr3(arr){
return Array.prototype.isPrototypeOf(arr)
}
console.log('判断一个变量就是一个函数')
function isFn(fn){
return {}.toString.call(fn) == '[object Function]'
}
function isFn2(fn){
return fn instanceof Function
}
function isFn3(fn){
return Function.prototype.isPrototypeOf(fn)
}
function isFn4(fn){
return typeof fn == 'function'
}
console.log('判断一个变量就是一个数字')
function isNum(item){
return typeof item == 'number'
}
console.log('判断一个变量就是一个字符串')
function isStr(str){
return typeof str == 'string'
}
补充:判断两个对象是否相等(不是引用相等)
function isObjectValueEqual(a, b) {
console.dir(Object)
var aProps = Object.getOwnPropertyNames(a);
//返回所有自身的属性名(包括可枚举属性,不包括Symbol类型属性,原型链的属性)组成的数组
var bProps = Object.getOwnPropertyNames(b);
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
if (a[propName] !== b[propName]) {
return false;
}
}
return true;
}
Array()与[]、new Array
不同点
Array()和[]和new Array返回结果相同,具体不同在于底层构造上面,可以点开下面连接学习
[]或new Array或Array()区别
//在我们比较相同时这样是不行的
console.log(Array() === [])//false 由于[]和Array()都是对象的范畴,所以指针不同,但本质相同
//需要这样比较
console.log(
Object.prototype.toString.call(Array()),//[object Array]
Object.prototype.toString.call([]),//[object Array]
Object.prototype.toString.call(new Array),//[object Array]
Object.prototype.toString.call(Array))//[object Function] 是一个构造函数,所以是Function
与Array比较,String、Number有哪些不同
与Array()比较,String()和Number()返回值略有不同,Array()返回数组属于对象的范畴,而String()、Number()返回的则是字符串和数字类型。
1,String()和Number()返回值存在栈中
我们知道变量当中可以分为基本类型和引用类型。
基本类型:存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。5种基本数据类型有Undefined、Null、Boolean、Number 和 String,它们是直接按值存放的,所以可以直接访问。
引用类型:存放在堆内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。每个空间大小不一样,要根据情况开进行特定的分配。
当我们需要访问引用类型(如对象,数组,函数等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。
console.log(Array() === [])//false
console.log(String() === '')//true
console.log(Number() === 0)//true
不过注意一点是new String()和new Number()都是对象,是引用类型。
2,String()和Number()使用instanceof 与 isPrototypeOf()无法判断原型链
//instanceof
console.log(Object() instanceof Object)//true
console.log(Array() instanceof Array)//true
console.log(String() instanceof String)//false
console.log(Number() instanceof Number)//false
//isPrototypeOf一个对象是否在另一个对象的原型链上
console.log(Array.prototype.isPrototypeOf([]))//true
console.log(String.prototype.isPrototypeOf(''))//false
console.log(Number.prototype.isPrototypeOf(0))//false
因为instanceof和isPrototypeOf都是用于对象,但是实例后的String和Number已经不属于对象了,所以不能使用。
但是,String()和‘’ 的确可以使用 String.prototype 的方法,说明 String.prototype 在其元素链上。
console.log(Object.getPrototypeOf(String())) // String
console.log(String.prototype) // String
console.log(String.prototype === ''.__proto__)
//true 证明 ‘’或者String()的原型是String.prototype