一、问题
(一)、继承有什么作用?
通过继承可以继承原有函数的一些属性和方法,避免重复定义一些属性和方法,举个例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<script>
function Person(name) {
this.name=name;
console.log(this.name)
}
Person.prototype.sayHi=function () {
console.log("Hi! my name is:"+this.name)
};
Person.prototype.sayEyesNum=function () {
console.log("I have two eyes.")
};
function Students(name) {
this.name=name;
Person.call(this,name)
}
Students.prototype=Object.create(Person.prototype); //这里一定要注意
//与Students.prototype.sayHi 间的顺序,Students.prototype.sayHi应该在后面,否则其会被覆盖掉!!
Students.prototype.constructor=Students;
Students.prototype.sayHi=function () {
console.log("Hi! I am student and my name is"+this.name)
};
Students.prototype.sayTeacherName=function () {
console.log("My Teacher's name is Wang")
};
var p1=new Person("ren"),
stu1=new Students("xue");
</script>
</body>
</html>
上述代码中,我先定义了一个Person的函数,且在该函数属性上绑定sayEyesNum()这个方法,然后我通过继承的方法,使得Students函数也具有了sayEyesNum()这个方法,而无需重新在Students函数上绑定sayEyesNum()这个方法。
(二)、有几种常见创建对象的方式? 举例说明?
- 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"
构造函数的主要问题是每个方法都会在每个实例上创建一遍。
- 3、原型模式
function Person(){
}
Person.prototype = {
constructor: Person,
name: "Nicholas",
age: 29,
job: "software Engineer",
friends: ["Shelby","Court"],
sayName: function() {
alert(this.name);
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true
原型模式虽然解决了上述几个问题,但是有时候我们需要某个实例要有自己的方法和属性。因此出现了运用最广泛的组合模式
- 4、组合使用构造函数模式和原型模式
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
该组合模式中,构造函数用于定义实例属性,原型用于定义方法和共享属性;
- 5、动态原型模式
function Person( name, age, job ) {
//属性
this.name = name;
this.age = age;
this.job = job;
//方法
if( typeof this.sayName != "function" ) {
Person.prototype.sayName = function() {
alert(this.name);
}
}
}
var person = new Person("Nicholas", 29, "software Engineer");
person.sayName();
- 6、寄生构造函数模式
function SpecialArray() {
//创建数组
var values = new Array();
//添加值
values.push.apply(values,arguments);
//添加新方法
values.toPipedString = function(){
return this.join("|");
};
//返回数组
return values;
}
var colors = new SpecialArray("red","blue","green");
alert(colors.toPipedString()); //"red|blue|green"
返回的对象与构造函数或者与构造函数的原型之间没有关系;不能依赖instanceof操作符来确定对象的类型。由于存在上述问题,我们建议在可以使用其他模式的情况下,不要使用这种模式。
- 7、稳妥构造函数模式
function Person( name, age, job ) {
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function() {
alert(name);
};
//返回对象
return o;
}
var person = Person("Nicholas", 29, "software Engineer");
Person.sayName(); //"Nicholas"
与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间也没什么关系, 因此instanceof操作符对这种对象没有意义。
(三)、下面两种写法有什么区别?
//方法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 p1 = new Person('若愚', 27);
通过第一种方式,People的printName方法是在函数People实例对象里的,因此当后面再新建一个People的实例对象时,又会创建一个printName方法,而不能够像第二种方式那样可以在People函数的属性上共用printName方法,不利于节省空间。
(四)、Object.create 有什么作用?兼容性如何?如何使用?
Object.create的作用是创建一个指定原型和若干个指定属性的对象。
由于Object.create是在ES5后出现的,因此如下浏览器才支持:
桌面端 移动端
它的语法如下:
Object.create(proto, [ propertiesObject ])
- proto 一个对象: 作为新创建的对象的原型;
- propertiesObject 可选。该参数对象是一组属性与值,该对象的名称将是新建对象的属性名称,值是描述性属性符。值得注意的是该参数对象不能是undefined,另外该对象自身所拥有的可枚举的属性才有效,也就是说其原型链上的属性是无效的。
举个例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<script>
var o;
o = Object.create({}, { p: { value: 42 } });
// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 24;
o.p //42
o.A = 12;
for (var prop in o) {
console.log(prop)
}
//"A"
delete o.p;
//false
</script>
</body>
</html>
(五)、hasOwnProperty有什么作用? 如何使用?
用来判断某个对象是否含有指定的自身属性。其与in运算符不同,hasOwnProperty会忽略掉原型链上继承到的属性。
其使用语法为obj.hasOwnProperty(prop)
- prop 为要检测的属性名;
举个例子:
<script>
var car={};
car.name="bench";
</script>
从原型链上继承的属性被忽略了
(六)、实现Object.create的 polyfill,如:(ps: 写个 函数create,实现 Object.create 的功能)
var obj = {a: 1, b:2};
var obj2 = create(obj);
console.log(obj2.a); //1
简单模拟:
function create(obj) {
function Tem() {}
Tem.prototype=obj;
return new Tem()
}
真实模拟:
if (typeof Object.create != 'function') {
// Production steps of ECMA-262, Edition 5, 15.2.3.5
// Reference: http://es5.github.io/#x15.2.3.5
Object.create = (function() {
//为了节省内存,使用一个共享的构造器
function Temp() {}
// 使用 Object.prototype.hasOwnProperty 更安全的引用
var hasOwn = Object.prototype.hasOwnProperty;
return function (O) {
// 1. 如果 O 不是 Object 或 null,抛出一个 TypeError 异常。
if (typeof O != 'object') {
throw TypeError('Object prototype may only be an Object or null');
}
// 2. 使创建的一个新的对象为 obj ,就和通过
// new Object() 表达式创建一个新对象一样,
// Object是标准内置的构造器名
// 3. 设置 obj 的内部属性 [[Prototype]] 为 O。
Temp.prototype = O;
var obj = new Temp();
Temp.prototype = null; // 不要保持一个 O 的杂散引用(a stray reference)...
// 4. 如果存在参数 Properties ,而不是 undefined ,
// 那么就把参数的自身属性添加到 obj 上,就像调用
// 携带obj ,Properties两个参数的标准内置函数
// Object.defineProperties() 一样。
if (arguments.length > 1) {
// Object.defineProperties does ToObject on its first argument.
var Properties = Object(arguments[1]);
for (var prop in Properties) {
if (hasOwn.call(Properties, prop)) {
obj[prop] = Properties[prop];
}
}
}
// 5. 返回 obj
return obj;
};
})();
}
(七)、如下代码中call的作用是什么?
function Person(name, sex){
this.name = name;
this.sex = sex;
}
function Male(name, sex, age){
Person.call(this, name, sex); //这里的 call 有什么作用
this.age = age;
}
这里call的作用是在函数Male的运行环境中运行Person函数,让函数Male继承了Person函数的属性和方法;
(八)、补全代码,实现继承
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.getName = function(){
return (this.name)
};
function Male(name, sex, age){
this.name=name;
this.sex=sex;
this.age=age;
}
Person.prototype.printName=function () {
console.log(this.name)
};
Male.prototype=Object.create(Person.prototype);
Male.prototype.constructor=Male;
Male.prototype.getAge = function(){
return (this.age)
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();
二、代码
(一)、实现如下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('确定');
}
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
position: relative;
}
.dialog{
border-radius: 5px;
background-color:#eee ;
box-shadow:0 0 5px 2px rgba(0, 0, 0, 0.5);
position: absolute;
top: 30%;
left: 50%;
width: 328px;
}
.title{
background-color: #676666;
padding: 8px 10px;
color: #fff;
font-weight: bolder;
}
.clearfix:after{
display: block;
clear: both;
content: "";
}
a{
text-align: center;
text-decoration: none;
}
.button a{
background-color: #e33100;
padding: 5px 8px;
border-radius: 5px;
margin-left: 10px;
margin-right: 10px;
color: #fff;
}
.button{
padding: 20px 0;
text-align: center;
}
.title a{
float: right;
width: 10px;
color: #fff;
}
.content{
color:#666 ;
padding: 10px;
}
.draggable{
cursor: move;
opacity: 0.8;
}
</style>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<button id="open1">打开1</button>
<button id="open2">打开2</button>
<button id="open3">打开3</button>
<button id="open4">打开4</button>
<button id="open5">打开5</button>
<p>鼠标在 dialog 上左键按下可拖动 dialog</p>
<p>可创建多个 dialog</p>
<script>
//功能描述:
// 1. 可使用 dialog.open() 去打开弹窗
// 2. 当点击确定、取消时可使用用户自定义事件
// 3. dialog 可拖动
// 4. 允许页面展示多个 dialog
function Dialog(){
this.createDialog();
this.bindEvent();
}
Dialog.prototype={
originOpts:{
title:"",
message:"",
isShowCancelBtn:true,
isShowConfirmBtn:false,
onCancel:function () {
},
onConfirm:function () {
}
},
open:function (opts) {
this.setOpts(opts);
this.setDialog();
this.showDialog();
},
setOpts:function (opts) {
if (typeof opts==="string"){
this.opts=$.extend({},this.originOpts,{message:opts})
}else if (typeof opts==="object"){
this.opts=$.extend({},this.originOpts,opts)
}
},
setDialog:function () {
var $dialog=this.$dialog;
console.log($dialog);
if (!this.opts.title){
$dialog.find(".title").hide();
}else {
$dialog.find(".title").show();
}
if (!this.opts.isShowCancelBtn){
$dialog.find(".button .cancel").hide();
}else {
$dialog.find(".button .cancel").show();
}
if (!this.opts.isShowConfirmBtn){
$dialog.find(".confirm").hide();
}else {
$dialog.find(".confirm").show();
}
$dialog.find(".title span").text(this.opts.title);
$dialog.find(".content").html(this.opts.message);
},
showDialog:function () {
this.$dialog.show();
},
hideDialog:function () {
this.$dialog.hide();
},
createDialog:function () {
var tp1='<div class="dialog">'+'<div class="title clearfix"><span></span><a class="cancel" href="####">X</a></div>'+'<h3 class="content"></h3>'+'<div class="button"><a class="cancel" href="####">取消</a><a class="confirm" href="####">确定</a></div>'+'</div>';
this.$dialog=$(tp1);
$("body").append(this.$dialog);
},
bindEvent:function () {
var _this=this;
_this.$dialog.find(".cancel").on("click",function () {
_this.opts.onCancel();
_this.hideDialog();
});
_this.$dialog.find(".confirm").on("click",function () {
_this.opts.onConfirm();
_this.hideDialog();
});
_this.$dialog.on("mousedown",function (e) {
var $dialog=$(this),
evtX=e.pageX-$dialog.offset().left,
evtY=e.pageY-$dialog.offset().top;
$dialog.addClass("draggable").data("evtPos",{
x:evtX,
y:evtY
})
});
$("body").on("mousemove",function (e) {
$(".draggable").length && $(".draggable").offset({
top:e.pageY-$(".draggable").data("evtPos").y,
left:e.pageX-$(".draggable").data("evtPos").x
});
$("body").on("mouseup",function () {
$('.draggable').length && $('.draggable').removeClass('draggable').removeData('evtPos');
})
})
}
};
$('#open1').on('click', function() {
var dialog1 = new Dialog();
dialog1.open('hello, 这里是饥人谷');
});
$('#open2').on('click', function() {
var dialog2 = new Dialog();
dialog2.open('<a href="####">这里是链接</a>');
});
$('#open3').on('click',function(){
var dialog3 = new Dialog();
dialog3.open({
title: '欢迎来到饥人谷',
message: "hello",
isShowCancelBtn: true,
isShowConfirmBtn: true,
onCancel: function(){
alert('cancel')
},
onConfirm: function(){
alert('确定');
}
});
});
var tp1 = '<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: tp1,
isShowCancelBtn: true,
isShowConfirmBtn: true,
onCancel: function(){
alert('cancel')
},
onConfirm: function(){
alert('确定');
}
});
});
$('#open5').on('click',function(){
var dialog5 = new Dialog();
dialog5.open({
title: '欢迎来到饥人谷',
message: "hello",
isShowCancelBtn: false,
isShowConfirmBtn: false
});
});
</script>
</body>
</html>
(二)、实现如下一个日历组件 【Demo】
<input class="date-ipt" type="text" placeholder="有初始值" date-init="2016/05/31" />
<input class="date-ipt" type="text" placeholder="无初始值" />
<script>
// 使用
$('.date-ipt').datePicker();
</script>
**本文版权归本人即简书笔名:该账户已被查封 所有,如需转载请注明出处。谢谢! *
网友评论