javascript之js原型-原型链总结

学习参考: MDN

前言:

先前Niao(说的就是我啦)一直从事着js学习研究,当时我是跟着廖老师的es系列教程走的。打算在毕业前搞个小东东,迫于时间问题。教程仅仅过了个大概。之前买的js进阶书籍就一直凉着。为了完全吃透js。niao也是下定决心,未来的一段时间,一直会更新js的进阶学习总结。

函数创建

先说明:js中一切皆对象,就连函数也不列外,不要看函数怎么跟一般的对象不一样呢,其实这是js中特殊对象。其实函数也有对象的方法和属性,比如

	//声明一个函数foo
	funciton foo()
   {
   	console.log(1314520)
   }
   //调用foo
   foo()//1314520没毛病
   //接下来才是重点,调用protoype
   foo.prototype//-->指向原型对象

可以确定函数也是对象,也有对象该有的属性方法了。回到开始,函数创建过程,申明一个函数,接下来js引擎会调用构造函数Funciton创建该函数。所以foo.constructor === Funciton(foo.constructor函数本身没有这个属性),所用函数的constructor均指向Function。接下来js引擎还会在内存中创建该函数原型对象,这个是默认的。该对象,通过prototype来引用。

对象创建

** 对象创建几种方式**

  • 字面量方式:
    举个栗子:
    let obj = {}//这里obj是变量,{}就是字面量
    这种方式同样是被
  • new调用构造函数创建

new调用构造创建对象所起作用,这里说明一下,

1.首相会创建一个实列对象
2.然后把实列对象的__proto__指向构造函数的原型对象
3.然后改变构造函数内的this指向。
4.最后返回该对象

这里写个封装new函数,实现底层

function New(func){    
    let obj = {};   //这里就直接新建一个空对象,用于返回的新对象。
    if(func.prototype != null){
        obj.__proto__ = func.prototype;
    }
    //改变this指向
    func.apply(obj,Array.prototype.slice.call(arguments, 1));
    //把func构造函数里的this 指向obj对象,把传进来的第二个参数开始,放入func构造函数里执行,比如:属性赋值。
   //需要属性赋值的构造函数,如function foo(a1,a2,....)
    return obj;
}
  • Object.create(obj,[options])该方法是ES5新增方法。该方法会新创建一个对象,它会把传入函数或对象关联到新建对象的__proto__。

create实现底层,这里介绍几个方法:

function create (obj,[options])//options:传入对象,外部对象里面是各个属性的属性描述符(数据描述符)
{
	 let obj = {};
	 
	obj.__proto__ = obj
	if (options === null){
		return obj;
	}
	return Object.defineProperties(obj,options)//如果需要添加需要属性,可以传入值
}

2.兼容性写法,因为__proto__为非标准属性,仅兼容市面上大多数主流浏览器,FF,chrome,… 。像IE这种古董,怕是得折腾人了,这里就不作测试- _ - 。

function create (obj)
 {
	function f () {};//这里得f做过度用,是个中间量。用于临时存储新对象__proto__ ==> obj
	f.prototype = obj
	return new f()
}

上面这个方法,实现的效果和方法一相同。但不理解new底层的,理解起来还是有点突兀的。这个可以结合上面我讲的new的作用,以及new函数封装。
这里我在变换一下写法:

function create(proto){
    let f = function(){};
    let obj = {};
    
    f.prototype = proto;
    obj.__proto__ = f.prototype;
    return obj;
}

测试上面的方法:
在这里插入图片描述
在这里插入图片描述
这下没得问题了巴 ??

原型链

原型链,这里我用图表示:
Alt
说明: 理解此图内容,可以结合下面原型指向内容

说起原型链不得不说两个重要属性:
protitype,proto.他们是访问原型入口。区分如下:

prototype:函数独有,其他实列对象不能访问得到
proto:所有对象都有该属性,即函数也能访问。

注意 : __prototype并不是一个标准属性,仅得到主流浏览器支持。标准属性为[[prototype]]

proto

上面属性就是访问原型的属性,为非标准属性,标准属性[[prototype]],隐藏属性,访问不到。

protoype

