缺点:继承了过多不必要的属性
// 父级
Professor.prototype = {
name: 'Zhang',
tSkill: 'JAVA'
}
function Professor() {}
var professor = new Professor();
// -------------分割线----------
// 子级
Teacher.prototype = professor;
function Teacher() {
this.name = 'Wang',
this.mSkill = 'JS'
}
var teacher = new Teacher();
// -------------分割线----------
// 孙子级
Student.prototype = teacher;
function Student() {
this.name = 'Li',
this.pSkill = 'HTML'
}
var student = new Student();
console.log(student);
缺点:无法继承借用构造函数的原型
Teacher.prototype.wife = 'Liu';
function Teacher(name, mSkill) {
this.name = name;
this.mSkill = mSkill;
}
function Student(name, mSkill, age, major) {
Teacher.apply(this, [name, mSkill]);
this.age = age;
this.major = major;
}
var student = new Student('Zhang', 'JS', 18, 'Computer');
console.log(student);
缺点:两个原型会相互影响,更改其中一个原型,更一个对应的原型也会被更改。
function Teacher() {
this.name = 'Li';
this.tSkill = 'Java';
}
Teacher.prototype = {
pSkill: 'JS'
}
var t = new Teacher();
console.log(t);
function Student() {
this.name = 'Wang';
}
Student.prototype = Teacher.prototype;
Student.prototype.age = 18;
var s = new Student();
console.log(s);
加中间缓冲对象,即可解决只继承父级的原型,而不继承构造属性
//父构造函数
function Teacher() {
this.name = 'Li';
this.tSkill = 'Java';
}
Teacher.prototype = {
pSkill: 'JS'
}
var t = new Teacher();
console.log(t);
// 中间对象缓冲
function Buffer() {}
Buffer.prototype = Teacher.prototype;
var buffer = new Buffer();
console.log(buffer);
// 子构造函数
function Student() {
this.name = 'Wang';
}
Student.prototype = buffer;
Student.prototype.age = 18;
var s = new Student();
console.log(s);
function inherit(Target, Origin) {
function Buffer(){}
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
// 还原构造器
Target.prototype.constructor = Target;
// 设置继承源
Target.prototype.super_class = Origin;
}
// 使用
function Teacher() {}
Teacher.prototype.name = "Zhang";
function Student() {}
inherit(Student, Teacher);
var t = new Teacher();
var s = new Student();
console.log(s);
console.log(t);
var inherit = (function() {
var Buffer = function() {}
return function(Target, Origin) {
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
// 还原构造器
Target.prototype.constructor = Target;
// 设置继承源
Target.prototype.super_class = Origin;
}
})();
function Teacher() {}
Teacher.prototype.name = "Zhang";
function Student() {}
inherit(Student, Teacher);
var t = new Teacher();
var s = new Student();
console.log(s);
console.log(t);
var inherit = (function() {
var Buffer = function() {}
return function(Target, Origin) {
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
// 还原构造器
Target.prototype.constructor = Target;
// 设置继承源
Target.prototype.super_class = Origin;
}
})();
var initPrammer = (function(){
var Programmer = function(){}
Programmer.prototype = {
name: '程序员',
tool: '计算机',
work: '编写应用程序',
say: function(){
console.log(this.myName + this.name + ',' + this.tool + this.work + ',' + this.lang.toString());
}
}
function FrontEnd(){}
function BackEnd(){}
inherit(FrontEnd, Programmer);
inherit(BackEnd, Programmer);
FrontEnd.prototype.lang = ['HTML', 'CSS'];
FrontEnd.prototype.myName = '前端';
BackEnd.prototype.lang = ['JAVA', 'PHP'];
BackEnd.prototype.myName = '后端';
return {
FrontEnd: FrontEnd,
BackEnd: BackEnd
}
})();
var frontEnd = new initPrammer.FrontEnd();
frontEnd.say();
var backEnd = new initPrammer.BackEnd();
backEnd.say();
// 判断一个变量是否为数组
var a = [];
console.log(a.constructor); // ƒ Array() { [native code] }
console.log(a instanceof Array); // true
var str = Object.prototype.toString.call(a);
console.log(str); // [object Array]
console.log(str === '[object Array]'); // true - 常用
// 缓存处理
var str = Object.prototype.toString,
trueTip = '[object Array]';
console.log(str.call(a) === trueTip); // true - 常用
// Object.prototype.toString.call 的原理
Object.prototype = {
toString: function() {
this.toString(); // call 将 this 替换为 a
}
}
// 深度封装typeof
// 原始值:number string boolean object function undefined -> string
// 引用值:object
// null: object
function myTypeof(val) {
var type = typeof(val);
var toStr = Object.prototype.toString;
var res = {
'[object Array]': 'array',
'[object Object]': 'object',
'[object Number]': 'object number',
'[object String]': 'object string',
'[object Boolean]': 'object boolean'
}
if (val === null) {
// null
return 'null';
} else if (type === 'object') {
// 引用值
var ret = toStr.call(val);
return res[ret];
} else {
// 原始值
return type;
}
}
console.log(myTypeof(new Number(1))); // 'object number'
// this 总结
// 1、全局 this -> window
// 2、预编译函数 this -> window
// 3、apply/call 改变 this 指向
// 4、构造函数的 this 指向实例化对象
// 构造函数的AO
function Test() {
// var = this {
// __proto__: Test.prototype
// }
this.name = '123';
}
var test = new Test();
// AO = {
// this: window -> {
// name: '123',
// __proto__: Test.prototype
// }
// }
// GO = {
// Test: function test(){...},
// test: {}
// }
function foo() {
bar.apply(null, arguments); // 传 null 就相当于没有this指向改变
// bar.call(); -> bar() -> bar(arguments);
// 函数执行: bar() -> bar.call() -> bar.call(arguments) -> bar(arguments);
}
function bar() {
console.log(arguments); // 最开始为 [] -> 执行变为传入的参数
}
foo(1, 2, 3, 4, 5); // Arguments(5) [1, 2, 3, 4, 5]
// JS 的 typeof 可能返回的值有哪些?
// object(null)/boolean/number/string/undefined/function
// isNaN 函数过程
function isNaN1(num) {
// 因为 NAN 不等于任何数, 所以需要转化为字符串再进行比较
var res = Number(num) + '';
if (res == 'NaN') {
return true;
} else {
return false;
}
}
console.log(isNaN1('123')); // false
console.log(isNaN1('abc')); // true
var a = '1';
function test() {
var a = '2';
this.a = '3';
console.log(a);
}
test(); // '2'
new test(); // '2'
console.log(a); // '3'
var a = 5;
function test() {
a = 0;
console.log(a);
console.log(this.a);
var a;
console.log(a);
}
test(); // 0 5 0
new test(); // 0 undefined 0
// this 指向 -很难
var name = '222';
var a = {
name: '111',
say: function() {
console.log(this.name);
}
}
var fun = a.say;
// var fun = function() {
// console.log(this.name); // this -> window
// }
fun(); // '222' this -> window
a.say(); // '111' this -> a
var b = {
name: '333',
say: function(fun) {
// fun() 函数在外面,指向 window
fun();
// 函数执行了
// +function() {
// console.log(this.name); // this -> window
// }();
}
}
b.say(a.say); // '222' // this -> window
b.say = a.say;
// function(fun) {
// fun();
// }
// function() {
// console.log(this.name);
// }
b.say(); // '333'this -> b
// 一道综合面试题
function Foo() {
getName = function() {
console.log(1);
}
return this;
}
// 借用对象自定义属性:Foo -> function -> .getName();
Foo.getName = function() {
console.log(2);
}
Foo.prototype.getName = function() {
console.log(3);
}
var getName = function() {
console.log(4);
}
function getName() {
console.log(5);
}
// Foo没执行,只是调用自定义的属性
Foo.getName(); // 2
// 预编译
// GO = {
// getName: undefined // 变量声明
// : getName() {console.log(5);} // 函数声明
// : getName() {console.log(4);} // 运行赋值
// }
getName(); // 4
// Foo 中的 getName 没有var,变为全局声明
// 执行GO就变为getName() {console.log(1);}
Foo().getName(); // 1
getName(); // 1
// 没执行:点号的优先级高于 new,所以Foo.getName() -> 2 -> new 2 无意义 =》 2
new Foo.getName(); // 2
// 执行了:括号优先级高于点号,Foo中没有this.getName()
// 最终在原型中找到了 Foo.prototype.getName => 3
new Foo().getName(); // 3
// new Foo().getName() -> 3 -> new 3 无意义 => 3
new new Foo().getName(); // 3