纯属笔记,加强记忆,不是教程,欢迎纠错,没有逻辑,不太适合学习使用。

--------------

继承多态等太多概念难以理解,还是从实践中慢慢学吧!争取能大致看懂网上的开源的代码。

--------------

对象的组成:方法和属性

属性关键词:静止的,状态

方法关键词:动态的,过程,处理,带括号

--------------

js中的面向对象不是其他语言那样的面向对象。

         <script type="text/javascript">
//定义arr为一个数组(数组也是一个对象实例,所以arr是个对象实例)
var my_arr=[];
//以前变量这样用,var number=10;
//现在定义属性,arr.number = 10; 就是用“点”即可!
my_arr.number = 10;
//定义对象的方法
my_arr.test = function(){
console.log(this);
//这里this就是这个数组,直接用数组名也可以
//alert(my_arr.number);
//alert(this.number);
}
//这样使用方法
my_arr.test();
</script>

这里需要注意的是,能不能将第6行放在第3行前面?

不可以,没有到第3行赋值,my_arr还是undefined,而undefined是不能有特性的。

         <script type="text/javascript">
var a ='ddd';
a.kkk = 'eee';
console.log(a.kkk); //火狐,打印出undefined ,可见,a不是一个对象类型的数据时,还不可以直接加“点”呢
a.ka = function (){
console.log('aaaaaaaaaaaaaaaaaa');
}
a.ka(); //报错,a.ka is not a function 可见,a不是一个对象类型的数据时,还不可以直接加“点”赋予方法呢
</script>
         <script type="text/javascript">
var a ='ddd';
String.prototype.kkk = 'eee';
a.kkk = 'eeeddd';
console.log(a.kkk); //火狐,打印出eee ,可见,a不是一个对象类型的数据时,还不可以直接加“点”呢,但是从字符串的原型上可以加
String.prototype.ka = function (){
console.log('aaaaaaaaaaaaaaaaaa');
}
a.ka(); //aaaaaaaaaaaaaaaaaa
</script>

结果是数组有个number属性和test方法,但是数组内容为空,length为0,但是这样alert(my_arr['number']);也可以弹出10

//TODO 以后再研究数组,但是可见,数组的内容是内容,属性和内容不是一回事,内容是数组里面存了啥,属性是这个数组实例有什么属性。如同,一个是汽车里装了谁谁,一个是汽车有车大灯的感觉。

------------

新建一个纯净的对象实例

     <script type="text/javascript">
var my_obj = new Object(); //新建一个对象实例my_obj,换成 var my_obj = {}; 也行,一个意思
my_obj.name = '张三'; //加个属性
my_obj.test = function(){ //加个方法
this.test2(); //对象的A方法中用到对象的B方法
}
my_obj.test2 = function(){
console.log(this.name);
}
my_obj.test(); //使用
</script>

对象中思考变量作用域的问题

以前学到变量作用域,都是函数和变量,现在加入对象,看看是怎么回事

     <script type="text/javascript">
console.log(my_obj); // 显示undefined,说明解析器中和其他类型一样,根据var,先放个undefined再说
var my_obj = {};
console.log(my_obj); // 显示 Object {}
my_obj.name = '张三';
console.log(my_obj); // 显示Object {name:"张三"}
</script>

其实可以这样理解,js解析器,预解析,根据var找到了my_obj,赋值undefined,如果放到不用对象的时候,出个name,需要var name一下,这里由于对象var了,对象下各个目前未定义的属性就相当于已经var但没赋值了,一旦测试都是undefined。第4行,由于还没有赋予name属性,如果查看my_obj.name的话,就是undefined,而第5行赋值,第6行再看,就是“张三”了。

     <script type="text/javascript">
var my_obj = {};
my_obj.name = '张三';
console.log(my_obj.test); //undefined
my_obj.test(); //浏览器提示出错,说test不是一个函数。可见my_obj.test = function(){...} 只是一个赋值,并没有因为是function,就扔到预解析仓库中
my_obj.test = function(){
console.log(this.name);
}
</script>
     <script type="text/javascript">