函数特有属性,用于访问函数原型对象。对象就两种,普通对象(字面量和new),原型对象。
区别:
每个对象都有原型,通过__proto__访问,对象内有实列继承成员,而prototype为函数的原型对象,上面定义了他的实列继承的相关。可以自定义属性方法,供原型链下游继承。

原型。什么是原型呢?
js是基于原型语言,而每一个对象,都有模板(原型对象),用于对象的属性和方法继承。而原型对象对象也有原型,最终指向Object.prototype.proto = null. 层层继承,就形成一条完整的链,原型链,而所说的原型就是原型对象。

下面看一个实列,理解原型以及原型链的运行原理,内涵

创建函数
funciton foo () {}
//在函数原型上添加属性
foo.prototype.name = 18
console.log(foo.prototype)

结果:

{

foo: “bar”,

constructor: ƒ doSomething(),
proto: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}

在是通过函数foo,new一个实列化对象

let obj = new foo()
//添加属性
obj.age = 110
console.log(obj)

结果:

{

age: 110,
proto: {
name: 18,
constructor: ƒ doSomething(),
proto: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
}

这里通过对象属性访问,同样可以访问到obj.__proto__上的name.提示:obj.proto === foo.prototype.基于原型,对象obj从函数原型上继承了属性name.这就是原型的使用。
原型链的访问过程分析:
对于属性name访问,浏览器首相查找obj对象内是否有此属性,如果没有。继续溯源原型链。在obj.proto(foo.prototype)查找,查找到输出;否则,继续像上层原型排查,proto__的__proto,这时的原型对象指向Object.prototype.因函数默认的prototype的__proto__指向Object.prototype,在此原型上查找该属性,如果不存在。继续溯源原型链,即obj.proto__的__proto__的__proto.然而是不存在的,因为Object.prototype.proto = null.此时原型链已经遍历完。该属性被复制为undefined

注意:实列对象和原型对象对原型的访问,只能通过__proto__,必须重申。原型链中的方法和属性没有被复制到其他对象——它们被访问需要通过前面所说的“原型链”的方式。

对象继承的属性,都被存放在原型,prototype内(称之为子命名空间)

原型指向

说完原型及原型链,再来总结具体原型的指向,总的如下:
范对象,还有js的特殊对象,函数。这里我分开总结,有函数搅和,整的太乱了。
1.函数的prototype指向原型对象,该对象由此函数构造(new)。该对象的__proto__指向Object.prototype;函数__proto__指向原型Function.prototype。应为函数也是对象,故也有constructor对应Function函数的构造,原型__proto__的__proto__指向Object.prototype

2.范对象(实列对象):
实列prototype===>构造的.prototype,非实列的成员均继承该构造的原型(当然该构造的prototype != null),那么该构造的__proto__ ===>Object.prototype

还有一点需要说明:对于Object.create创建的新对象的__proto__指向给定的实列。
这点可以参考上面new以及create的封装。??

Constructor

每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数。对于函数来所,函数的原型对象prototype以及constructor两个属性紧密联系。此属性是原型对象特有,因此应用此构造需要遍历原型链。此又可作为原型链理解的案列。

此属性的运用:

代码:

function Person(name,age,interests) {
	this.name = name;
	this.age = age;
	this.interests = interests
}

let person1 = new Person('keke','18',['girls','swiming'])

//使用constructor,应用Person. 这里constructor继承自。Person,因此可以直接调用,而不用加.prototype
let person2 = person1.constructor('tom','8',['fish','pair'])

//访问新对象属性
console.log(person2.name)//tom 

原型链运用

1.属性查找(而部分有讲)
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
2.对象继承

function Person(name){   //父类(构造函数)
    this.name = name;
}
Person.prototype.getName = function(){   //在父类的原型对象上添加方法
    return this.name;
}

function Son(name,age){    //子类(构造函数)
    this.name =  Person.call(this, name);
    this.age = age;
}

Son.prototype = new Person();    //把子类(构造函数) 的原型对象  挂到 原型链上去。

Son.prototype.getAge = function(){
    return this.age;
}
var s = new Son("zdx",666);
s.getName();    //Son.prototype 上没有 getName方法,现在能使用了,就完成了 继承。
son.prototype = new Person('')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值