js对象总结(2)

五、原型:

  1、原型的定义: 原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过改构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。

  2、利用原型特点和概念,可以提取共有属性。将一类对象的共有属性提取出来,放到该类对象的原型中,从而不需要每次用new操作符时都重新定义一遍该共有属性。

  如下,定义一个Person构造函数,而属于Person多构造对象共有的属性方法,则定义到Person的原型中

Person.prototype = {
				eat: function (food){
					console.log('I have eated ' + food);
				},
				sleep:function () {
					console.log("I am sleeping");
				}
			}
			// 人的构造函数
			function Person (name, age) {
				this.name = name;
				this.age = age;
			}
			var person1 = new Person('zsn', 18);
			console.log(person1.name);//zsn
			person1.eat('apple');//I have eated apple

 3、如何查看原型:

   之前是不允许我们查看构造函数的原型的,但后来提供了一个可查看构造函数原型的接口:隐士属性__proto__(其实我们能够访问原型的属性,或者说继承原型,靠的就是__proto__属性连接着构造函数和原型,可以说没有__proto__属性的存在,就无法实现原型的继承)

(1)、首先我们先说明一下__proto__这个接口是存放到哪里的

   看过以上对象创建过程的都应该知道在用new创建一个对象时,内部会隐士自动创建一个this的对象,进过一系列处理后再隐士将this对象返回。而__proto__就对于隐士创建的this对象中,如下代码:

//原型
			Person.prototype = {
				eat: function (food){
					console.log('I have eated ' + food);
				},
				sleep:function () {
					console.log("I am sleeping");
				}
			}
			// 构造函数
			function Person (name) {
				
				//var this = Object.create(Person.prototype);
				//p.s.在隐士创建的this对象中存在一个属性,即__proto__,该属性存储了Person.prototype
				this.name = name;
				// return this;
			}
			 // 对象的创建
			var person1 = new Person('zsn');
			// 打印原型
			console.log(person1.__proto__);

如何查看原型:直接通过new操作符创建的对象访问__proto__属性即可

  4、如何查看对象的构造函数,我们通过属性constructor来查看:

    contructor属性位于构造函数的原型中,其中存储的是构造函数信息,所以在不知道原型的情况下,由原型继承原理,我们可以用实例对象来直接访问constructor,即获取创建该实例的构造函数

function Person () {
				this.name = 'myName';
				this.age = 18;	
			}
			var person = new Person();
			console.log(person.constructor);// function Perso(){...}

六、原型链:

  1、定义:原型链就是将一个个原型串连起来,形成一条原型继承的链子。

  2、原型链的构成:

      如下代码例子, Child继承Parent, Parent继承GrandParent, 而GrandParent没有自定义原型,所以默认为原型链的最顶端new Object();

       (为什么Object为最顶端,因为Object.prototype为null,为null是没有原型的)

 //    原型链: Child -> new Parent() -> new GrandParent() -> new Object();
			 function GrandParent(){
			 	this.name = 'GrandParent';
			 	this.a = 3;
			 }
			Parent.prototype = new GrandParent();
			function Parent() {
				this.name = 'parent';
				this.b = 2;
			}
			Child.prototype = new Parent();
			function Child() {
				this.name = 'child';
                this.c = 1;
			}
			var child = new Child();
			console.log(child); // Child {name: "child", c: 1}
			console.log(child.a); //3
			console.log(child.b); //2
			console.log(child.c); //1
			console.log(child.name); //child

 3、原型链的增删改查:

    使用如上的原型链说明, Child -> new Parent() -> new GrandParent() -> new Object(), 实例对象为child

    (1)、增:

      为child实例对象添加属性,总是添加为其自己本身的属性,为对原型和原型链是没有影响的。(再具体说即对和其相同构造函数构造的实例对象无法造成影响,以下说法同此)

    (2)、删:

      使用delete操作符只能删除child实例对象自己本身的属性,而无法删除由原型继承而来的属性

    (3)、改:

      分两种情况:

        若修改的属性为继承自原型的,且值类型为原始值,则仅仅修改的是该实例对象的属性,对原型无法造成影响。

若修改的属性为继承自原型的,属性值类型为引用值,则对引用值的修改又分两种情况:

            第一种是直接对该修改的属性赋值 => 此情况仅仅修改的是实例对象的该属性,无法对原型造成影响。

            第二种是对该修改的属性添加内容或去除内容,而不是对其重新赋值 => 此情况会对原型造成影响。如下例子:

Person.prototype = {
				has: [1, 2, 3]
			}
			function Person (){
				this.name = 'zsn';
			}
			var person1 = new Person();
			var person2 = new Person();
			person1.has.push(4);
			 // person1 和 person2都改变了,因为person1的修改影响到了原型,进而影响到了另一个实例对象
			console.log(child.a); //3
			console.log(child.b); //2

七、对象继承史

  由于之前已经总结过这些,所以此处直接就粘链接了: http://www.cnblogs.com/Walker-lyl/p/5592048.html

八、命名空间:

        我们可以利用对象创建命名空间来管理变量,防止污染全局,适用于模块开发,如下简单的小demo:

