Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

面向对象的编程方式总结。 #13

Open
Kelichao opened this issue Oct 27, 2016 · 0 comments
Open

面向对象的编程方式总结。 #13

Kelichao opened this issue Oct 27, 2016 · 0 comments
Labels

Comments

@Kelichao
Copy link
Owner

Kelichao commented Oct 27, 2016

对象对象的编程方式

  • 工厂模式
  • 构造函数式
  • 原型模式
  • 组合使用构造函数式和原型模式
  • 动态原型模式
  • 寄生构造函数模式
  • 稳妥构造函数模式

对象如何存在浏览器内存的方式。

对象被new或者创造的时候,从堆区开辟了一个空间地址,来存放它的数据,通过x,y两个栈记录它的堆地址空间,在访问x,y的时候其实是指向堆空间来进行操作的。

var x = y = {
    a:1
}
x.b=2;
y.c=3;// Object {a: 1, b: 2, c: 3}

x=null;
y// Object {a: 1, b: 2, c: 3}

工厂模式

function createObject(name) {
    var obj =new Object();
    obj.name =name;
    return obj;
}

var p1 = createObject("Bob");
console.log(p1.constructor);// constructor构造器,通俗的将,就是对象是属于什么类。
/*
    输出
    function Object() { [native code] }
*/

但是工厂模式的缺点是没有解决对象识别问题,
p1.constructor始终是指向function Object() { [native code] }
因此无法知道一个对象的类型。

构造函数模式

function Person(name) {
    this.name = name;
}
var p1 = new Person("Bob");

console.log(p1.constructor);// constructor构造器
/*
    输出
    Person(name) {
        this.name = name;
    }
*/

与工厂模式相比,p1是属于Person类的,这点正是胜过工厂模式的地方。

注意点
console.log(Person.constructor.constructor);// function Function() { [native code] }
说明当执行一个function Person(){}函数的时候,实际上是new了一个Function构造器

var x = new Function("\
    var a=1;\n\
    console.log(a)\n\
    return a;");
console.log(x);// function anonymous(){........} 显示一个匿名函数

var x = function() {
    var a = 1;
    return a;
}
console.log(x);// function (){........} 与上面的差别是少了匿名函数这几个字

原型模式

//原型模式
function Person() {}
Person.prototype.say = function() {
    console.log("Bob");
};
var p1 = new Person().say(); // ->Bob

有一个连接存在于实例与构造函数的原型对象之间

  • Apple是构造函数
  • prototype是构造函数的原型对象
    image

验证实例与构造函数的原型对象之间是否有关联

  • Person.prototype.isPrototypeOf(p1);// true
  • Object.getPrototypeOf(p1)// Person.prototype
  • p1._ proto _// Person.prototype

检验对象的一个属性是否是属于原型对象

  • p1.hasOwnProperty("a");// a是实例的属性返回true, a是构造函数的属性返回false

所以在使用for in循环的时候需要注意,该方法会把实例属性,以及原型对象属性全部列出来

function Person() {
    this.a=1;
}
Person.prototype.b=2;

var p1 = new Person();
var arr =[];
for (var i in p1) {
    arr.push(p1[i]);
}
console.log(arr);// [1, 2]

由于没有直接测定是否属性在实例的原型链上的方法

function hasPrototypeProperty(obj, name) {

    //  原型链上的属性 =!(对象有这个属性 && 是实例的属性)
    return !((name in obj) && (obj.hasOwnProperty(name)));
}

原型链的动态性

由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来
所以:new对象的时候,他是根据当前的prototype对象地址来进行引用的

/*高级编程书P 156*/

// 定义一个类/构造函数
function Person() {};

var firend = new Person();

// 在实例化对象之后更改原型链的某个方法
Person.prototype.say = function() {
    alert("hi");
};

// 可以得到新加的函数
firend.say();// "hi"
  • 两种方式的举例
// 解析原型的动态性
// 定义一个类/构造函数
function Person() {};

// 记录一开始的prototype对象,
// 函数一旦执行就会拥有这个原型链对象
var before = Person.prototype;

