js原型

  1. 传统的构造方法定义方式会影响性能,容易造成多个对象有多个方法副本,应该将方法单独抽取出来,让所有的对象共享该方法
  2. 可以考虑将方法全部放到外面但是有安全隐患
    在开发中会引入各种框架或库,自定义的成员越多,出现命名冲突的几率越大
    可能开发中会有多个构造函数,每一个构造函数会有多个构造方法,那么就会变得不容易维护
  3. 任意的对象都会默认链接到他的原型中
    创建一个函数,会附带的创建一个特殊的对象,该对象使用 函数.protoType 引用,称其为函数的原型属性
    每一个由该函数作为构造函数创建的对象,都会默认的连接到该特殊的对象

传统构造函数的问题

function Foo(){
	this.say = function(){
	}
}

1、由于对象是调用 new Foo() 所创建出来的,因此每一个对象在创建的时候,函数的 sayHello 都会被创建一次
2、那么每个对象都含有一个独立、不同、功能相同的sayHello 方法
3、在代码中方法就会消耗性能,最典型的资源就是内存
4、这里最好的办法就是将函数体放在构造函数之外,那么在构造函数中只需要引入该函数即可

function sayHello(){}
function Foo(){
	this.say = sayHello();
}

5、会在开发中变得困难:引入框架危险、代码繁冗不好维护。解决的办法就是外面的函数不占用名字
6、每一个函数在定义的时候,有一个神秘对象创建出来
7、每一个由构造函数创建的对象都会默认的连接到该神秘对象上

var f1 = Foo();
var f2 = Foo();
f1.sayHello();//如果f1中没有sayHello方法,就会到Foo.protoType中去找
f2.sayGoodbye();//如果f2中没有sayHello方法,就会到Foo.protoType中去找

8、由相同构造函数创建出来的对象共享一个对象,就是
构造函数.protoType
9、只需要将共享的东西、重复会多占用内存的东西放到
构造函数.protoType 中,那么多由相同构造函数所创建的对象就可以共享

function Foo(){}
Foo.prototype.sayHello = function(){
	console.log( ... );
};
var f1 = new Foo();
var f2 = new Foo();
f1.sayHello();
f2.sayHello();
f1.sayHello === f2.sayHello;

常见错误

1、赋值的错误

function Person(){}
Person.prototype.name = '张三';
var p1 = new Person();
var p2 = new Person();
p2.name = '李四';
console.log( p1.name );
console.log( p2.name );
//如果是访问数据,当前对象如果没有该数据就到构造函数的原型属性中去找
//如果是写数据,当对象中有该数据的时候就是修改值;如果对象中没有该数据,那就是添加值

原型相关概念

1、关于面向对象的概念
①类class: 在js 中就是构造函数
在传统的面向对象语言中,使用一个叫做类的东西定义模板,然后使用模板创建对象
在构造方法中也具有类似的功能,因此称其为类

②实例(instance)与对象(object)
实例一般是指某一个构造函数创建出来的对象,我们称之为某某构造函数的实例
实例就是对象,对象是一个泛称
实例和对象是近义词

③键值对与属性和方法
在js 中键值对的集合称为对象
如果值为数据(非函数),就称该键值对为属性property
如果值为函数(方法),就称该键值对为方method

④父类与子类
传统的面向对象语言中使用类来实现继承,那么就有父类、子类的概念
父类又称为基类,子类又称为派生类
在js 中,常常称为父对象、子对象、基对象和派生对象

2、原型相关概念:
①**"神秘对象"针对构造函数称为原型属性prototype**
"神秘对象"就是构造函数的原型属性 简称原型