var my_obj = {};
my_obj.name = '张三';
my_obj.test = xxx;
my_obj.test(); //这样写是可以执行的,因为函数xxx扔到预解析仓库了,上一行又赋予test这个函数了,显示张三
function xxx(){
console.log(this.name);
}
</script>
<script type="text/javascript">
var my_obj = {};
my_obj.name = '张三';
my_obj.test = function xxx(){
console.log(this.name);
};
my_obj.test(); // 正常运行 </script>
 <script type="text/javascript">
var my_obj = {};
my_obj.name = '张三';
my_obj.test = function xxx(){
console.log(this.name);
};
xxx(); //浏览器报错,火狐认为,xxx未定义,也就是说,在等号后面的函数不会被预解析,这里不求预解析,连解析都没有
</script>
     <script type="text/javascript">
var my_obj = {
name : "张三",
test : function(){
//对象也是个变量作用域,这里面是可以使用对象外面的函数的
//console.log(name); 不可以这样用,不能因为name和test平级,就不加this,属性名和变量是不同的,要加上对象名才能用
console.log(this.name); //console.log(my_obj.name); 这样也行
}
};
my_obj.test(); //显示张三
console.log(my_obj.name); //想使用对象的属性,就要加对象名 </script>

-----------------------

这里新建对象不够灵活,如果要建的对象名不是张三呢,而是好几个,张三,李四,王二,麻子等很多人,那么就要用到工厂方式

还按照上面的方式就是如下代码

         <script type="text/javascript">
var my_obj1 = {
name: "张三",
test: function() {
console.log(this.name); //如果是console.log(my_obj2.name); 将显示李四,也就是用到了其他对象的属性。
}
}; var my_obj2 = {
name : "李四",
test : function(){
console.log(this.name);
}
}
my_obj1.test(); //显示张三
my_obj2.test(); //显示李四
</script>

js并不是其他语言那样的面向对象,这里的对象,其实是其他语言中 对象实例的意思。

上面代码怎么精简呢,共同部分用一个函数来生成即可,也就是所谓的工厂模式,如下

         <script type="text/javascript">
function CreatePerson(name){ //这个function就相当于一个生产对象的工厂
var obj = new Object();
obj.name = name;
obj.test = function() {
console.log(this.name);
}
return obj;
} var my_obj1 = CreatePerson('张三'); //开始生产了
var my_obj2 = CreatePerson('李四');
my_obj1.test();//使用工厂生产出来的对象
my_obj2.test();
</script>

在js中,用new去调用一个函数的话,这个函数中的this就是创建出来的对象,而且函数的返回值直接就是this  隐式返回

难以理解这句吧,就是js规定的,函数加new, 函数中的this就是对象实例本身,并且函数返回该对象实例(不用你操作了,js帮你搞定)。

         <script type="text/javascript">
function CreatePerson(name){
this.name = name;
console.log(this); //打印出的this就是张三 这里就相当于js帮你做了 var my_obj1 = new Object(); 最后return my_obj1;
}
var my_obj1 = new CreatePerson('张三');
console.log(my_obj1); //打印出的my_obj1就是张三
</script>

这样调用

var my_obj1 = new CreatePerson('张三'); 是不是很像  var date = new Date();
         <script type="text/javascript">
function CreatePerson(name){
this.name = name;
this.test = function(){
console.log(this.name);
}
} var my_obj1 = new CreatePerson('张三');
my_obj1.test();
</script>

但是这样还是有问题,每个对象实例的方法,都是在内存总新建的,用prototype来对相同的对象实例方法进行定义,使之共用内存。改造如下

         <script type="text/javascript">
function CreatePerson(name){
this.name = name;
} CreatePerson.prototype.test = function(){
console.log(this.name);
} var my_obj1 = new CreatePerson('张三');
var my_obj2 = new CreatePerson('李四'); alert(my_obj1.test == my_obj2.test); //true
my_obj1.test(); // 张三
my_obj2.test(); // 李四 </script>

这里面的对象这样去记忆理解容易点。 my_obj1和my_obj2是具体的某个人,是对象的实例。而CreatePerson是人这一类,是构造函数。在CSS中,有行内样式 <div style="...."></div> 或者写成 <div class="..."></div>这里。用构造函数加上prototype的方式,类似于class,能广泛用于很多个个体对象实例,而直接加在个体上的方法就只能用于个体,同时,二者有重名冲突的时候,个体上的方法优先级较高。

         <script type="text/javascript">