var workSpace = {
				person1: {
					name: 'one',
					age: 18
				},
				person2: {
					name: 'two',
					age: 20
				}
			}
			    // 这样两个人虽然有同名变量,但不会相互影响,因为位于不同命名空间
     //    访问第一个人的姓名
     console.log(workSpace.person1.name);
     console.log(workSpace.person2.name);

九、实现类似jquery中的链式调用: return this;

    如下小demo,其中的this不懂的没关系,上面会说,你只要把次demo中的this当成person对象就行

var person = {
				foodCount: 10,
				eat: function() {
					this.foodCount--;
					return this;
				},
				buy: function() {
					this.foodCount++;
					return this;
				},
				print: function () {
					console.log(this.foodCount);
				}
			}
			 //   foodCount初始值为10, 在连续吃了三次后,变为7
			 person.eat().eat().eat();
			 person.print();

十、对象的枚举:

  1.obj.hasOwnProperty('prop');

  该方法的作用是来判断对象obj的自身属性中是否含有属性prop,自身属性是在构造函数中生成的或者实例对象后来自己添加的,而继承属性则是从原型上继承的属性,所以该方法就是判断该属性是从原型继承来的还是自身的。

  作用: 遍历一个对象的所有自身属性,因为es5中的对象遍历是默认打印包括继承自原型的属性的,demo如下

 

Person.prototype.age = 18;
     function Person () {
         this.name = 'lyl';
     }
     var person = new Person();
    //  未用hasOwnProperty
    // print:
    //  lyl
     for(var prop in person) {
         console.log(person[prop]);
     } 
    //  使用hasOwnProperty
    // print: 
    // 18 lyl
     for(var prop in person) {
         if(person.hasOwnProperty(prop)) {
             console.log(person[prop]);
         }
     }

2、prop in obj; 

  in操作符用来判断该对象obj上是否有该属性prop,prop既可以是自身属性,也可以是继承属性,如下demo

Person.prototype.age = 18;

			function Person() {
				this.name = 'lyl';
			}
			var person = new Person();
			console.log('age' in person); // true
			console.log('name' in person); // true
			delete person.name;
			console.log('name' in person); //false

3、object instanceof Object;

  instanceof操作符用来判断object实例对象是否为Object构造函数创建的,如下demo

Person.prototype.age = 18;
			function Person() {
				this.name = 'lyl';
			}
			var person = new Person();
			console.log(person instanceof Person); // true
			console.log(new Object() instanceof Person); //false

十一、this基本介绍:

  1、函数预编译过程 this —> window
  2、全局作用域里 this —> window

  3、obj.func();   func()里面的this指向obj), 可以这样理解,谁调用func,则this就指向谁

  4、call/apply 可以改变函数运行时this指向,

    (1)、call用法:

      func.call(要改变后的this, arg1, arg2, ... );

    (2)、apply用法:

      func.apply(要改变后的this, [arg1, arg2, arg2]);

    (3)、apply和call共同点:都是改变this指向

        apply和call不同点:传参形式不同,call是将参数一个个传进来,而apply是将所有参数存进一个数组中,然后将该数组传

如下demo:

// demo1
			function demo1(){
				console.log(this);
			}
			// demo1() <==> this.demo1(); <==> window.demo1()
			demo1(); // window
			// demo2
			var demo2 = {
				retThis: function(){
					console.log(this);
				}
			}
			demo2.retThis(); // demo2 = {...}
			// call / apply改变this
			demo1.call(demo2); // demo2 = {}
			demo2.retThis.call(window); // window

十二、对象的克隆:

  你可能回想,直接用等号赋值不久完成克隆了吗?这还用说,但你忽略了对象是一个引用值,赋值操作赋的是该对象的引用,然后会产生很坏的影响。

  举例来说,将obj1赋值给obj2,然后我们向obj2中添加了一个属性,然后我们会惊喜的发现obj1中也有了此刚刚向obj2中添加的属性,但我obj1并不需要该属性啊,则造成obj1不开心了,为了让obj1开心起来,我们向下看,嘿嘿:

  对象克隆,分为浅克隆和深克隆,而上边的直接赋值的克隆操作为浅克隆,为什么称为浅克隆呢?因为,克隆的和被克隆的对象在克隆操作完成后,指向同一个地址引用,改变其中一个(注意:此处的改变为增加或删除对象的属性,而不是为该对象重新赋值一个对象),另一个也会改变,而深克隆则不会产生此现象。

  深克隆/深拷贝code如下,这是我从网上搜到的一个目前我见到的最完整最简短的code,直接贴上:

// 对象的深度克隆(Array / obj /...)
        function  deepClone(obj) {
            var str, retObj = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {};
            if(typeof obj !== 'object') {
                return;
            }else if(window.JSON) {
                str = JSON.stringify(obj);
                retObj = JSON.parse(str);
            }
            else {
                for(var prop in obj) {
                    retObj[prop] = typeof obj[prop] === 'object' ? deepClone(obj[prop]) : obj[prop];
                }
            }
            return retObj;
        }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值