// 原型对象 var Student = { name: 'Robot', height: 1.2, run: function(){ console.log(this.name + ' is running') } }; function createStudent(name){ // 基于Student原型创建一个新对象 var s = Object.create(Student); // 初始化新对象 s.name = name; return s; } var xiaoming = createStudent('xiaozhu'); xiaoming.run(); // xiaozhu is running console.log(xiaoming.height); // 1.2 console.log(xiaoming.__proto__ === Student); // true
创建对象
javascript对每个创建的对象都会设置一个原型,指向它的原型对象。
当我们用 obj.xxx 访问一个对象的属性时,js引擎先再当前对象上查找该属性,如果没找到,就到其原型对象上查找,如果还没有找到,就一直上溯到Object.prototype 对象, 然后,如果还没有找到,就只能返回undefined。
例如:创建一个Array对象:
var arr = [1,2,3]
其原型链是:
arr ---> Array.prototype ---> Object.prototype ---> null
Array.prototype 定义了indexOf()、shift() 等方法,因此可以在所有的Array对象上直接调用这些方法。
当我们创建一个函数时:
function foo() { return 0; }
函数也是一个对象,它的原型链是
foo ---> Function.prototype ---> Object.prototype ---> null
Function.prototype 定义了 apply() 等方法,因此,所有函数都可以调用apply() 方法。
构造函数
除了直接用{...} 创建一个对象外,js还可以使用一种构造函数的方法来创建对象。 先定义一个构造函数:
function Student(name){ this.name = name; this.hello = function(){ console.log('Hello ' + this.name + '!') } }
在js中,可以用关键字 new 来调用这个函数,并返回一个对象:
var xiaoming = new Student('小明'); xiaoming.name; // 小明 xiaoming.hello(); // Hello, 小明!
注意: 如果不写 new ,这就是一个普通函数,它返回undefined, 但是。如果写了new ,它就变成了一个构造函数,它绑定的this 指向了新创建的对象,并默认返回this。 也就是说,不需要在最后写 return this;
新创建的xiaoming的原型链是:
xiaoming---> Student.prototype ---> Object.ptototype ---> null
再创建xiaohong、xiaojun,那么这些对象的原型与xiaoming是一样的:
xiaoming ↘ xiaohong -→ Student.prototype ----> Object.prototype ----> null xiaojun ↗
不过有个小问题:
xiaoming.name; // '小明' xiaohong.name; // '小红' xiaoming.hello; // function: Student.hello() xiaohong.hello; // function: Student.hello() xiaoming.hello === xiaohong.hello; // false
xiaoming 和 xiaohong各自的name不同,这是对的,否则我们取法区分谁是谁了。
xiaoming和xiaohong各自的hello是一个函数,但它们是两个不同的函数,虽然函数名称和代码都是相同的!
如果我们通过new Student() 创建了很多对象,这些对象的hello 函数实际上只需要共享同一个函数就可以了,这样可以节省很多内存。
修改代码如下:
function Student(name) { this.name = name; }
// 公共方法 Student.prototype.hello = function (){ console.log(`Hello ${this.name}`) }
为了区分普通函数和构造函数,按照约定,构造函数首字母应当大写,而普通函数首字母应当小写。
我们还可以编写一个createSdtudent() 函数。在内部封装所有的new操作。一个常用的编程模式:
function Student(props) { this.name = props.name || '匿名'; // 默认值为’匿名‘ this.age = props.age || 18; // 默认值为18 } Student.prototype.hello = function(){ console.log(`Hello ${this.name}`) } function createStudent(props){ return new Student(props || {}) } var xiaozhu = createStudent({ name: 'xiaozhu' }) console.log(xiaozhu.age); // 18 xiaozhu.hello(); // Hello xiaozhu var xiaoli = createStudent({ name: 'xiaoli', age: 20 }) console.log(xiaoli.name); // xiaoli xiaoli.hello(); // Hello xiaoli
浙公网安备 33010602011771号