JavaScript基础 —— 原型&&原型链
构造函数
function Foo(name, age) { this.name = name; this.age = age; this.class = 'class-1'; //return this ; //默认有这一行 } var f = new Foo('张三', 22); var f1 = new Foo('李四', 29);
构造函数 - 扩展
var a={} 其实是 var a=new Object() 的语法糖 var a=[] 其实是 var a=new Array() 的语法糖 function Foo() {....} 其实是 var Foo=new Function(...) 使用 instanceof 判断一个函数是否是一个变量的构造函数
原型规则和示例
- 所有的引用类型(数组、对象、函数),都具有对象属性(即可自有扩展的属性),
null
除外 - 所有的引用类型(数组、对象、函数),都有一个
__proto__
属性(隐式原型),属性值是一个普通的对象
var obj = { }; obj.x=100; console.log(obj.__proto__); // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} var arr = []; arr.x = 200; console.log(arr.__proto__); // [constructor: ƒ, concat: ƒ, find: ƒ, findIndex: ƒ, pop: ƒ, …] function fn() {}; fn.x = 300; console.log(fn.__proto__); // ƒ () { [native code] } var d = null; console.log(d.__proto__); // Uncaught TypeError: Cannot read property '__proto__' of null
- 所有的
函数
,都有一个prototype
属性(显式原型),属性值也是一个普通对象
console.log(fn.prototype); // {constructor: ƒ}
- 所有的引用类型(数组、对象、函数),
__proto__
属性值指向它的构造函数的prototype
属性值
console.log(obj.__proto__ === Object.prototype); // true
- 当视图得到一个对象(所有的引用类型)的某个属性时,如果这个对象本身没有这个属性,那么会去它的
__proto__
(即它的构造函数的prototype
)中寻找。
// 构造函数 function Foo(name, age) { this.name = name; } Foo.prototype.alertName = function() { console.log('alertName' + this.name); } // 创建示例 var f = new Foo('张三'); f.prientname = function() { console.log('prientname' + this.name); } // 测试 f.prientname(); // prientname张三 f.alertName(); // alertName张三
原型链
// 构造函数 function Foo(name, age) { this.name = name; } Foo.prototype.alertName = function() { console.log('alertName' + this.name); } // 创建示例 var f = new Foo('张三'); f.prientname = function() { console.log('prientname' + this.name); } // 测试 f.prientname(); // prientname张三 f.alertName(); // alertName张三 f.toString(); // "[object Object]" 在f.__proto__.__proto__中查找,即Object的显式原型中寻找
instanceof
-
instanceof
用于判断引用类型
属于哪个构造函数
的方法
// f的 __proto__ 一层一层网上找,找到对应的 Foo.prototype f instanceof Foo //true f instanceof Object //true
q:如何准确判断一个变量是数组类型
var arr=[] // 可以正确判断的情况 arr instanceof Array //true Object.prototype.toString.call(arr) // "[object Array]" Object.prototype.toString.apply(arr) // "[object Array]" Array.isArray(arr) // true // 不能判断的情况 typeof arr // object 是无法判断是否是数组的 // 不准确 arr.constructor === Array //true 但是原型链可以被改写,这样判断不安全
// 扩展 兼容老版本浏览器,isArray的写法 if(!Array.isArray){ Array.isArray = function(arg){ return Object.property.toString.call(arg) === '[object Array]' } }
q:写一个原型链继承的例子
function Elem(id) { this.elem = document.getElementById(id); } Elem.prototype.html = function(val) { var elem = this.elem; if (val) { elem.innerHTML = val; return this; // 后续的链式操作 } else { return elem.innerHTML; } } Elem.prototype.on = function(type, fn) { var elem = this.elem; elem.addEventListener(type, fn); return this; } var main = new Elem('main') main.html('Hello World
').on('click', function() { alert('Hello javascript') })
q:描述 new
一个对象的过程
- 创建一个对象
-
this
指向这个新对象 - 执行代码,即对
this
赋值 - 返回
this
function Foo(name, age) { this.name = name; this.age = age; this.class = 'class-1'; //return this ; //默认有这一行 } var f = new Foo('张三', 22); var f1 = new Foo('李四', 29);