Q&A:
1. 继承有什么作用?
- 概念:继承是指一个对象直接使用另一个对象的属性和方法。
- 作用:继承划分了类的层次性,父类代表的是更一般、更泛化的类,而子类则是更为具体、更为细化;继承是实现代码重用、扩展软件功能的重要手段,子类中与父类完全相同的属性和方法不必重写,只需写出新增或改写的内容,这就是说子类可以复用父类的内容,不必一切从零开始。
2. 有几种常见创建对象的方式? 举例说明?
- 单一接口创建(Object构造函数或字面量创建):
var obj1 = new Object();
var obj2 = {};
- 工厂模式(函数封装单一接口创建对象的细节):
function createPerson(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayName = function() {
console.log(this.name);
};
return obj;
}
var p1 = createPerson('kevin', 24);
var p2 = createPerson('zhao', 23);
通过在函数中创建一个新对象,将具体细节添加到新对象,最后返回出新对象的过程,解决单一接口创建对象的大量重复代码,但是仍有很多问题,因此有后面介绍的新模式出现。
- 构造函数模式(形式类似原生构造函数的自定义构造函数):
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
};
}
var p1 = new Person('kevin', 24);
var p2 = new Person('zhao', 23);
构造函数模式相比于工厂模式,能够解决对象识别的问题(知道一个对象的类型),但是每个实例中的方法是不一样的,每个sayName()相当于new Function()创建的新方法,这样完全没必要,所以下面介绍原型模式。
- 原型模式:
function Person() {}
Person.prototype.name = 'kevin';
Person.prototype.age = 24;
Person.prototype.sayName = function() {
console.log(this.name);
};
var p1 = new Person();
p1.sayName(); // 'kevin'
var p2 = new Person();
p2.sayName(); // 'kevin'
原型模式解决了属性和方法共享的问题,但是也正因为共享,使得引用类型属性容易出现问题,在例子中,若name是一个数组对象属性,则p1中使用push添加数组项则在p2中的数组也跟着改变,所以有了下面的方法。
- 组合使用构造函数模式和原型模式:
function Person(name, age) {
this.name = name;
this.age = age;
this.friends = ['john', 'hunger'];
}
Person.prototype.sayName = function() {
console.log(this.name);
}
var p1 = new Person('kevin', 24);
var p2 = new Person('zhao', 23);
这种方法,每个实例都拥有自己的属性,即使在p2中更改name属性也不会影响p1的属性,而方法则添加在原型中,实现共用方法,这种混成的模式取得了两者的优点,是目前认同度最高的一种创建自定义类型的方法。
3. 下面两种写法有什么区别?
<script>
//方法1
function People(name, sex) {
this.name = name;
this.sex = sex;
this.printName = function() {
console.log(this.name);
}
}
var p1 = new People('饥人谷', 2);
//方法2
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function() {
console.log(this.name);
}
var p2 = new Person('若愚', 27);
</script>
- 第一种方法是上面所讲的构造函数模式,每创建一个实例,其中的printName()方法就会通过new Function()创建一次,所以每个实例拥有一个新方法,这是种资源的浪费;
- 第二种方法是混合模式,将属性设置在构造函数中,而将需要共用的方法绑定在原型上,相比于第一种模式,这种模式更加实用。
4. Object.create有什么作用?兼容性如何?如何使用?
-
Object.create作用:
Object.create()方法创建一个拥有指定原型和若干个指定属性的对象。 -
兼容性:
Object.create是ES5引入的方法,在IE9中严格模式不适用,在其他浏览器部分版本,parseInt方法配合使用上会出现问题(忽略前导0),不过主流PC浏览器兼容性良好。
- 使用:
function Person() {} //创建空构造函数
Person.prototype.name = 'kevin'; //原型绑定属性
var p1 = Object.create(Person.prototype); // 创建只继承原型的实例
var p2 = Object.create(Person.prototype, { //创建继承原型,同时含有自身属性的实例
age: {
value: 24
},
name: {
value: 'zhao'
}
});
5. hasOwnProperty有什么作用? 如何使用?
- 作用:判断一个对象是否包含自定义属性而不是原型上的属性;
-
使用:
还是按照上一个问题的例子:
6. 实现Object.create的 polyfill,如:(ps: 写个 函数create,实现 Object.create 的功能)
// 第一步:判断浏览器是否支持Object.create
if(typeof Object.create != 'function') {
// 第二步:若不支持Object.create,则创建Polyfill
Object.create = (function() {
function Temp = () {} // 创建临时保存原型的函数
var hasOwn = Object.prototype.hasOwnProperty; // 保存hasOwnProperty方法,方便之后使用
return function(o) {
if(typeof o != 'object') { // 判断第一个原型参数类型
throw TypeError('原型参数必须是一个对象或者null');
} else {
Temp.prototype = o; // 将原型绑定在临时对象上
var obj = new Temp(); // 创建要返回的新对象
o = null; // 清空杂散参数对象
if(arguments.length > 1) { // 判断是否含有第二个属性参数
var Properties = Object(arguments[1]); // 创建含有这些属性的对象
for(var prop in Properties) { // 遍历对象中的属性
if(hasOwn.call(Properties, prop)) { // 将对象自身描述符绑定的属性筛选
obj[prop] = obj[prop]; // 绑定在obj上
}
}
}
return obj; // 返回obj
}
};
})();
}
7. 如下代码中call的作用是什么?
<script>
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
function Male(name, sex, age) {
Person.call(this, name, sex);
this.age = age;
}
</script>
- 作用:在Male函数中,调用Person函数,使Male函数能够执行Person上的初始化代码,实现构造函数继承。
8. 补全代码,实现继承
function Person(name, sex) {
// todo...
}
Person.prototype.getName = function() {
//todo...
};
function Male(name, sex, age) {
//todo...
}
//todo...
Male.prototype.getAge = function() {
//todo...
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();
- 实现继承:
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function() {
console.log(this.name);
};
function Male(name, sex, age) {
Person.call(this, name, sex);
this.age = age;
}
// 寄生方法:
// function inheritPrototype(subType, superType) {
// function F() {}
// F.prototype = superType.prototype;
// var prototype = new F();
// prototype.constructor = subType;
// subType.prototype = prototype;
// }
//
// inheritPrototype(Male, Person);
// Object.create方法
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.getAge = function() {
console.log(this.age);
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();
Coding:
1. 实现如下dialog 弹窗功能
//功能描述:
// 1. 可使用 dialog.open() 去打开弹窗
// 2. 当点击确定、取消时可使用用户自定义事件
// 3. dialog 可拖动
// 4. 允许页面展示多个 dialog
function Dialog() {
//todo...
}
var tpl = '<ul><li>列表1</li><li>列表2</li><li>列表1</li><li>列表1</li></ul>';
$('#open4').on('click', function() {
var dialog4 = new Dialog();
dialog4.open({
title: '欢迎来到饥人谷',
message: tpl,
isShowCloseBtn: true,
isShowConfirmBtn: true,
onClose: function() {
alert('close');
},
onConfirm: function() {
alert('确定');
}
});
});
2. 实现如下一个日历组件
<input class="date-ipt" type="text" placeholder="有初始值" date-init="2016/05/31" />
<input class="date-ipt" type="text" placeholder="无初始值" />
<script>
// 使用
$('.date-ipt').datePicker();
</script>
本文归本人和饥人谷所有,如需转载请注明出处