上篇中我们提到:
凡是函数就有属性prototype
由某一个函数new出来的对象会自动的链接到该函数的prototype中
连接到prototype的作用:资源共享
属性(属性和方法)没有区别
如果访问对象的属性,就在当前对象找,如果没有就在其原型对象中找
原型对象就是对象的构造函数的prototype属性
原型对象(站在new新创建的对象的角度)和原型属性(站在构造函数的角度)
__proto__是站在对象的角度讨论其原型对象
Prototype是站在构造函数的角度讨论原型属性,或构造函数创建的对象的原型对象
循环语句:for、while 、do while、for in
分支语句:if.....else.... Switch case
Break:跳出当前循环体
Continue:仅仅跳出本次循环而整个循环体继续执行
数字转换成字符串:变量名+“” ; string(变量名);变量名.tostring
字符串转换成数字:Number(变量名).ParseInt
boolean类型转换成字符串使用“”
数字或字符串转换成boolean类型:!变量名 Boolean(变量名)
判断数字是有限数字:isFinite();Infinity()无限循环
判断数字为NaN:isNaN();JS中有一个特性NaN与自己不相等
判断数字 : 最简单的办法是做数学运算 a- 0和 b*1
setTimeout多少秒后执行一次
setInterval 多少秒后执行,间隔多少秒后再次执行,直到clearInterval
都是先延时再执行
要求:给一段代码,能清楚它整个的层次结构
二.对象类型
在js 中,类型是很弱的一个概念。JavaScript是一个弱类型的编程语言
在js中 数据是有类型的,但是变量是没有类型的约束
变量一旦被赋值,通过typeof能得到变量的类型,也就是数据的类型
Typeof是一个运算符
对象的类型?Typeof操作对象,统一返回Object。特殊function返回function
console.log( typeof [] );
console.log( typeof {} );
console.log( typeof 123 );
console.log( typeof "" );
console.log( typeof true );
console.log( typeof new Date() );
console.log( typeof /123/ );
console.log( typeof function () {} ); //function
需要明确对象的类型,以便做赋值的处理
一旦确定了对象的类型,我们做封装就会特别方便
-------------------------------------------------------------------------------------------------------------------------------
在jq中$()括号中可以传递的:
$(????)
string------------>选择器 ,html
function---------> onload
DOM对象-----------> jq对象
function Person(){
}
var p = new Person(); //常常称为person对象
创建XX对象,其实描述的是构造函数方法的名字。
构造函数的名字就是 对象的类型 的名字。
圆括号是一个运算符,圆括号括起来就是表达式。
({}):Object !{}:false +{}:NaN
[]:Array
三.Constructor
每一个对象都可以访问到一个属性
其中有一个是constructor(构造器)
每一个对象的constructor属性 描述的就是其构造函数。
每一个对象都链接到其原型对象上。
对象的constructor属性是其原型对象提供的。
每一个对象都有原型对象。
四.如何获得对象的类型?也就是构造函数的名字。
1.传统的字符串处理函数:字符串方法
1.1获得对象的构造函数 var ctr = p.constructor;
1.2.将函数转换为字符串 var s = ""+ctr;
1.3.将function与 ( 之间的字符串截取出来(截取方法??)
replace:找到了返回的是新的字符串,不会改变原来的
indexOf方法:在对应的字符串里找字符串。
找到了,返回开始的索引,是一个number
找不到,返回 -1
slice截取(startIndex+2 endIndex)开始索引 结束索引
startIndex 是“|”,startIndex+1是空格,+2是名字
//replace:string <string>.replace(<string>,<string>)
//indexOf:number <string>.indexOf(<string>)
//slice:(startIndex+2 endIndex)
改良简化
1. 将重复的字符串处理合并,利用一个变量来描述
2.if 嵌套 if,代码很复杂
获得开始的索引,获得结束的索引 ,如果索引符合要求,就获得了字符串
2.利用正则表达式 用来匹配
?前面如果是正常的字符 表示0--1次
?如果是长度限定的元字符 表示尽可能少的匹配
3.函数有一个属性name,该属性表述函数的名字(IE8不支持 ,考虑兼容)
**通用的获得对象类型,处理获得函数名(写一个函数,获得函数名字)
花括号有代码缩进作用,但是用的多了会很乱,开发时能不写就不写
在IE8调试:IE8里面找到脚本 先设断点 再启动调试
火狐调试:自己装filebug ;自带的 脚本启用
·再简化,用三目运算符(技巧:条件占一行,每个值占一行;符号放后面;前后有一 点缩进。根据逻辑,代码组织,然后分层 ),三目运算符是一个表达式
·再简化,用逻辑中断,(||;&&),连接两个表达式
五.继承
面向对象的特征就是 封装性 继承性 多态性
封装性:把一些复杂的东西封装起来,只留一个简单的接口,让用户可以通过这 个接口调用。函数就是一种封装。面向对象就是把函数封装起来
继承性:拿来主义。自己没有,把别人的拿过来,让其成为自己的。
在JS中有两种继承模型
1.原型继承 2.组合继承
1.原型继承 (对象继承自其原型对象)
如果需要让某一个对象有某一个行为(属性,方法),那么可以考虑将这个行为加到原型对象中(在构造函数的原型属性里加),那么这个对象就继承自原型对象,获得了该行为。
如何使用原型对象?(3种方法,实际开发中用的多的是后2种)
1.利用对象的动态特性添加成员
var Person = function () {};
Person.prototype.sayHello = function () {
alert (‘ 哈哈哈 ‘);
};
// 此时 原型对象是对象, 可以利用动态特性随时添加成员
// 添加的成员都会被 构造函数创建的对象所继承
2.利用覆盖原型对象
Person.prototype.sayHello = function () {}
Person.prototype.sayGoodbye= function () {};
Person.prototype.sayLove = function () {};
......
// 如果需要添加的内容非常多
// var Person = function () {};
function Person() {}
Person.prototype = {
constructor: Person,
sayHello: function() {},
sayGoodbye: function() {},
sayLove: function () {}
};
// 这里由 Person 创建出来的对象什么类型?
// Object
// 为什么? 合理吗?
var p = new Person();
console.log( p.constructor.name )
//覆盖原型对象实现继承的时候, 一定要给新对象添加一个 constructor 属性
// 以便模拟对象的类型. 但是如果对对象的类型要求不严格可以忽略
3.利用组合式继承添加原型成员
// 对象.extend( 对象 )
2.组合式继承(可以有多个父类)
其他编程语言中一个子类只能有一个父类。
组合式继承就是将其他对象的属性循环绑定在当前对象上。
由于for in 循环中的对象可以随意的替代,因此o2可以继承自任意的对象,因此,这个继承方法称为组合式继承。
这里希望o2可以继承自任意对象,所以为了简化继承的代码,给o2提供一个方法,叫extend。组合式添加
o2.extend = function ( obj ) {
for ( var k in obj ) {
this[ k ] = obj[ k ];
}
}
o2.extend ( o1 ); //继承
3.经典的继承代码
在实际开发中, 如果希望获得一个继承自 对象 o 的对象(把o当成原型对象)
可以使用 Object.create 方法,这是ES5 提供的方法 (IE9以上支持)
Object.create语法:新对象(返回) Object.create( 作为原型对象的对象 )
注:Object 是大写,小写的object在typeof类型时会有,但它是不存在的
var o1 = { name: ‘jim‘ };
var o2 = Object.create( o1 );
// 类型无关,即无法确定类型
以上用的不多,但它是经典(用来解释继承),利用它讲浏览器兼容的问题。在这个地方要
1.明确函数调用语法 2.功能是什么?
//模拟create
//它会创建一个新对象, 让他继承自参数 对象
// 创建新对象就有构造函数
// 继承对象就有原型对象
function create( obj ) {
function F() {}
// 要有继承
F.prototype = obj;
return new F();
}
var o3 = create( o1 );
在实际开发中, 如果是为了兼容所有的浏览器, 有两种做法:
1.在原生对象中提供方法
if ( !Object.create ) {
Object.create = function ( obj ) {
function F() {}
// 要有继承
F.prototype = obj;
return new F();
}
}
var o4 = Object.create( o1 );
var _ = 0;//IE里面为了设断点
问题:原生污染
2, 统一用新的方法
var o5 = create ( obj );
无论浏览器是否支持该方法,都应该使用自己定义的方法来完成,但是在方法内部, 判断浏览器是否具有该功能, 如果有该功能 则使用浏览器提供的功能;如果浏览器不支持该功能, 则自己实现(视频中有源码)
4.小结
原型式继承
1.概念:对象继承自原型对象:对象没有的成员,可以由原型对象提供
2.实现方式:
动态添加原型对象成员(原型对象是个对象,所以点名字=值,添加的是值就是属性,添加的是function就是方法)
直接替换原型对象,就是将构造函数的原型属性给它赋值(如果对类型要求严格需要添加constructor属性)
利用extend函数给原型对象添加成员(可以看成第一种方法的升级版)
经典的继承代码
var o1 = { name: ‘jim‘ };
var o2 = Object.create( o1 );
O2作为对象,它的原型对象由谁决定 ?
O2的原型对象由构造函数的prototype决定
o2的原型对象是o1
//结论
O2的构造函数的prototype=o1
O2有构造函数吗?
O2是由create函数创建,那么在函数内部有一个构造函数就可以了
浏览器兼容性问题
两种解决办法
jQuery是模仿prototype框架写的。prototype框架是第一个用$作为全局对象的框架。
prototype框架的设计哲学是所有的东西都给原生对象提供,但是这样谁都可以引一个框架进来,框架多了,原生对象就变得复杂,使的乱,就会出现覆盖。
---->所以就不管什么样的浏览器,统一的调用方法来完成,在方法中完成。
1.直接交给原生对象,给原生对象提供功能(容易出现混乱)
2.无论是什么浏览器,都执行通用的方法。在方法中判断是否使用原生方法
六、原型链
对象都有一些共同的方法
toString、constructor...
对象是有原型对象的,原型对象也是对象...
重新定义原型继承
//原型对象也有原型对象,对象的原型对象一直往上找。会找到一个null
//在这个过程中,有一个Object类型,有很多方法的对象
//它就是Object.prototype
要求看到一个对象就知道他的原型链是什么样子的?
arr->Array.prototype->Object.protopyte->null
关于内存:别的语言有堆和栈,但是JavaScript是在浏览器上的,浏览器的厂商有很 多,各个浏览器实现的不同。
1.一个基本类型,在内存中的逻辑结构(不是物理结构)
var num=123 //在内存中有一个区域存储数字123,这个内存标记为num
值类型存储数值本身
2.引用类型存储的是数据的引用
引用类型的数据,有两个存储区域,一个存储数据本身,一个变量存储引用。
原型链结构