function CreatePerson(name){
this.name = name;
} CreatePerson.prototype.test = function(){
console.log(this.name);
} var my_obj1 = new CreatePerson('张三');
var my_obj2 = new CreatePerson('李四'); //为my_obj1这个个体又单独加个test。prototype定义的test对该个体来说失效
my_obj1.test = function(){
console.log(this.name+'111');
} alert(my_obj1.test == my_obj2.test); //false
my_obj1.test(); // 张三111
my_obj2.test(); // 李四 </script>

再看看最开始怎么定义my_obj1,直接 var my_obj1 = new Object(); 或者写 var obj = {};这也是js的面向对象,到现在用构造函数的方式,一个是直接定义到个体,一个是先定义一个种类,然后再出个体。

使用原型再举个例子,求数组中元素的和,如下

         <script type="text/javascript">
var arr_1 = [1,9,3,5];
Array.prototype.sum = function(){
var result = 0;
for (var i=0;i<this.length;i++) {
result += this[i];
}
return result;
} console.log(arr_1.sum());//
</script>

原型要加在构造函数上

         <script type="text/javascript">
var arr_1 = [1,9,3,5];
var arr_2 = [3,5,7];
Array.prototype.sum = function(){
var result = 0;
for (var i=0;i<this.length;i++) {
result += this[i];
}
return result;
}
arr_1.sum = function(){
return '我要覆盖prototype的方法!';
} console.log(arr_1.sum());//我要覆盖prototype的方法!
console.log(arr_2.sum());//
</script>

----------------

js是基于原型的程序

每个基本类型数据都有一个原型,字符串 String  数字 Number 布尔值 Boolean 数组 Array

尽量不要去修改系统对象下面的方法和属性。

例子:重写数组的push方法

         <script type="text/javascript">
var arr = [1,2,3];
Array.prototype.push = function(){//这里系统自带的push就被覆盖了
for(var i=0; i<arguments.length;i++){
this[this.length] = arguments[i];
}
return this.length;
} arr.push(9,8,7,6,5);
console.log(arr);
</script>

---------------

包装对象:基本类型(除了null 和 undefined)都有自己对应的包装对象,如String Number  Boolean,这里也就知道了,null空对象和undefined未定义是不能再添加属性和方法的

        <script type="text/javascript">
var str1 ='hello123';
var str2 = new String('hello123');//通过new创建的都是对象 console.log(typeof str1);//string
console.log(typeof str2);//object
</script>
         <script type="text/javascript">
var str1 = 'hello123';
var str2 = new String('hello123'); //通过new创建的都是对象 console.log(typeof str1); //string
console.log(typeof str2); //object
str2.lastvalue = function() {
return this.charAt(this.length - 1);
}
console.log(str2.lastvalue());//最后一个字符3 str1.lastvalue = function() { //报错,因为str1是字符串,不是对象,不能添加方法,只能使用其包装对象给予的方法
return this.charAt(this.length - 1);
}
console.log(str1.lastvalue());
</script>

如果str1这个字符串类型数据,要添加方法,那可以添加到它的包装对象上。如下

         <script type="text/javascript">
var str1 = 'hello123';
String.prototype.lastvalue = function(){
return this.charAt(this.length-1);
}
console.log(str1.lastvalue());
</script>

-----------------------------

原型链:个体实例和原型之间的链接 , 原型链的最外层是Object.prototype

举例:个体人物:张三 / 原型:男人

张三具有属性:姓名:张三;

     <script type="text/javascript">
function Man(name){
this.name = name;
}
Man.prototype.name = '男人';
Object.prototype.name = '人类'; var Zhanshan = new Man('张三');
console.log(Zhanshan.name); //显示张三,如果没有第3行代码,则根据原型链,显示为男人,如果连第5行也没有,则显示为人类
//console.log(Man.prototype.name); //显示男人,若无第5行,则显示为人类
</script>

也就是注意层级关系。没有找到的属性就往原型链上找,优先级当然是内层优先。

-------------------

------------------

面向对象的一些属性和方法