②"神秘对象"与构造函数创建出来的对象也有一定的关系(如果是访问数据,当前对象如果没有该数据就到构造函数的原型属性中去找
"神秘对象"针对构造函数所创建出来的对象称为原型对象,简称原型
构造函数的原型属性和对象的原型对象是同一个东西

③对象继承自其原型
解释1:构造函数所创建出来的对象 继承自 构造函数的原型属性
解释2:构造函数所创建出来的对象 继承自 该对象的原型对象
构造函数所创建出来的对象与构造函数的原型属性所指向的对象是两个不同的对象
继承:

  • 原型中的成员,可以直接被实例对象所使用
  • 也就是说实例对象直接"含有"原型中的成员
  • 因此 实例对象 继承自 原型
  • 这样的继承就是"原型继承"
  • js 是基于"原型继承"的面向对象语言

3、一些问题:
{} 构造函数是什么?
凡是字面量的对象都有构造函数
{} Object
[] Array
/./ RegExp
function… Function

如何使用原型

1、利用对象的动态特性
构造函数.prototype.xxx = vvv;

2、利用直接替换

Student.prototype = {
	sayHello:function() {},
	study:function() {}
}

什么是原型属性?
针对构造函数而言,构造函数的prototype所指向的对象(原型属性所表示的对象),我们称为构造函数的原型属性
什么是原型对象?
针对该创建出来的对象而言,该构造函数的原型属性所表示的对象,就是我创建出来的这个对象的原型对象

原型与继承小结

1、什么是原型?
构造函数创建出来的时候,就有一个神秘对象创建出来,它里面可以添加任何的属性和方法,构造函数创建出来的实例对象是继承自该神秘对象的(意思就是如果实例对象在调用某一个属性或方法的时候,如果实例对象里面由有,就调用实例对象的;如果没有,就调用神秘对象的)

2、如何使用原型?
原型的作用就是用来继承的,可以利用点或者是直接替换的方式添加成员

3、什么是原型继承?
实例对象会默认的连接到原型对象里去,原型对象可以是你自己提供的(用替换的方法做),第二种就是继承自默认的原型对象
一般的开发方式,属性交给构造函数,方法交给原型

4、如何实现原型继承?

  • 混合式继承方式: 利用混入的方法给原型添加成员,那么实例对象就可以继承指定的方法和属性
  • 直接替换原型对象
//例如要实现一个自定义的集合(数组)
//弄一个类型 ItcastCollection
function ItcastCollection () {}
//要提供数组的方法为其添加成员

1、{}就是Object new出来的,就是一个对象的实例
2、[]就是Array new 出来的,就是一个数组的实例
3、/./就是RegExp new出来的,就是一个正则表达式的实例

从案例12引出的问题:
1、什么时候会得到undefined
2、我们介绍的是在实例中没有,就到原型中找,如果在原型中没有,怎么办呢?

属性搜索原则

1、原型链
2、属性搜索原则

  • 所谓属性搜索原则,就是对象在访问属性和方法的时候,首先在当前对象中查找
  • 如果当前对象中存储该属性或方法,停止查找,直接使用该属性和方法
  • 如果对象没有该成员,那么在其原型对象中查找
  • 如果原型对象含有该成员,那么停止查找,直接使用
  • 如果原型中还没有,就到原型的原型中查找
  • 如此往复,直到找到Object.prototype,还没有,那么就返回 undefined
  • 如果是调用方法,就报错,该xxx不是一个函数
function Student( name, age ) {
	this.name = name;
	this,age = age;
}
Student.prototype = {
	sayHello: function() {
		console.log( 'hello' );
	}
};
var p = new Student( '张三', 19 );
p.sayHello();

代码分析:
1、首先预解析的过程,声明构造函数Student,同时创建神秘对象 Student.prototype
2、第一句话执行Student.prototype,重新覆盖原型对象,原来的默认原型对象已不再被指向
3、new 创建对象,然后将对象的引用交给构造函数的this
4、在构造函数的内部,利用对象的动态特性,给刚刚创建出来的对象提供属性:name 和 age

  • 构造函数在调用的时候传入参数 ‘张三’ 和 19
  • 因此对象的属性 name 为 ‘张三’ ,age 为 19
  • 对象初始化完成之后,返回变量的 ‘地址’ 给变量p

5、执行调用方法 p调用 sayHello 方法

  • 首先在p指向的对象中查看,没有 sayHello 方法
  • 然后在其原型对象,Student.prototype中查找(是新的原型对象)
  • 在新的原型对象中有 sayHello,因此调用它
  • 在该方法中打印 ‘hello’
  • 方法调用结束,程序结束

对象的原型链

1、凡是对象就有原型
2、原型也是对象
凡是对象就有原型,那么原型又是对象,因此凡是给定一个对象,那么就可以找到他的原型,原型还有原型,那么如此下去,就构成一个对象的序列,称该结构为原型链。

问题:
1、原型链到底到什么时候是一个头?
2、一个默认的原型链结构是怎样的
3、原型链结构对已知语法的修正

原型链的结构

凡是使用构造函数,创建对象,并且没有利用赋值的方式修改原型,就说该对象保留默认的原型链。

默认原型链结构是什么样子呢?

function Person() {}
var p = new Person();
//p具有默认的原型链

默认的原型链结构就是:
当前对象 ==>> 构造函数.prototype ==> Object.prototype ==>null

在实现继承的时候,有时会利用替换原型链结构的方式实现原型继承,那么原型链结构就会发生改变

function ItcastCollection () {}
ItcastCollection.prototype = [];
var arr = new ItcastCollection();
//arr => [] => Array.prototype => Object.prototype => null

什么是原型式继承

通过修改原型链结构(增加一个节点、删除一个节点、修改节点中的成员)使得我们的实例可以使用这条链中的所有方法

绘制对象的原型链结构

说明:函数中也有‘proto’属性,暂时不考虑函数的该属性

function () {}
var p = new Person();

在js中,所有的对象字面量在解析以后,就是一个具体的对象了,那么可以理解为调用的对应构造方法
1、例如在代码中写上{},就相当于’new Object()’
2、例如代码中有{},就相当于‘new Array()’
3、例如代码中有’/./’,就相当于’new RegExp( ‘.’ )’
注意:在底层理论执行的过程中,是否有调用构造函数(不易一定,和浏览器的版本有关)
在原型链中绘制 Object.prototype 对应的构造函数

绘制原型链结构

var o = {
	appendTo: function ( dom ) {
	}
};
function DivTag() {}
DivTag.prototype = o;
var div = new DivTag();

div => o => Object.prototype =>null

函数的构造函数Function

在js中使用 Function 可以实例化函数对象,也就是说在js 中函数与普通对象一样,也是一个对象类型,函数是js中的一等公民
1、函数是对象,就可以使用对象的动态特性
2、函数是对象,就有构造函数创建函数
3、函数是函数,可以创建其他对象
4、函数是唯一可以限定变量作用域的结果

要解决的问题:
1、Function 如何使用
2、Function 与函数的关系
3、函数的原型链结构

函数是Function的实例

语法:

   new Function( arg0, arg1, arg2, arg3, ..., argN, body ); 

注意:Function()里面的参数都是字符串
该构造函数的作用,是将参数连接起来组成函数

  • 如果参数只有一个,表示函数体
  • 如果参数有多个,最后一个参数表示新函数体,前面的所有参数表示新函数的参数
  • 如果没有参数,表示创建一个空函数

创建一个打印一句话的函数

//传统的
function foo () { console.log( '你好!' ); }
//Function
var func = new Function( 'console.log( "你好!" );' );
//功能上,foo与func等价

创建一个空函数

//传统
function foo() {}
//Function
var func = new Function();

传入函数内一个数字,打印该数字

//传统
function foo( num ) { console.log( num ); }
//Function
var func = new Function( "num", "console.log( num );" );
func();

arguments 参数

arguments 是一个伪数组对象,表示在函数调用的过程中传入所有参数的集合
在函数过程中没有规定参数的个数与类型,因此函数调用就具有灵活的特性,那么为了方便使用,在每一个函数调用的过程中,函数代码体内就有一个默认的对象 arguments,它存储着实际传入的所有参数
js中函数并没有规定如何传参
1、定义函数的时候不写参数,一样可以调用时传递参数
2、定义的时候写了参数调用的时候也可以不传参
3、定义的时候写了一个参数,调用的时候可以随意的传递多个参数
在代码设计中,如果需要函数带有任意个参数的时候,一般就不带任何参数,所有的参数利用arguments来获取。
一般的函数定义语法,可以写成

function foo ( /*...*/ ) {
}

函数的原型链结构

任意的一个函数都是相当于大写的Function的实例,类似于{}与new Object() 的关系

function foo() {}
//告诉解释器,有一个对象叫foo,他是一个函数
//相当于new Function() 得到一个函数对象

1、函数应该有什么属性’ proto '(当对象来看)
2、函数的构造函数是什么?Function
3、函数应该继承自 ’ Function.prototype ’
4、‘ Function.prototype ’ 继承自 ‘Object.prototype’
(大写的Function和函数就是一个默认的作用域链,如果不使用赋值的方式去改变原型结构的时候,你用构造函数所创建出来的对象保留的是默认的原型链结构 对象=> 构造函数.prototype => Object.prototype => null)

绘制函数的原型三角形结构

1、Object是大写 Function 的实例
2、Object作为对象是继承自 Function.prototype 的,又 Function.prototype继承自Object.prototype
3、Function 是所有函数的构造函数,Function也有实例,所以Function同时也是自己的构造函数(*****)
在 js 中,任何对象的老祖宗都是Object.prototype
在 js 中,任何函数的老祖宗都是 Function.prototype

Function的使用

1、使用 Function 创建函数与原来的方式创建函数的区别?

  • Function 是使用字符串构建函数,那么就可以在程序运行过程中构建函数
  • 以前的函数必须一开始就写好,再经过预解析,一步一步的执行
  • 假定从服务器那里拿到了"[ 1, 2, 3, 4 ]"
    将数组形式的字符串,转换成数组对象
    var arr = ( new Function( ’ return ’ + str + ‘;’ ) )();

2、自调用函数

3、eval函数:把字符串变成代码

4、绘制完整的原型链结构

  • 以Person为例
  • p => Person.prototype => Object.prototype => null
  • Object构造函数 o =>Object.prototype => null
  • Person是Function的实例,继承自Function.prototype
  • Object也是Function的实例,也继承自Function.prototype
  • Function也是Function创建出来的(他是一个特例),也是继承自Function.prototype
  • Function.prototype 继承自Object.prototype => null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值