js+面向对象相关笔记(三)

1.构造函数中有一个prototype属性指向一个原型对象,然后原型对象中有一个constructor属性指行构造函数,所以它们才能够互相关联,如果你改变了构造函数的prototype属性所指向的原型对象如p.prototype={},那么现在这个原型的构造函数就会变成Object,自然就调用不了之前旧的原型中的方法了,因为当前的构造函数已经和新的原型进行了关联。


2.检测一个对象的数据类
◆使用Object.prototype.toString.call(arr);,方法中传递一个对象的实例,就能够找到它是什么数据类型,但是这种方法无法检测出自动定义构造函数创建出来的对象的实例
◆使用arr.constructor.name;也就是直接获取这个对象的构造函数的名称,既可以获取系统预定义的类型,也能够获取到自己自定义的构造函数创建出来的对象的实例的类型的名称,这种方式最会简洁,非常好。


3.js继承的三种方式
◆给原型对象添加成员(通过对象的动态特性),但是这并不是严格意义上的继承
◆直接替换掉原来的原型对象,那么构造函数实例化的对象就能够调用新的原型对象中的方法和属性(使用这种方式实现继承的时候,很有可能把之前原型中的属性和方法清空)。
◆利用混合的方式给原型对象添加成员,就是使用for in 外加对象的动态特性,也能够把另一个对象所有的方法都传给当前的对象(使用这种方式有可能会把原来原型中的同名方法或属性覆盖掉)。


4.扩展内置对象
◆一般扩展对象的属性或者方法,会使用给原型对象添加成员(对象的动态特性),但是这种方式不适合用在js 的内置对象中,因为如果改了内置对象中的成员,那么其它地方需要用就没办法了,会造成冲突,所以不推荐这么使用。
★扩展内置对象的方式可以使用如下的方式【
//新创建一个构造函数
function MyArr(){}
//替换掉这个构造函数的原型(也就是让它继承自新的类型)
MyArr.prototype=new Array();//它的原型就是一个数组了,于是它就能够调用内置对象数组中的方法
var myarr=new MyArr();
myarr.push("1个球");//调用数组的方法
myarr.push("2个球","3个球");
console.log(myarr);//["一个球","2个球","3个球"]
】,MyArr的原型变成了一个数组的实例化对象,这个数组的实例化对象并不会影响数组的原型,所以可以随便往里面添加成员或修改原成员,不会影响数组对象。


5.原型链
◆每个构造函数都有原型对象
◆每个对象都会有构造函数
◆每个构造函数的原型也都是一个对象
◆那么这个原型对象也会有构造函数
◆那么这个原型对象的构造函数也会有原型对象
◆循环往复就会形成一条链式结构,就称为原型链,并且到最终都会指向一个Object,Object的原型对象不存在,所以Object是最终的类型,也称之为基类(最终的类型)
◆对象.__proto__实际上等价于对象.constructor.prototype,也就是对象.构造函数.原型,但是最好不要动__proto__,因为会影响到构造函数的原型,这个属性一般用来测试,因为代码量很少,并且它并不在标准之内。
◆当你替换掉当前构造函数的原型后要记得给这个构造函数的原型添加一个constructor属性,不然就有可能无法通过对象.constructor来获取当前对象的构造函数了【
Human.prototype=new Animal();//原型继承自Animal的一个对象
Human.prototype.constructor=Human;//但是自己还是Human类型的
】。


6.对象的成员搜索原则
◆当访问一个对象的成员的时候,会先在自身中去找(因为js中有对象的动态特性,当然对象也是由构造函数创建出来的),找到了那就直接使用,如果没有找到,那么就会去当前对象的原型中去找,找到了还是直接用,如果没有找到,那么就会去当前对象的原型对象中的原型对象中去找,就这样一直找到最后一个原型对象(Object.prototype),如果还是没找到,如果你访问的是引用类型则返回null,如果你访问的是基本类型则返回的是undefined,你访问的如果是一个方法,那么就会报错,因为null无法被当作方法来进行调用。


7.原型继承概念
◆通过修改原型链结构来实现继承,就叫做原型继承


8.ECMAScript5经典继承
◆使用一个方法Object.create()来实现原型继承:【
var object1={name:"zs"};
var obj=Object.create(object1);
console.log(obj.name);

◆兼容性写法,因为是ECMAScript5新增的一个方法:

var object1={name:"zs"};
//如果这个方法存在 才调用,首先检测浏览器是否有这个能力,如果没有就手动添加一个这样的方法,但是不推荐使用
if(Object.create){
//使用ECMAScript5中的经典继承方式
var obj=Object.create(object1);
conosle.log(obj.name);
}else {
//手动添加一个这样的方法
Object.create=function(object1){
//自定义一个构造函数
function F(){}
//使用原型继承的方式
F.prototype=object1;
//初始化这个构造函数 并返回
return new F();
}
var obj=Object.create(object1);
conosle.log(obj.name);
}



9.Object.prototype的成员 (以下的p代指一个对象)
◆constructor:原型对象内的一个属性,执行该原型对象相关联的构造函数【p.constructor】。
◆hasOwnProperty:一个方法,用来判断对象本身(不包含原型)是否拥有某个属性【p.hasOwnProperty("name")】。
◆propertyIsEnumerable:判断属性是否属于对象本身,判断属性是否可以被遍历【p.propertyIsEnumerable("name")】。
◆Object.defineProperty(obj,prop,descriptor);可以用来添加属性,同时也可以用来附加一些信息,例如这个属性是否可写可读可遍历

obj: 需要被操作的目标对象
prop: 目标对象需要定义或修改的属性的名称
descriptor: 将被定义或修改的属性的描述符


var obj = new Object();
Object.defineProperty(obj, 'name', {
    configurable: false,
      writable: true,
        enumerable: true,
        value: '张三'
})
                     console.log(obj.name)  //张三

◆toString()和toLocaleString():会根据操作系统来进行字符串的大小写转换,并且如果是日期的话还会进行地区时间的转换。
◆valueOf:当对象参与运算的时候,默认会先去调用对象的valueOf方法,如果valueOf获取到的值,无法进行运算,那么就会去调用这个对象的toString方法,最终做的就是字符串拼接的工作了
◆__proto__:是对象中的属性,会指向该对象的构造函数的原型对象,可以通过对象.__proto__去访问原型对象。


10.Function这个构造函数,可以用来新建函数对象
◆var 函数名=new Function();,一个参数都不传递的情况下就是创建一个空的函数。
◆var 函数名=new Function("函数体");,只传一个参数的情况,这个参数就是函数体。
◆var 函数名=new Function("参数1","参数2","函数体");,传递多个参数的情况,最后一个参数为函数体,前面的参数都是该函数的参数名。
◆解决使用传递的函数体过于长的问题【
◇可以使用+作为连接符号。
◇可以定义一个模板,然后通过dom来读取模板中的字符串,然后将读取到的字符串作为函数体位置上的参数。



◆解决使用传递的函数体过于长的问题2(ECMAScript6语法)【
//使用``来作为字符串的界定符号
var distinct=new Function(`
var arr=[];
for(var i=0;i<arguments.length;i++){
if(arr.indexOf(arguments[i])==-1){
arr.push(arguments[i]);
}
}


`)





11.eval函数可以用来将字符串转换为javascript代码并且运行
◆使用eval来解析JSON格式字符串的时候,会将{}解析为代码块儿,而不是对象,所以需要在JSON格式的字符串前面拼接上var obj=,如【
var jsonData='{"name":"zs"}';
eval("var obj="+jsonData);
console.log(obj);//{name:"zs"}
】。
◆使用eval来解析JSON格式字符串的时候,会将{}解析为代码块儿,而不是对ixang,所以需要在JSON格式的字符串两边下上小括号,如【
var jsonData='({"name":"zs"})';
var obj=eval(jsonData);
console.log(obj);//{name:"zs"}

◆由于eval可以将字符串转换为js代码并且执行,所以可能会引发跨站点脚本攻击,所以不推荐使用eval,将JSON格式字符串转换为js对象,可以使用JSON.parse();。


12.静态成员和实例成员的概念,是从其它变成语言中引入的
◆静态成员:是指构造函数的属性和方法【
如jquery中 $.trim();$.each();.$.extends();

◆实例成员:是指实例的属性和方法【
如$("#id").css();$("#id").text();

◆一般都是把工具方法,作为静态成员(全局共享,并且添加起来还是使用的对象的动态特性,构造函数的对象都可以调用)
◆一般把跟对象相关的方法,作为实例成员







posted @ 2018-06-15 09:53  我叫贾文利  阅读(88)  评论(0编辑  收藏  举报