hasOwnProperty  :  对象个体实例自身是不是有某个属性?如果是个体自身的属性返回true; 如果属性是原型下的,返回false;

     <script type="text/javascript">
function Man(name){
this.name = name;
}
Man.prototype.name = '男人'; var Zhanshan = new Man('张三');
console.log(Zhanshan.hasOwnProperty('name')); //true
</script>
     <script type="text/javascript">
function Man(name){
//this.name = name;
}
Man.prototype.name = '男人'; var Zhanshan = new Man('张三');
console.log(Zhanshan.hasOwnProperty('name')); //false
</script>
    <script type="text/javascript">
function Man(name){
//this.name = name;
}
Man.prototype.name = '男人'; var Zhanshan = new Man('张三');
Zhanshan.name = '张三三';
console.log(Zhanshan.hasOwnProperty('name')); //true
</script>
    <script type="text/javascript">
function Man(){
this.name = '张三';
}
Man.prototype.name = '男人'; var Zhanshan = new Man('张三');
console.log(Zhanshan.hasOwnProperty('name')); //true 虽然新建个其他的个体实例,name也会是张三,但是该个体实例自身有name属性,所以还是true </script>

constructor : 查看对象的构造函数

     <script type="text/javascript">
function Man(name){
this.name = '张三';
}
Man.prototype.name = '男人'; var Zhanshan = new Man('张三');
console.log(Zhanshan.constructor == Man); //true
</script>
     <script type="text/javascript">
var a1 = [1,2,3];
console.log(a1.constructor = Array); //true
</script>

当我们写一个函数时,程序自动会生成constructor

     <script type="text/javascript">
function Aaa(){
}
//注意,下面这句话是系统内部自动实现的,这里写出来,好看到系统做了什么,只要定义一个函数,系统都会"自动生成"下面一句
//Aaa.prototype.constructor = Aaa; //这里可以自行更改,将覆盖,如Aaa.prototype.constructor = Array;但是乱改后将影响使用
console.log(Aaa.prototype);
//只有constructor是函数原型自身的,hasOwnProperty这个方法是Object上的,是通过原型链找到的
</script>

现在知道不要更改constructor,但是有时候,不注意我们就更改了,如下:

     <script type="text/javascript">
function Aaa(){
}
Aaa.prototype.name = '张三';
Aaa.prototype.age = 30; var a1 = new Aaa();
console.log(a1.constructor); //Aaa
</script>

上面我们知道,Aaa.prototype也是一个对象,上面的改写为如下形式,就更改了constructor

     <script type="text/javascript">
function Aaa(){
}
//这里更改了,不是更改属性,而是重新对Aaa.prototype进行了赋值,也就弄丢了constructor属性
Aaa.prototype = {
name:"张三",
age :30
}
var a1 = new Aaa();
console.log(a1.constructor); //Object </script>

所以,当我们按照上面这张方法写的时候,要加上修正的,变成如下

     <script type="text/javascript">
function Aaa(){
}
//弄丢的constructor属性再找回来
Aaa.prototype = {
constructor:Aaa, //注意不要加引号,注意这句话就是为了修正对象constructor属性
name:"张三",
age :30
}
var a1 = new Aaa();
console.log(a1.constructor); //Aaa
</script>

还有一个地方注意:用for in循环对象的属性的时候,系统自带的属性是循环不到的

     <script type="text/javascript">
function Aaa(){
}
Aaa.prototype.name = '张三';
Aaa.prototype.age = 30;
Aaa.prototype.constructor = Aaa;
var a1 = new Aaa();
for (var attr in Aaa.prototype) {
console.log(attr); //显示了name和age,但是不显示constructor,即使还单独写一次
}
</script>

但是,如果用= 重新赋值的方式,再循环打印是可以打印出来的哦!如下

     <script type="text/javascript">
function Aaa(){
}
//这种方式是重新赋值
Aaa.prototype = {
constructor:Aaa, //注意不要加引号,注意这句话就是为了修正对象constructor属性
name:"张三",
age :30
}
var a1 = new Aaa();
for (var attr in Aaa.prototype) {
console.log(attr); //显示constructor name age
}
</script>