// new的时候,实例的指针跟随当前的原型
//所以在new之前随便改变原型,对实例无其他影响
var p1 = new Person();
console.log(before.isPrototypeOf(p1));// true  原型链是before

// new的时候,实例的指针指向当前的原型
// 而不是指向构造函数的原型对象时
var p2 = new Person();
var after = Person.prototype = {};
console.log(after.isPrototypeOf(p2));// true  原型链变成after了
  • prototype原型对象与new实例化对象的先后顺序
function Person(){
    this.name = "hello";
    this.age = 88;

    // 如果没有say方法
   // 这里能够充分看出,实例对于Person.prototype原型对象的取得
   // 是在把整个构造函数运行完毕后才赋予的
  // 如果在构造函数内部就把prototype地址更改了,就属于在new之前更改原型对象
    if(typeof this.say != "function"){
        Person.prototype = {
            constructor: Person,
            say: function(){
                return this.name;
            }
        };
    }
}

var p1 = new Person();
console.log(p1.say());// 报错

组合使用构造函数模式和原型模式

    function Person(name) {

    	//通过构造函数模式,传递参数。 
    	this.name = name;
    }
    Person.prototype = {

    	/*
    	 * 构造器
		 * 没有这个属性也可以通过instanceof返回正确的类型
		 * 但无法通过construcor确定对象的类型了
		 * 如果真的很重要,可以这样进行设回
    	 */
    	constructor: Person,
    	sayName: function() {
    		console.log(this.name);
    	}
    };

动态原型模式

看起来更加的结实,感觉是一个整体一般。

	function Person(name) {

		//通过构造函数模式,传递参数。 
		this.name = name;
		if(typeof this.sayName !== "function") {
			Person.prototype.sayName = function() {
					console.log(this.name);
				};
		}
	}

	var p1 = new Person('Bob');
	var p2 = new Person("lily");

	console.log(Object.getPrototypeOf(p1) === Object.getPrototypeOf(p2));// true

但是需要注意的点是,这种形式不能用字面量重写原型!

    function Person(name) {

    	//通过构造函数模式,传递参数。 
    	this.name = name;
    	if(typeof this.sayName !== "function") {

        // 用字面量重写了原型对象,导致切断了实例与新原型之间的联系。
        // 所以这个从侧面反映出,原型对象指针的赋予是在new的最开始处赋值的,在执行这个函数体之前
    		Person.prototype = {
    			constructor: Person,
    			sayName: function() {
    				console.log(this.name);
    			}
    		};
    	}
    }

    var p1 = new Person('Bob');
    var p2 = new Person("lily");

    console.log(Object.getPrototypeOf(p1) === Object.getPrototypeOf(p2));// false

原型链关系的方法汇总

以下面的Person为例

function Person() {
    this.a = 1;
}
Person.prototype.b = 2;

var p1 = new Person();

Object对象方法

  • Object.getOwnPropertyDescriptor(p1,"a")// 取得对象的属性值
  • Object.getPropertypeOf(p1)// 取得p1实例的原型对象属性即为p1._ _ proto _ _ ( Person.prototype)
  • Object.getOwnPropertyNames(p1)// 返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组(_ _ proto_ _属性除外),与Object.key()不同的是,key方法返回的是可枚举属性。
Object.getOwnPropertyDescriptor(p1,"a");// Object {value: 1, writable: true, enumerable: true, configurable: true}
Object.getPrototypeOf(p1)// Object {b: 2}
Object.getOwnPropertyNames(p1)// ["a"]
Object.getOwnPropertyNames(Person.prototype)// ["constructor", "b"]

原型对象上的方法

  • Person.prototype.isPrototypeOf(p1)// p1实例的原型对象指向是否是A的原型对象

Person.prototype.isPrototypeOf(p1)// true

实例上的方法

  • p1.hasOwnProperty(a)// true 实例本身,false该属性不在实例本身上

p1.hasOwnProperty(a)// true

@Kelichao Kelichao changed the title 关于对象是如何存在的 面向对象的编程方式。 Oct 28, 2016
@Kelichao Kelichao changed the title 面向对象的编程方式。 面向对象的编程方式总结。 Oct 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant