1. 객체지향 팩토리 방식
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson("Nicholas", 29, "Software Engineer"); var person2 = createPerson("Greg", 27, "Doctor"); person1.sayName(); //"Nicholas" person2.sayName(); //"Greg"
팩토리 모델 방식의 단점은 중복 코드가 많이 생성된다는 점이에요!
2. 생성자 패턴은 객체를 생성합니다
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); person1.sayName(); //"Nicholas" person2.sayName(); //"Greg" alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true alert(person2 instanceof Object); //true alert(person2 instanceof Person); //true alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true alert(person1.sayName == person2.sayName); //false
new 키워드를 이용하여 객체를 생성하면 다음과 같은 4가지 과정을 거치게 됩니다
3. 생성자를 함수로 사용
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person = new Person("Nicholas", 29, "Software Engineer"); person.sayName(); //"Nicholas" Person("Greg", 27, "Doctor"); //adds to window window.sayName(); //"Greg" var o = new Object(); Person.call(o, "Kristen", 25, "Nurse"); o.sayName(); //"Kristen"
함수로 사용하는 경우 생성자는 일반 함수와 다르지 않으며 단지 window 객체 아래에 추가된 메소드일 뿐입니다. 생성자에 의해 생성된 객체는 실제로 새로운 객체를 생성하기 때문에 둘은 본질적으로 다르고 분리되어 있으며, 메소드도 여전히 다릅니다!
4. 공통된 방법을 사용하여 전 세계적으로 일관성이 없는 문제를 해결합니다
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); person1.sayName(); //"Nicholas" person2.sayName(); //"Greg" alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true alert(person2 instanceof Object); //true alert(person2 instanceof Person); //true alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true alert(person1.sayName == person2.sayName); //true
위 방법으로 동일한 문제를 해결하더라도 정의된 전역 메서드 자체가 창에 속하므로 로컬과 글로벌이 구분되지 않습니다! 그래서 이 방법은 거의 사용되지 않습니다! 권장되지 않습니다.
5. 프로토타입 모드
우리가 만드는 모든 함수에는 프로토타입 개체가 있습니다. 이 속성은 개체를 가리키는 포인터이며, 이 개체의 기능은 특정 유형의 모든 인스턴스에서 공유할 수 있는 메서드를 갖는 것입니다.
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true alert(Person.prototype.isPrototypeOf(person1)); //true alert(Person.prototype.isPrototypeOf(person2)); //true //only works if Object.getPrototypeOf() is available if (Object.getPrototypeOf){ alert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name); //"Nicholas" }
프로토타입 이해
함수가 생성될 때마다 함수의 프로토타입 객체를 가리키는 프로토타입 속성이 생성됩니다. 기본적으로 프로토타입 객체에는 프로토타입 속성이 있는 함수에 대한 포인터가 포함된 생성자(생성자 속성)가 포함됩니다!
속성 읽는 순서
코드가 개체의 속성을 읽을 때마다 검색이 수행됩니다. 대상은 개체 자체의 인스턴스에서 시작됩니다. 그렇지 않은 경우 프로토타입 체인의 가장 바깥쪽 레이어가 검색될 때까지 계속해서 객체를 검색합니다.
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //"Greg" 来自实例 alert(person2.name); //"Nicholas" 来自原型
이 요소의 인스턴스 속성이 삭제되는 경우
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //"Greg" ?from instance alert(person2.name); //"Nicholas" ?from prototype delete person1.name; alert(person1.name); //"Nicholas" - from the prototype
6. hasOwnProperty 메소드
이 방법을 사용하면 속성이 인스턴스에 있는지 프로토타입에 있는지 감지할 수 있습니다! hasOwnProperty는 Object에서 상속되며 지정된 속성이 객체 인스턴스에 존재하는 한 true를 반환합니다.
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); alert(person1.hasOwnProperty("name")); //false alert("name" in person1); //true person1.name = "Greg"; alert(person1.name); //"Greg" ?from instance alert(person1.hasOwnProperty("name")); //true alert("name" in person1); //true alert(person2.name); //"Nicholas" ?from prototype alert(person2.hasOwnProperty("name")); //false alert("name" in person2); //true delete person1.name; alert(person1.name); //"Nicholas" - from the prototype alert(person1.hasOwnProperty("name")); //false alert("name" in person1); //true
7. Object.keys() 열거형 속성 메서드
이 메소드는 객체를 매개변수로 받고 열거 가능한 모든 속성을 포함하는 문자열 배열을 반환합니다
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var keys = Object.keys(Person.prototype); alert(keys); //"name,age,job,sayName" 如果想得到所有实例的属性,无论它是否可以枚举都可以使用这个方法来获取 function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var keys = Object.getOwnPropertyNames(Person.prototype); alert(keys); //"constructor,name,age,job,sayName"
이 방법은 상위 버전의 브라우저에서만 지원됩니다
8.간단한 프로토타입 작성 방법
function Person(){ } Person.prototype = { name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } }; var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //false alert(friend.constructor == Object); //true
프로토타입을 다시 작성하는 것은 기본 프로토타입 메서드를 덮어쓰는 것과 같습니다. 그런 다음 동일한 구성 메서드도 다시 작성되고 다시 작성된 구성 메서드는 Object 객체를 가리킵니다! 원래 개체 대신 Person
여전히 이전 생성자를 가리키고 싶다면 명시적으로 지정할 수 있습니다.
function Person(){ } Person.prototype = { constructor : Person, name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } }; var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //true alert(friend.constructor == Object); //false
9. 프로토타입 방식의 동적 추가
function Person(){ } Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", sayName : function () { alert(this.name); } }; var friend = new Person(); Person.prototype.sayHi = function(){ alert("hi"); }; friend.sayHi(); //"hi" ?works!
10. 네이티브 객체의 프로토타입 방법
alert(typeof Array.prototype.sort); //"function" alert(typeof String.prototype.substring); //"function" String.prototype.startsWith = function (text) {//修改原生对象的原型方法 return this.indexOf(text) == 0; }; var msg = "Hello world!"; alert(msg.startsWith("Hello")); //true
11. 생성자와 프로토타입 패턴의 조합을 사용하여 객체 생성
//构造函数模式 function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby", "Court"]; } //原型模式 Person.prototype = { constructor: Person, sayName : function () { alert(this.name); } }; var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court" alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName); //true
12. 다이내믹 프로토타입 모드
function Person(name, age, job){ //properties this.name = name; this.age = age; this.job = job; //methods if (typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); }; } } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName();
13. 기생 생성자 패턴
function Person(name, age, job){ var o = new Object();//依赖全局对象初始化一个对象,然后再返回这个对象 o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName(); //"Nicholas" function SpecialArray(){ //create the array var values = new Array(); //add the values values.push.apply(values, arguments); //assign the method values.toPipedString = function(){ return this.join("|"); }; //return it return values; } var colors = new SpecialArray("red", "blue", "green"); alert(colors.toPipedString()); //"red|blue|green" alert(colors instanceof SpecialArray);
어필 메소드에 대해 조금 설명하자면, 새로운 객체를 생성하기 위해 외부 객체에 의존하기 때문에 속성과 메소드의 소스를 결정하기 위해 인스턴스 오브 메소드에 의존할 수 없습니다! 실제로 생성자와는 아무런 관련이 없습니다!
14. 안전한 생성자 패턴
function Person(name, age, job){ var o = new Object(); o.sayName = function(){ alert(name); }; return o; } var friend = Person("Nicholas", 29, "Software Engineer"); friend.sayName(); //"Nicholas"
이 방법은 새로운 this 키워드에 의존하지 않습니다! 객체의 메소드와 속성에 접근하고 싶다면 객체가 정의한 메소드를 통해서만 얻을 수 있습니다!
15. 상속
자바스크립트는 프로토타입 체인을 통해 상속을 구현합니다
function SuperType(){ this.property = true;//定义一个属性 } SuperType.prototype.getSuperValue = function(){//定义的原型方法 return this.property; }; function SubType(){ this.subproperty = false; } //inherit from SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true alert(Object.prototype.isPrototypeOf(instance)); //true alert(SuperType.prototype.isPrototypeOf(instance)); //true alert(SubType.prototype.isPrototypeOf(instance)); //true SubType继承SuperType的方法和属性,因此当instance可以直接调用SuperType的方法! function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //inherit from SuperType SubType.prototype = new SuperType(); //new method SubType.prototype.getSubValue = function (){ return this.subproperty; }; //override existing method SubType.prototype.getSuperValue = function (){ return false; }; var instance = new SubType(); alert(instance.getSuperValue()); //false
위의 예는 재정의된 프로토타입이 이전에 상속된 프로토타입을 덮어쓰고 반환된 최종 결과가 예상한 효과가 아닌 경우가 많다는 것을 보여줍니다
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //inherit from SuperType SubType.prototype = new SuperType(); //使用字面量添加的方法导致上面的方法失效了 SubType.prototype = { getSubValue : function (){ return this.subproperty; }, someOtherMethod : function (){ return false; } }; var instance = new SubType(); console.log(instance); alert(instance.getSuperValue()); //error!
다음 예에서는 프로토타입 재작성의 위험도 보여줍니다
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ } //inherit from SuperType SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green,black"
原型共享导致两个不同的对象调用的同一个数据
16、借用构造函数来实现继承
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ //inherit from SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green"
传递参数
function SuperType(name){ this.name = name; } function SubType(){ //inherit from SuperType passing in an argument SuperType.call(this, "Nicholas"); //instance property this.age = 29; } var instance = new SubType(); alert(instance.name); //"Nicholas"; alert(instance.age); //29
17、组合继承方式
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; }
18、原型继承
function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob");
19、寄生组合式继承
function object(o){ function F(){} F.prototype = o; return new F(); } function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); //create object prototype.constructor = subType; //augment object subType.prototype = prototype; //assign object } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27
以上就是今天的javascript学习小结,之后每天还会继续更新,希望大家继续关注。