instanceof 运算符,判断个体对象和原型函数 是否有原型链上的关系,返回true或false 如下

     <script type="text/javascript">
function Man(name){
this.name = name;
}
function Woman(name){
this.name = name;
}
var zhanshan = new Man();
console.log(zhanshan instanceof Man); //true
console.log(zhanshan instanceof Object); //true
console.log(zhanshan instanceof Woman); //false
</script>

用instanceof判断某变量是否是数组

     <script type="text/javascript">
var a1 = [1,2,3,4,5];
console.log(a1 instanceof Array); //true; var b1 = 'hi';
console.log(b1 instanceof Array); //false;
</script>

toString 方法  把对象转成字符串 。 系统对象下面都是自带的,而自己创建的对象toString在object上

如下

     <script type="text/javascript">
var a1 = [1,2,3,4,5];
console.log(a1.toString == Object.prototype.toString); //false 系统对象下面都是自带的,不是Object上的;
console.log(a1.toString == Array.prototype.toString); //true 系统对象下面都是自带的,在Array上 不在Object
function Bbb(){
}
var b1 = new Bbb();
console.log(b1.toString == Object.prototype.toString); //true 自己创建的对象toString在object上
</script>
     <script type="text/javascript">
var a1 = [1,2,3,4,5];
console.log(a1.toString()); //1,2,3,4,5
console.log(typeof a1.toString()); //string
</script>
     <script type="text/javascript">
var a1 = [1,2,3,4,5];
console.log(a1.toString()); //1,2,3,4,5
console.log(typeof a1.toString()); //string //按照系统toString生成的1,2,3,4,5 如果不符合我们使用的格式的话,我们还可以自己去改写
Array.prototype.toString = function(){
return this.join('+'); //将数组内容按照加号连接
}
console.log(a1.toString()); //1+2+3+4+5
</script>
     <script type="text/javascript">
var num = 255;
console.log(num.toString(16)); //ff, 参数16是16进制的意思,输出16进制的数据 rgb色彩可以用~~
console.log(num.toString(2)); // 11111111 参数2是2进制的意思
</script>

上面是利用toString转换数字进制

toString还可以用来判断变量的数据类型,比typeof   instanceof  更精准,如下

     <script type="text/javascript">
var num = 255;
console.log(Object.prototype.toString.call(num)); // [object Number]
console.log(Object.prototype.toString.call(num) == '[object Number]'); // true; var str = 'hello';
console.log(Object.prototype.toString.call(str)); // [object String]
var arr = [1,2,5];
console.log(Object.prototype.toString.call(arr)); // [object Array] console.log(Object.prototype.toString.call({name:'张三'})); //[object Object] </script>

-------------

对象的继承  继承要求原类不变,新出子类

如何做?

     <script type="text/javascript">
function CreateUser(name,age){
this.name = name;
this.age = age;
} CreateUser.prototype.dosometing = function(){
console.log(this.name+'dosometing');
} var Zhanshan = new CreateUser('张三',39);
Zhanshan.dosometing(); function CreateStar(name,age,job){
CreateUser.call(this,name,age); //这句话完成了属性的继承
this.job = job;//这句话添加父级没有的新属性
} CreateStar.prototype = CreateUser.prototype; //这句话完成了方法的继承,但是根据对象赋值可知,这里,子类对象的变化,父类对象亦变。不是完美的方式。 var Lichen = new CreateStar('李晨',40,'演员');
console.log(Lichen.name + '是个' + Lichen.job);
Lichen.dosometing(); console.log(Lichen.constructor); //CreateUser 因为直接CreateStar.prototype = CreateUser.prototype; 所以这里不是CreateStar console.log(CreateStar.prototype.constructor); //CreateUser
console.log(CreateUser.prototype.constructor); //CreateUser
console.log(CreateUser.prototype.constructor == CreateStar.prototype.constructor); //true; </script>

