js高级
1.关于对象
JS是面向对象的编程语言,对象其实就是属性和方法的集合体。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值,这个值可以是数据或函数。
创建对象一般有两种方法:
(1)创建一个Object实例
var person = new Object();
person.name = "zhangsan";
person.age = 22;
person.sayHi = function(){}
(2)使用对象字面量
var person = {
name: "zhangsan",
age: "22",
sayHi: function(){}
}
虽然上面两种方法都可以创建对象,但如果要创建很多对象,这样做就很不方便了。于是就有了工厂模式,构造函数模式,原型模式,组合使用构造函数模式和原型模式。
工厂模式基本淘汰了,不再赘述。说下构造函数模式:
function Person(name,age){
this.name = name;
this.age = age;
this.sayHi =function(){
console.log(this.name)
}
}
var person1 = new Person("a", 12);
var person2 = new Person("b", 14);
按照惯例,构造函数始终都应该以一个大写字母开头。
要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4步
(1) 创建一个新对象;new出对象
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
用构造函数模式创建对象的缺点主要是,每个方法都要在每个实例上重新创建一遍,而这是没有必要的。所以可以把构造函数内部的函数定义移到外面来。
function Person(name,age){
this.name = name;
this.age = age;
this.sayHi = sayHi
}
//在外面声明,不会反复创建
function sayHi(){
console.log(this.name)
}
var person1 = new Person("a", 12);
var person2 = new Person("b", 14);
并且用这种方法创建对象的方法,会比较耗内存,如果对象有很多方法,我们就需要定义多个全局函数,也就没有了封装性可言。
故我们引出了原型的概念
构造函数原型 prototype
构造函数通过原型分配的函数是所有对象所共享的。
js规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有的对象的实例就可以共享这些方法。
function Star(name, age) {
this.name = name;
this.age = age;
}
//这里要写=的形式,不能写sing(){}的形式
//给构造函数添加原型的方法
Star.prototype.sing = function() {
console.log("我会唱歌");
}
var ldh = new Star("刘德华", 11);
var zxy = new Star("张学友", 99);
ldh.sing();
zxy.sing();
原型是什么?
原型的作用是什么?
一般情况下,公共属性放到构造函数里面,公共方法要放到原型里面。
每个对象都有系统给添加的__proto__指向我们构造函数的原型对象
对象上的__proto__与构造函数的prototype是等价的。
方法的查找规则:首先看对象上是否有sing方法,如果没有这个方法,如果对象有__proto__就去构造函数原型对象prototype身上找。
原型的constructor
如果我们通过Start.prototype.方法名=function(){}
的形式进行修改原型对象。那我们得到的原型对象中会有constructor函数。此时无论实例化多少对象,对象中都会有原型对象中的constructor.
Star.prototype.sing = function() {
console.log("我会唱歌");
}
console.log(Star.prototype.constructor);
但是
如果我们要通过Start.prototype={方法名:function(){}}
对象的形式修改原型对象,则成成的原型对象中就没有了constructor函数。此时我们就得希望constructor指回原来的构造函数
Start.prototype={
**//手动指回原来的构造函数**
constructor:Start,
sing:function(){}
read:function(){}
}
console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor);`
都指向了构造函数
每个函数都有一个prototype属性,这个prototype属性就是我们的原型对象
每个对象都会有一个_proto_指向他的构造函数的原型对象
__proto__和prototype的区别
__proto__
:是实例对象指向原型对象的指针,隐式原型,是每个对象都会有的一个属性。指向构造函数的prototype。
prototype
:是构造函数的原型对象,显式原型,只有函数才会有,也是一个对象,也会有__proto__。
原型链
为什么要使用原型链呢?
1.为了实现继承,简化代码,实现代码重用!
2.只要是这个链条上的内容,都可以被访问和使用到!
原型链的特点
1、就近原则,当我们要使用一个值时,程序会优先查找离自己最近的,也就是本身有没有,如果自己没有,他就会沿着原型链向上查找,如果还没有找到,它还会沿着原型链继续向上查找,找到到达Object
2、引用类型,当我们使用或者修改原型链上的值时,其实使用的是同一个值!
3、JS中每个函数都存在原型对象属性prototype。并且所有函数的默认原型都是Object的实例。
4、每个继承父函数的实例对象都包含一个内部属性_proto_。该属性包含一个指针,指向父函数的prototype。若父函数的原型对象的_proto_属性为再上一层函数。在此过程中就形成了原型链。
原型链:通过__proto__串起来的链状对象结构,为了对象访问机制使用
无论通过什么形式添加,他都是通过对象的方式查找
Star.prototype.age = 18;
console.log(ldh.age)
//18
Object.prototype.age = 18;
console.log(ldh.age)
//18
如果对象本身有这个属性,那么优先使用对象的方法
原型对象里的this指向的都是实例对象
<script>
console.log(Array.prototype);
//向原型对象中追加一个方法
Array.prototype.sum = function() {
var sum = 0;
// 方法中的this指向的是调用此方法的对象
for (var i = 0; i < this.length; i++) {
sum = sum + this[i];
}
return sum;
}
var arr = [1, 2, 3];
console.log(arr.sum()); //6
// 此时原型对象中就多了一个sum()方法
console.log(Array.prototype);
</script>
ES6之前继承属性
ES6之前继承方法
函数
类
p38