《你不知道的JavaScript-上卷》第二部分-this和对象原型-笔记-6-行为委托

Prototype的机制到底是什么

  • Prototype 机制就是指对象中的一个内部链接引用另一个对象
  • 如果在第一个对象上没有找到需要的属性或者方法引用,引擎就会继续在 Prototype关联的对象上进行查找。

JavaScript 中这个机制的本质就是对象之间的关联关系

6.1 面向委托的设计

把思路从类和继承的设计模式转换到委托行为的设计模式

对象关联 OLOO,objects linked to other objects

  • XYZ 对象(和 ABC 对象)委托了Task 对象
js 复制代码
        var Task = {
            setID: function (ID) { this.id = ID; },
            outputID: function () { console.log(this.id); }
        };
        // 让 XYZ 委托 Task
        XYZ = Object.create(Task);
        XYZ.prepareTask = function (ID, Label) {
            this.setID(ID);
            this.label = Label;
        };
        XYZ.outputTaskDetails = function () {
            this.outputID();
            console.log(this.label);
        };
        // ABC = Object.create( Task );
        // ABC ... = ...

6.1.3 比较思维模型

面向对象

js 复制代码
function Foo(who) {
    this.me = who;
}

Foo.prototype.identify = function() {
    return "I am " + this.me;
};

function Bar(who) {
    Foo.call( this, who );
}

Bar.prototype = Object.create( Foo.prototype );

Bar.prototype.speak = function() {
    alert( "Hello, " + this.identify() + "." );
};

var b1 = new Bar( "b1" );

var b2 = new Bar( "b2" );

b1.speak();

b2.speak();

简化版本


对象关联

js 复制代码
Foo = {
    init: function(who) {
        this.me = who;
    },

    identify: function() {
        return "I am " + this.me;
    }
};

Bar = Object.create( Foo );

Bar.speak = function() {
    alert( "Hello, " + this.identify() + "." );
};

var b1 = Object.create( Bar );

b1.init( "b1" );

var b2 = Object.create( Bar );
b2.init( "b2" );

b1.speak();
b2.speak();

6.2 类与对象

包含所有通用控件行为的父类(可能叫作 Widget)和继承父类的特殊控件子类的项目设计

在不使用任何"类"辅助库或者语法的情况下,使用纯JavaScript 实现类风格的代码

js 复制代码
// 父类

        function Widget(width, height) {
            this.width = width || 50;
            this.height = height || 50;
            this.$elem = null;
        }

        Widget.prototype.render = function ($where) {
            if (this.$elem) {
                this.$elem.css({
                    width: this.width + "px",
                    height: this.height + "px"
                }).appendTo($where);
            }
        };

        // 子类

        function Button(width, height, label) {
            // 调用"super"构造函数
            Widget.call(this, width, height);
            this.label = label || "Default";
            this.$elem = $("<button>").text(this.label);
        }

        // 让 Button"继承"Widget
        Button.prototype = Object.create(Widget.prototype);

        // 重写 render(..)
        Button.prototype.render = function ($where) {
            //"super"调用
            Widget.prototype.render.call(this, $where);
            this.$elem.click(this.onClick.bind(this));
        };

        Button.prototype.onClick = function (evt) {
            console.log("Button '" + this.label + "' clicked!");
        };

        $(document).ready(function () {
            var $body = $(document.body);
            var btn1 = new Button(125, 30, "Hello");
            var btn2 = new Button(150, 40, "World");
            btn1.render($body);
            btn2.render($body);
        });

ES6的class语法糖 写法

js 复制代码
class Widget {
    constructor(width, height) {
        this.width = width || 50;
        this.height = height || 50;
        this.$elem = null;
    }
    render($where) {
        if (this.$elem) {
            this.$elem.css({
                width: this.width + "px",
                height: this.height + "px"
            }).appendTo($where);
        }
    }
}
class Button extends Widget {
    constructor(width, height, label) {
        super(width, height);
        this.label = label || "Default";
        this.$elem = $("<button>").text(this.label);
    }
    render($where) {
        super($where);
        this.$elem.click(this.onClick.bind(this));
    }
    onClick(evt) {
        console.log("Button '" + this.label + "' clicked!");
    }
}
$(document).ready(function () {
    var $body = $(document.body);
    var btn1 = new Button(125, 30, "Hello");
    var btn2 = new Button(150, 40, "World");
    btn1.render($body);
    btn2.render($body);
});

使用对象关联风格委托来更简单地实现 Widget/Button

js 复制代码
var Widget = {
    init: function (width, height) {
        this.width = width || 50;
        this.height = height || 50;
        this.$elem = null;
    },
    insert: function ($where) {
        if (this.$elem) {
            this.$elem.css({
                width: this.width + "px",
                height: this.height + "px"
            }).appendTo($where);
        }
    }
};
var Button = Object.create(Widget);
Button.setup = function (width, height, label) {
    // 委托调用
    this.init(width, height);
    this.label = label || "Default";
    this.$elem = $("<button>").text(this.label);
};
Button.build = function ($where) {// 委托调用
    this.insert($where);
    this.$elem.click(this.onClick.bind(this));
};
Button.onClick = function (evt) {
    console.log("Button '" + this.label + "' clicked!");
};
$(document).ready(function () {
    var $body = $(document.body);
    var btn1 = Object.create(Button);
    btn1.setup(125, 30, "Hello");
    var btn2 = Object.create(Button);
    btn2.setup(150, 40, "World");
    btn1.build($body);
    btn2.build($body);
});
相关推荐
小磊哥er1 小时前
深入解构Claude Code - 第 8 篇 · 数据放哪、钱怎么算
javascript·ai编程
kyriewen2 小时前
我装了30多个Skill,给AI安排了8个岗位
前端·javascript·ai编程
风骏时光牛马3 小时前
大模型落地实践中的技术选型思路与方案对比
前端
IT_陈寒3 小时前
Vite打包时的静态资源坑,我帮你踩过了
前端·人工智能·后端
默_笙4 小时前
🔥 让 AI 帮我写完整个 Next.js 博客:框架就是 AI 的"上下文 buff"
前端·javascript
牧艺5 小时前
登录页还在用渐变?我一口气做了 5 个能摸的背景动效:吹蒲公英、滴墨染水、点熔岩闷裂
前端·canvas·交互设计
陆枫Larry5 小时前
状态机简介
前端
陆枫Larry5 小时前
一次登录问题排查:接口没错,错的是旧业务逻辑
前端
小小小小宇5 小时前
大模型打分与采样原理,以及 Pi Agent 核心原理
前端
一位正在转型AI全栈的前端工程师6 小时前
AI 全栈学习之旅 -Week 5:RAG 知识库问答系统:从零到生产级部署的全栈实践总结
前端·python