js面向对象学习的更多相关文章

  1. js面向对象学习 - 对象概念及创建对象

    原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...

  2. js面向对象学习总结

    1.函数作为参数进行传递 function a(str,fun){ console.log(fun(str)) }; function up(str){ return str.toUpperCase( ...

  3. js面向对象学习笔记(五):tab切换

    重点是this指向问题 <style> .hide{display: none;} #box div,#box1 div{display: none;} .hover{background ...

  4. js面向对象学习笔记

    1.函数的定义方式 第一种定义方式 function fn1() { alert("fn1"); } alert(fn) 函数就是一个特殊的对象,是一个Function类的实例,其 ...

  5. js面向对象学习笔记(三):原型

    //原型:改写对象下面公用的方法或者属性,让公用的方法或者属性在内存中只存在一份(提高性能)//原型:prototype :要写在构造函数的下面var arr =[1,2,3,4,5];var arr ...

  6. js面向对象学习笔记(四):对象的混合写法

    //对象的混合写法//1.构造函数function 构造函数() { this.属性}构造函数.原型.方法 = function () {};//调用var 对象1 = new 构造函数();对象1. ...

  7. js面向对象学习笔记(二):工厂方式:封装函数

    //工厂方式:封装函数function test(name) { var obj = new Object(); obj.name = name; obj.sayName = function () ...

  8. js面向对象学习笔记(一):创建空对象,理解this指向

    var obj = new Object();//创建一个空对象 obj.name = '小王';//属性 obj.sayName = function () { //对象方法 对象最重要的是this ...

  9. 从 prototype.js 深入学习 javascript 的面向对象特性

    从 prototype.js 深入学习 javascript 的面向对象特性 js是一门很强大的语言,灵活,方便. 目前我接触到的语言当中,从语法角度上讲,只有 Ruby 比它更爽. 不过我接触的动态 ...

随机推荐

  1. Python中路径操作

    目录 1. os.path模块 2. pathlib模块 2.1 目录操作 2.2 文件操作 3. shutil模块 3.1 os模块 3.2 shutil模块 1. os.path模块 3.4版本之 ...

  2. jquery获取元素(父级的兄弟元素的子元素)

    一.获取父级元素 使用jquery获取父级元素: parent() 例如:$(this).parent('ul'); 二.获取同级元素 使用jquery获取同级元素:siblings() 例如:$(t ...

  3. Ajax全局处理错误

    背景:项目前端ajax请求很多都没有写error方法,所以用户体验很不好 新来的前端负责人发现这个问题,写了一个错误处理方法,如下 //统一处理Ajax错误方法 function onAjaxErro ...

  4. 一次 C# 查詢數據庫 算法優化的案例

    最近有次在修改某段程式時,發現一段程式算法看起來簡單. 但背後因為多次查詢數據庫,導致效能問題. 這段程式主要是利用 EPPLUS 讀取 Excel 資料,檢查資料是否已存在數據庫中,若有就將已存在的 ...

  5. ADO.NET学习(一)

    一.ADO.NET简介 ADO.NET可以看作是C#语言访问数据库的一种方式.编程语言编写的程序需要数据库的支持,那么怎样才能让他们建立连接呢?当然是ADO.NET 二.ADO.NET 整体流程 1) ...

  6. JVM虚拟机基本概念

    一.JVM运行时数据区域1.1.程序计数器 一块较小的内存空间,当前线程所执行的字节码指示器.每个线程有一个独立的程序计数器1.2.Java虚拟机栈 线程私有,生命周期与线程相同 每个方法在执行时会创 ...

  7. Ubuntu16.04安装Qt5.12.2

    第一步:下载文件 https://download.qt.io/official_releases/qt/5.12/5.12.2/ 第二步:安装依赖库 sudo apt-get install bui ...

  8. 使用VC建立网络连接并访问网络资源

    目录 1. 提出问题 2. 解决方案 1. 提出问题 在windows下可以通过系统操作,将局域网的资源映射到本地,从而实现像本地数据一样访问网络资源.实际上这些步骤也可通过代码调用win32函数实现 ...

  9. python turtle 书写新年快乐

    文章链接:https://mp.weixin.qq.com/s/xYSKH_KLYfooIoelJH02Cg 农历2018年的最后一篇文章,踏上回家的征途前,推荐一个Python的三方库turtle, ...

  10. java或Jmeter实现两个日期相加减(2003-06-01-2003-05-01)

    在beanshell中写入如下代码, import java.io.FileInputStream; SimpleDateFormat myFormatter = new SimpleDateForm ...