美文网首页
JS面向对象、JQuery选择器

JS面向对象、JQuery选择器

作者: 啊烟雨 | 来源:发表于2018-11-05 19:46 被阅读0次

    ECMAScript 有两种开发模式:1.函数式(过程化),2.面向对象(OOP)。面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript 没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。

    js(如果没有作特殊说明,本文中的js仅包含ES5以内的内容)本身是没有class类型的,但是每个函数都有一个prototype属性。prototype指向一个对象,当函数作为构造函数时,prototype则起到类似class的作用。

    一.创建对象

    创建一个对象,然后给这个对象新建属性和方法。

    varbox =newObject();//创建一个Object 对象box.name = 'Lee';//创建一个name 属性并赋值box.age = 100;//创建一个age 属性并赋值box.run =function() {//创建一个run()方法并返回值returnthis.name +this.age + '运行中...';

    };

    alert(box.run()); //输出属性和方法的值

    上面创建了一个对象,并且创建属性和方法,在run()方法里的this,就是代表box 对象本身。这种是JavaScript 创建对象最基本的方法,但有个缺点,想创建多个类似的对象,就会产生大量的代码。

    为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。

    functioncreateObject(name, age) {//集中实例化的函数varobj =new Object();

    obj.name = name;

    obj.age = age;

    obj.run =function () {returnthis.name +this.age + '运行中...';

    };return obj;

    }varbox1 = createObject('Lee', 100);//第一个实例varbox2 = createObject('Jack', 200);//第二个实例alert(box1.run());

    alert(box2.run()); //保持独立

    工厂模式解决了重复实例化的问题,但是它有许多问题,创建不同对象其中属性和方法都会重复建立,消耗内存;还有函数识别问题等等。

    二.构造函数的方法

    构造函数的方法有一些规范:

    1)函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和

    普通函数);

    2)通过构造函数创建对象,必须使用new 运算符。

    functionBox(name, age) {//构造函数模式this.name = name;this.age = age;this.run =function () {returnthis.name +this.age + '运行中...';

    };

    }varbox1 =newBox('Lee', 100);//new Box()即可varbox2 =newBox('Jack', 200);

    alert(box1.run());

    alert(box1 instanceofBox);//很清晰的识别他从属于Box

    构造函数可以创建对象执行的过程:

    1)当使用了构造函数,并且new 构造函数(),那么就后台执行了new Object();

    2)将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this 就

    代表new Object()出来的对象。

    3)执行构造函数内的代码;

    4)返回新对象(后台直接返回)。

    注:

    1)构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用new 运算符来调用,否则就是普通函数。

    2)this就是代表当前作用域对象的引用。如果在全局范围this 就代表window 对象,如果在构造函数体内,就代表当前的构造函数所声明的对象。

    这种方法解决了函数识别问题,但消耗内存问题没有解决。同时又带来了一个新的问题,全局中的this 在对象调用的时候是Box 本身,而当作普通函数调用的时候,this 又代表window。即this作用域的问题。

    三.原型

    我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype 通过调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。

    functionBox() {}//声明一个构造函数Box.prototype.name = 'Lee';//在原型里添加属性Box.prototype.age = 100;

    Box.prototype.run =function() {//在原型里添加方法returnthis.name +this.age + '运行中...';

    };

    构造函数的声明方式和原型模式的声明方式存储情况如下:

    所以,它解决了消耗内存问题。当然它也可以解决this作用域等问题。

    我们经常把属性(一些在实例化对象时属性值改变的),定义在构造函数内;把公用的方法添加在原型上面,也就是混合方式构造对象(构造方法+原型方式):

    varperson =function(name){

      this.name = name

      };

      person.prototype.getName =function(){

        returnthis.name;

      }

      varzjh =new person(‘zhangjiahao’);

      zjh.getName(); //zhangjiahao

    原型:

    1.原型对象

      每个javascript对象都有一个原型对象,这个对象在不同的解释器下的实现不同。比如在firefox下,每个对象都有一个隐藏的__proto__属性,这个属性就是“原型对象”的引用。

    2.原型链

      由于原型对象本身也是对象,根据上边的定义,它也有自己的原型,而它自己的原型对象又可以有自己的原型,这样就组成了一条链,这个就是原型链,JavaScritp引擎在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回undefined.原型链一般实现为一个链表,这样就可以按照一定的顺序来查找。

    1:__proto__和prototype

    JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例:

    console.log(zjh.__proto__ === person.prototype)//true

    同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype

    console.log(person.prototype.__proto__ === Object.prototype)//true

    继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null

    console.log(Object.prototype.__proto__)//null

    我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。如下图:


    2:constructor

    原型对象prototype中都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用

    person.prototype.constructor === person//trueFunction.prototype.constructor === Function//trueObject.prototype.constructor === Object//true

    3:我们再举一个例子:

    function Task(id){ 

        this.id = id; 

    Task.prototype.status = "STOPPED"; 

    Task.prototype.execute =function(args){ 

        return"execute task_"+this.id+"["+this.status+"]:"+args; 

        vartask1 =newTask(1);  vartask2 =newTask(2); 

    task1.status = "ACTIVE"; 

    task2.status = "STARTING"; 

    print(task1.execute("task1")); 

    print(task2.execute("task2"));

    结果:

    execute task_1[ACTIVE]:task1

    execute task_2[STARTING]:task2

    构造器会自动为task1,task2两个对象设置原型对象Task.prototype,这个对象被Task(在此最为构造器)的prototype属性引用,参看下图中的箭头指向。

    由于Task本身仍旧是函数,因此其”__proto__”属性为Function.prototype, 而内建的函数原型对象的”__proto__”属性则为Object.prototype对象。最后Obejct.prototype的”__proto__”值为null。

    总结:

    实例对象的__proto__指向,其构造函数的原型;构造函数原型的constructor指向对应的构造函数。构造函数的prototype获得构造函数的原型。

    有时某种原因constructor指向有问题,可以通过

    constructor:构造函数名;//constructor : Task

    重新指向。

    四:继承

    继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而ECMAScript 只支持继承,不支持接口实现,而实现继承的方式依靠原型链完成。

    在JavaScript 里,被继承的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为子类型(子类,派生类)

    1.call+遍历

    属性使用对象冒充(call)(实质上是改变了this指针的指向)继承基类,方法用遍历基类原型。

    function A()

    {

        this.abc=12;

    }

    A.prototype.show=function ()

    {

        alert(this.abc);

    };//继承Afunction B()

    {

        //继承属性;this->new B()A.call(this);//有参数可以传参数A.call(this,name,age)}//继承方法;B.prototype=A.prototype;for(variin A.prototype)

    {

        B.prototype[i]=A.prototype[i];

    }//添加自己的方法B.prototype.fn=function ()

    {

        alert('abc');

    };varobjB=new B();varobjA=newA();objB.show();

    可以实现多继承。

    2.寄生组合继承

    主要是Desk.prototype = new Box(); Desk 继承了Box,通过原型,形成链条。主要通过临时中转函数和寄生函数实现。

    临时中转函数:基于已有的对象创建新对象,同时还不必因此创建自定义类型

    寄生函数:目的是为了封装创建对象的过程

    //临时中转函数functionobj(o) {//o表示将要传递进入的一个对象functionF() {}//F构造是一个临时新建的对象,用来存储传递过来的对象F.prototype = o;//将o对象实例赋值给F构造的原型对象returnnewF();//最后返回这个得到传递过来对象的对象实例}//寄生函数function create(box, desk) {varf = obj(box.prototype);

    f.constructor = desk;//调整原型构造指针desk.prototype = f;

    }function Box(name) {this.name = name;this.arr = ['apple','pear','orange'];

    }

    Box.prototype.run =function () {returnthis.name;

    };function Desk(name, age) {

    Box.call(this, name);this.age = age;

    }//通过寄生组合继承实现继承create(Box, Desk);//这句话用来替代Desk.prototype = new Box();vardesk =newDesk('Lee',100);

    desk.arr.push('peach');

    alert(desk.arr);

    alert(desk.run());

    JQuery选择器:

    性质:选择某个网页元素,然后对它进行某种操作

    jquery选择器可以快速地选择元素,选择规则和css样式相同,使用length属性判断是否选择成功。

    $(document) //选择整个文档对象

    $('li') //选择所有的li元素

    $('#myId') //选择id为myId的网页元素

    $('.myClass') // 选择class为myClass的元素

    $('input[name=first]') // 选择name属性等于first的input元素

    $('#ul1 li span') //选择id为为ul1元素下的所有li下的span元素

    对选择集进行修饰过滤(类似CSS伪类)

    $('#ul1 li:first') //选择id为ul1元素下的第一个li

    $('#ul1 li:odd') //选择id为ul1元素下的li的奇数行

    $('#ul1 li:eq(2)') //选择id为ul1元素下的第3个li

    $('#ul1 li:gt(2)') // 选择id为ul1元素下的前三个之后的li

    $('#myForm :input') // 选择表单中的input元素

    $('div:visible') //选择可见的div元素

    对选择集进行函数过滤

    $('div').has('p'); // 选择包含p元素的div元素

    $('div').not('.myClass'); //选择class不等于myClass的div元素

    $('div').filter('.myClass'); //选择class等于myClass的div元素

    $('div').first(); //选择第1个div元素

    $('div').eq(5); //选择第6个div元素

    选择集转移

    $('div').prev('p'); //选择div元素前面的第一个p元素

    $('div').next('p'); //选择div元素后面的第一个p元素

    $('div').closest('form'); //选择离div最近的那个form父元素

    $('div').parent(); //选择div的父元素

    $('div').children(); //选择div的所有子元素

    $('div').siblings(); //选择div的同级元素

    $('div').find('.myClass'); //选择div内的class等于myClass的元素

    相关文章

      网友评论

          本文标题:JS面向对象、JQuery选择器

          本文链接:https://www.haomeiwen.com/subject/gwzsxqtx.html